Improve unlock motion further.

Bug: 15244051
Change-Id: I6f567ff327695ec6ece56748cd300b8103715811
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index 7918755..38316ff 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -166,6 +166,11 @@
         return info;
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
     // This is an optimization to ensure we only recompute the patterns when the inputs change.
     private static final class Patterns {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 97aa993..63698e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -58,6 +58,7 @@
     private ImageView mCameraImageView;
     private ImageView mPhoneImageView;
     private ImageView mLockIcon;
+    private View mIndicationText;
 
     private ActivityStarter mActivityStarter;
     private UnlockMethodCache mUnlockMethodCache;
@@ -87,6 +88,7 @@
         mCameraImageView = (ImageView) findViewById(R.id.camera_button);
         mPhoneImageView = (ImageView) findViewById(R.id.phone_button);
         mLockIcon = (ImageView) findViewById(R.id.lock_icon);
+        mIndicationText = findViewById(R.id.keyguard_indication_text);
         watchForCameraPolicyChanges();
         watchForAccessibilityChanges();
         updateCameraVisibility();
@@ -231,6 +233,10 @@
         return mLockIcon;
     }
 
+    public View getIndicationView() {
+        return mIndicationText;
+    }
+
     @Override
     public void onMethodSecureChanged(boolean methodSecure) {
         updateTrust();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 6a83a5e..319096d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -18,6 +18,7 @@
 
 import android.content.res.Resources;
 import android.graphics.Path;
+import android.view.animation.AccelerateInterpolator;
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
@@ -31,6 +32,10 @@
 
     private static final float CLOCK_RUBBERBAND_FACTOR_MIN = 0.08f;
     private static final float CLOCK_RUBBERBAND_FACTOR_MAX = 0.8f;
+    private static final float CLOCK_SCALE_FADE_START = 0.95f;
+    private static final float CLOCK_SCALE_FADE_END = 0.75f;
+    private static final float CLOCK_SCALE_FADE_END_NO_NOTIFS = 0.5f;
+
 
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MIN = 1.4f;
     private static final float CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX = 3.2f;
@@ -61,6 +66,8 @@
         sSlowDownInterpolator = new PathInterpolator(path);
     }
 
+    private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
+
     /**
      * Refreshes the dimension values.
      */
@@ -87,18 +94,29 @@
     }
 
     public void run(Result result) {
-        int y = getClockY() - mKeyguardStatusHeight/2;
+        int y = getClockY() - mKeyguardStatusHeight / 2;
         float clockAdjustment = getClockYExpansionAdjustment();
         float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier();
         result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier);
         int clockNotificationsPadding = getClockNotificationsPadding()
                 + result.stackScrollerPaddingAdjustment;
         int padding = y + clockNotificationsPadding;
-        y += clockAdjustment;
         result.clockY = y;
         result.stackScrollerPadding = mKeyguardStatusHeight + padding;
-        result.clockAlpha = getClockAlpha(result.stackScrollerPadding
-                - (y + mKeyguardStatusHeight));
+        result.clockScale = getClockScale(result.stackScrollerPadding,
+                result.clockY,
+                y + getClockNotificationsPadding() + mKeyguardStatusHeight);
+        result.clockAlpha = getClockAlpha(result.clockScale);
+    }
+
+    private float getClockScale(int notificationPadding, int clockY, int startPadding) {
+        float scaleMultiplier = getNotificationAmountT() == 0 ? 6.0f : 5.0f;
+        float scaleEnd = clockY - mKeyguardStatusHeight * scaleMultiplier;
+        float distanceToScaleEnd = notificationPadding - scaleEnd;
+        float progress = distanceToScaleEnd / (startPadding - scaleEnd);
+        progress = Math.max(0.0f, Math.min(progress, 1.0f));
+        progress = mAccelerateInterpolator.getInterpolation(progress);
+        return progress;
     }
 
     private int getClockNotificationsPadding() {
@@ -144,11 +162,12 @@
                 + t * CLOCK_ADJ_TOP_PADDING_MULTIPLIER_MAX;
     }
 
