Animate clock position on Keyguard.

Also disable animations when on Keyguard and screen is turned off.

Change-Id: Iec031ab336357194b5d387bc0aad00a702a8ef54
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cd8ddc3..c15f25f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -302,6 +302,6 @@
     <!-- The margin between the clock and the notifications on Keyguard. See
          keyguard_clock_height_fraction_* for the difference between min and max.-->
     <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
-    <dimen name="keyguard_clock_notifications_margin_max">28dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
 
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 047983b..19252c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,6 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
@@ -25,7 +27,10 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
@@ -34,6 +39,7 @@
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
@@ -80,6 +86,9 @@
     private int mClockNotificationsMarginMax;
     private float mClockYFractionMin;
     private float mClockYFractionMax;
+    private Interpolator mFastOutSlowInInterpolator;
+    private ObjectAnimator mClockAnimator;
+    private int mClockAnimationTarget = -1;
 
     /**
      * The number (fractional) of notifications the "more" card counts when calculating how many
@@ -120,6 +129,8 @@
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
@@ -164,21 +175,55 @@
      * showing.
      */
     private void positionClockAndNotifications() {
+        boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
             mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding;
         } else {
             int notificationCount = mNotificationStackScroller.getNotGoneChildCount();
-            int y = getClockY(notificationCount);
+            int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2;
             int padding = getClockNotificationsPadding(notificationCount);
-            mKeyguardStatusView.setY(y - mKeyguardStatusView.getHeight()/2);
-            mStackScrollerIntrinsicPadding =
-                    (int) (mKeyguardStatusView.getY() + mKeyguardStatusView.getHeight() + padding);
+            if (animateClock || mClockAnimator != null) {
+                startClockAnimation(y);
+            } else {
+                mKeyguardStatusView.setY(y);
+            }
+            mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding;
         }
         mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
-                mAnimateNextTopPaddingChange);
+                mAnimateNextTopPaddingChange || animateClock);
         mAnimateNextTopPaddingChange = false;
     }
 
+    private void startClockAnimation(int y) {
+        if (mClockAnimationTarget == y) {
+            return;
+        }
+        mClockAnimationTarget = y;
+        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                getViewTreeObserver().removeOnPreDrawListener(this);
+                if (mClockAnimator != null) {
+                    mClockAnimator.removeAllListeners();
+                    mClockAnimator.cancel();
+                }
+                mClockAnimator =
+                        ObjectAnimator.ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
+                mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
+                mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+                mClockAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mClockAnimator = null;
+                        mClockAnimationTarget = -1;
+                    }
+                });
+                StackStateAnimator.startInstantly(mClockAnimator);
+                return true;
+            }
+        });
+    }
+
     private int getClockNotificationsPadding(int notificationCount) {
         float t = notificationCount
                 / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 4e1ffa5..a92061f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2922,4 +2922,12 @@
     public void reattachSystemIcons() {
         mSystemIconArea.addView(mSystemIcons, 0);
     }
+
+    public void onScreenTurnedOff() {
+        mStackScroller.setAnimationsEnabled(false);
+    }
+
+    public void onScreenTurnedOn() {
+        mStackScroller.setAnimationsEnabled(true);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 77b760e..1040c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -125,11 +125,13 @@
 
     public void onScreenTurnedOff() {
         mScreenOn = false;
+        mPhoneStatusBar.onScreenTurnedOff();
         mBouncer.onScreenTurnedOff();
     }
 
     public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
         mScreenOn = true;
+        mPhoneStatusBar.onScreenTurnedOn();
         if (callback != null) {
             callbackAfterDraw(callback);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index cb0a696..58ada75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -108,6 +108,7 @@
             = new ArrayList<AnimationEvent>();
     private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
+    private boolean mAnimationsEnabled;
 
     /**
      * The raw amount of the overScroll on the top, which is not rubber-banded.
@@ -352,7 +353,7 @@
             mTopPadding = topPadding;
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
-            if (animate) {
+            if (animate && mAnimationsEnabled && mIsExpanded) {
                 mTopPaddingNeedsAnimation = true;
                 mNeedsAnimation =  true;
             }
@@ -440,9 +441,11 @@
     public void onChildSnappedBack(View animView) {
         mAmbientState.onDragFinished(animView);
         if (!mDragAnimPendingChildren.contains(animView)) {
-            mSnappedBackChildren.add(animView);
+            if (mAnimationsEnabled) {
+                mSnappedBackChildren.add(animView);
+                mNeedsAnimation = true;
+            }
             requestChildrenUpdate();
-            mNeedsAnimation = true;
         } else {
             // We start the swipe and snap back in the same frame, we don't want any animation
             mDragAnimPendingChildren.remove(animView);
@@ -451,10 +454,12 @@
 
     public void onBeginDrag(View v) {
         setSwipingInProgress(true);
-        mDragAnimPendingChildren.add(v);
         mAmbientState.onBeginDrag(v);
+        if (mAnimationsEnabled) {
+            mDragAnimPendingChildren.add(v);
+            mNeedsAnimation = true;
+        }
         requestChildrenUpdate();
-        mNeedsAnimation = true;
     }
 
     public void onDragCancelled(View v) {
@@ -1082,8 +1087,7 @@
     }
 
     private void generateRemoveAnimation(View child) {
-        if (mIsExpanded) {
-
+        if (mIsExpanded && mAnimationsEnabled) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 // Generate Animations
                 mChildrenToRemoveAnimated.add(child);
@@ -1141,8 +1145,17 @@
         }
     }
 
+    public void setAnimationsEnabled(boolean animationsEnabled) {
+        mAnimationsEnabled = animationsEnabled;
+    }
+
+    public boolean isAddOrRemoveAnimationPending() {
+        return mNeedsAnimation
+                && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
+    }
+
     public void generateAddAnimation(View child) {
-        if (mIsExpanded) {
+        if (mIsExpanded && mAnimationsEnabled) {
 
             // Generate Animations
             mChildrenToAddAnimated.add(child);
@@ -1447,7 +1460,7 @@
         mStackScrollAlgorithm.setDimmed(dimmed);
         mAmbientState.setDimmed(dimmed);
         updatePadding(dimmed);
-        if (animate) {
+        if (animate && mAnimationsEnabled) {
             mDimmedNeedsAnimation = true;
             mNeedsAnimation =  true;
         }
@@ -1459,8 +1472,10 @@
      */
     public void setActivatedChild(View activatedChild) {
         mAmbientState.setActivatedChild(activatedChild);
-        mActivateNeedsAnimation = true;
-        mNeedsAnimation =  true;
+        if (mAnimationsEnabled) {
+            mActivateNeedsAnimation = true;
+            mNeedsAnimation =  true;
+        }
         requestChildrenUpdate();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 5ac51f8..a9dcdd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -434,7 +434,7 @@
     /**
      * Start an animator instantly instead of waiting on the next synchronization frame
      */
-    private void startInstantly(ValueAnimator animator) {
+    public static void startInstantly(ValueAnimator animator) {
         animator.start();
         animator.setCurrentPlayTime(0);
     }