-    private float getClockAlpha(int clockNotificationPadding) {
-        float t = getNotificationAmountT();
-        t = (float) Math.pow(t, 0.3f);
-        float multiplier = 1 + 2 * (1 - t);
-        float alpha = 1 + (float) clockNotificationPadding * multiplier / mKeyguardStatusHeight * 3;
+    private float getClockAlpha(float scale) {
+        float fadeEnd = getNotificationAmountT() == 0.0f
+                ? CLOCK_SCALE_FADE_END_NO_NOTIFS
+                : CLOCK_SCALE_FADE_END;
+        float alpha = (scale - fadeEnd)
+                / (CLOCK_SCALE_FADE_START - fadeEnd);
         return Math.max(0, Math.min(1, alpha));
     }
 
@@ -168,6 +187,11 @@
         public int clockY;
 
         /**
+         * The scale of the Clock
+         */
+        public float clockScale;
+
+        /**
          * The alpha value of the clock.
          */
         public float clockAlpha;
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 a090217..a6ce5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -32,6 +32,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
@@ -48,6 +49,11 @@
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
         KeyguardPageSwipeHelper.Callback {
 
+    // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
+    // changed.
+    private static final int CAP_HEIGHT = 1456;
+    private static final int FONT_HEIGHT = 2163;
+
     private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
 
     private KeyguardPageSwipeHelper mPageSwiper;
@@ -56,7 +62,7 @@
     private View mQsPanel;
     private View mKeyguardStatusView;
     private ObservableScrollView mScrollView;
-    private View mStackScrollerContainer;
+    private TextView mClockView;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
     private int mNotificationTopPadding;
@@ -105,7 +111,7 @@
             new KeyguardClockPositionAlgorithm.Result();
     private boolean mIsSwipedHorizontally;
     private boolean mIsExpanding;
-    private KeyguardBottomAreaView mKeyguardBottomArea;
+
     private boolean mBlockTouches;
     private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
     private int mNotificationScrimWaitDistance;
@@ -137,9 +143,9 @@
         mHeader.getBackgroundView().setOnClickListener(this);
         mHeader.setOverlayParent(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
-        mStackScrollerContainer = findViewById(R.id.notification_container_parent);
         mQsContainer = findViewById(R.id.quick_settings_container);
         mQsPanel = findViewById(R.id.quick_settings_panel);
+        mClockView = (TextView) findViewById(R.id.clock_view);
         mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
         mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
@@ -179,6 +185,11 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
+        // Update Clock Pivot
+        mKeyguardStatusView.setPivotX(getWidth() / 2);
+        mKeyguardStatusView.setPivotY(
+                (FONT_HEIGHT - CAP_HEIGHT) / 2048f * mClockView.getTextSize());
+
         // Calculate quick setting heights.
         mQsMinExpansionHeight = mHeader.getCollapsedHeight() + mQsPeekHeight;
         mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
@@ -201,7 +212,7 @@
      * showing.
      */
     private void positionClockAndNotifications() {
-        boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
+        boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
         int stackScrollerPadding;
         if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
             int bottom = mStackScrollerOverscrolling
@@ -219,17 +230,17 @@
                     getHeight(),
                     mKeyguardStatusView.getHeight());
             mClockPositionAlgorithm.run(mClockPositionResult);
-            if (animateClock || mClockAnimator != null) {
+            if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockY);
             } else {
                 mKeyguardStatusView.setY(mClockPositionResult.clockY);
             }
-            applyClockAlpha(mClockPositionResult.clockAlpha);
+            updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
             stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
             mTopPaddingAdjustment = mClockPositionResult.stackScrollerPaddingAdjustment;
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
-        requestScrollerTopPaddingUpdate(animateClock);
+        requestScrollerTopPaddingUpdate(animate);
     }
 
     private void startClockAnimation(int y) {
@@ -262,13 +273,10 @@
         });
     }
 
-    private void applyClockAlpha(float alpha) {
-        if (alpha != 1.0f) {
-            mKeyguardStatusView.setLayerType(LAYER_TYPE_HARDWARE, null);
-        } else {
-            mKeyguardStatusView.setLayerType(LAYER_TYPE_NONE, null);
-        }
+    private void updateClock(float alpha, float scale) {
         mKeyguardStatusView.setAlpha(alpha);
+        mKeyguardStatusView.setScaleX(scale);
+        mKeyguardStatusView.setScaleY(scale);
     }
 
     public void animateToFullShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 1f3098d..12aa004 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -62,6 +62,7 @@
     protected int mTouchSlop;
     protected boolean mHintAnimationRunning;
     private boolean mOverExpandedBeforeFling;
+    private float mOriginalIndicationY;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -82,6 +83,7 @@
 
     private Interpolator mLinearOutSlowInInterpolator;
     private Interpolator mBounceInterpolator;
+    protected KeyguardBottomAreaView mKeyguardBottomArea;
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
@@ -652,6 +654,22 @@
         });
         animator.start();
         mHeightAnimator = animator;
+        mOriginalIndicationY = mKeyguardBottomArea.getIndicationView().getY();
+        mKeyguardBottomArea.getIndicationView().animate()
+                .y(mOriginalIndicationY - mHintDistance)
+                .setDuration(250)
+                .setInterpolator(mLinearOutSlowInInterpolator)
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mKeyguardBottomArea.getIndicationView().animate()
+                                .y(mOriginalIndicationY)
+                                .setDuration(450)
+                                .setInterpolator(mBounceInterpolator)
+                                .start();
+                    }
+                })
+                .start();
     }
 
     /**