Modified the way icons merge into the shelf

The icon can now also move into the shelf in an animated
way instead of just moving out of it.

Change-Id: Iba4ebd3cd48b5299b89bd0cb2b05bd318e352173
Fixes: 33463805
Test: add notification observe behavior when scrolling
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index d1c0073..8ae84cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -929,6 +929,10 @@
         return topPadding;
     }
 
+    public float getContentTranslation() {
+        return mPrivateLayout.getTranslationY();
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0a138b8..296c788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -45,6 +45,8 @@
     public static final boolean SHOW_AMBIENT_ICONS = true;
     private static final boolean USE_ANIMATIONS_WHEN_OPENING =
             SystemProperties.getBoolean("debug.icon_opening_animations", true);
+    private static final boolean ICON_ANMATIONS_WHILE_SCROLLING
+            = SystemProperties.getBoolean("debug.icon_scroll_animations", true);
     private ViewInvertHelper mViewInvertHelper;
     private boolean mDark;
     private NotificationIconContainer mShelfIcons;
@@ -63,6 +65,7 @@
     private NotificationIconContainer mCollapsedIcons;
     private int mScrollFastThreshold;
     private int mStatusBarState;
+    private float mMaxShelfEnd;
 
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -168,6 +171,7 @@
             }
             mShelfState.hasItemsInStableShelf = lastViewState.inShelf;
             mShelfState.hidden = !mAmbientState.isShadeExpanded();
+            mShelfState.maxShelfEnd = maxShelfEnd;
         } else {
             mShelfState.hidden = true;
             mShelfState.location = ExpandableViewState.LOCATION_GONE;
@@ -202,9 +206,11 @@
         int colorTwoBefore = NO_COLOR;
         int previousColor = NO_COLOR;
         float transitionAmount = 0.0f;
-        boolean scrollingFast = mAmbientState.getCurrentScrollVelocity() > mScrollFastThreshold
+        float currentScrollVelocity = mAmbientState.getCurrentScrollVelocity();
+        boolean scrollingFast = currentScrollVelocity > mScrollFastThreshold
                 || (mAmbientState.isExpansionChanging()
                         && Math.abs(mAmbientState.getExpandingVelocity()) > mScrollFastThreshold);
+        boolean scrolling = currentScrollVelocity > 0;
         boolean expandingAnimated = mAmbientState.isExpansionChanging()
                 && !mAmbientState.isPanelTracking();
         int baseZHeight = mAmbientState.getBaseZHeight();
@@ -233,7 +239,7 @@
                 }
             }
             updateNotificationClipHeight(row, notificationClipEnd);
-            float inShelfAmount = updateIconAppearance(row, expandAmount, scrollingFast,
+            float inShelfAmount = updateIconAppearance(row, expandAmount, scrolling, scrollingFast,
                     expandingAnimated, isLastChild);
             numViewsInShelf += inShelfAmount;
             int ownColorUntinted = row.getBackgroundColorWithoutTint();
@@ -284,11 +290,13 @@
      * @return the icon amount how much this notification is in the shelf;
      */
     private float updateIconAppearance(ExpandableNotificationRow row, float expandAmount,
-            boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
+            boolean scrolling, boolean scrollingFast, boolean expandingAnimated,
+            boolean isLastChild) {
         // Let calculate how much the view is in the shelf
         float viewStart = row.getTranslationY();
         int fullHeight = row.getActualHeight() + mPaddingBetweenElements;
         float iconTransformDistance = getIntrinsicHeight() * 1.5f;
+        iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount);
         if (isLastChild) {
             fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight());
             iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight()
@@ -321,26 +329,25 @@
             fullTransitionAmount = 0.0f;
             iconTransitionAmount = 0.0f;
         }
-        updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount, scrollingFast,
-                expandingAnimated, isLastChild);
+        updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount,
+                iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
         return fullTransitionAmount;
     }
 
     private void updateIconPositioning(ExpandableNotificationRow row, float iconTransitionAmount,
-            float fullTransitionAmount, boolean scrollingFast, boolean expandingAnimated,
-            boolean isLastChild) {
+            float fullTransitionAmount, float iconTransformDistance, boolean scrolling,
+            boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
         StatusBarIconView icon = row.getEntry().expandedIcon;
         NotificationIconContainer.IconState iconState = getIconState(icon);
         if (iconState == null) {
             return;
         }
         float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f;
-        if (clampedAmount == iconTransitionAmount) {
-            iconState.keepClampedPosition = false;
-        }
         if (clampedAmount == fullTransitionAmount) {
-            iconState.useFullTransitionAmount = fullTransitionAmount == 0.0f || scrollingFast
-                    || expandingAnimated;
+            iconState.useFullTransitionAmount = scrollingFast || expandingAnimated
+                || (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f && scrolling);
+            iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
+                    && fullTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging();
             iconState.translateContent = mMaxLayoutHeight - getTranslationY()
                     - getIntrinsicHeight() > 0;
         }
@@ -350,49 +357,41 @@
             iconState.useFullTransitionAmount = true;
         }
         float transitionAmount;
-        boolean needCannedAnimation = iconState.clampedAppearAmount == 1.0f
-                && clampedAmount == 0.0f;
-        if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount) {
+        if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
+                || iconState.useLinearTransitionAmount) {
             transitionAmount = iconTransitionAmount;
-        } else if (iconState.keepClampedPosition
-                && iconState.clampedAppearAmount != clampedAmount) {
-            // We animated to the clamped amount but then decided to go the other way. Let's
-            // animate it to the new position
-            transitionAmount = iconTransitionAmount;
-            iconState.needsCannedAnimation = true;
-            iconState.keepClampedPosition = false;
-        } else if (needCannedAnimation || iconState.keepClampedPosition
-                || iconState.iconAppearAmount == 1.0f) {
-            // We need to perform a canned animation since we crossed the treshhold
-            transitionAmount = clampedAmount;
-            iconState.keepClampedPosition = iconState.keepClampedPosition || needCannedAnimation;
-            iconState.needsCannedAnimation = needCannedAnimation;
         } else {
-            transitionAmount = iconTransitionAmount;
+            // We take the clamped position instead
+            transitionAmount = clampedAmount;
+            iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount;
         }
         iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING
                     || iconState.useFullTransitionAmount
                 ? fullTransitionAmount
                 : transitionAmount;
         iconState.clampedAppearAmount = clampedAmount;
-        setIconTransformationAmount(row, transitionAmount);
         float contentTransformationAmount = isLastChild || iconState.translateContent
                 ? iconTransitionAmount
                 : 0.0f;
         row.setContentTransformationAmount(contentTransformationAmount, isLastChild);
-    }
-
-    private boolean isLastChild(ExpandableNotificationRow row) {
-        return row == mAmbientState.getLastVisibleBackgroundChild();
+        setIconTransformationAmount(row, transitionAmount, iconTransformDistance,
+                clampedAmount != transitionAmount);
     }
 
     private void setIconTransformationAmount(ExpandableNotificationRow row,
-            float transitionAmount) {
+            float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation) {
         StatusBarIconView icon = row.getEntry().expandedIcon;
         NotificationIconContainer.IconState iconState = getIconState(icon);
 
         View rowIcon = row.getNotificationIcon();
-        float notificationIconPosition = row.getTranslationY();
+        float notificationIconPosition = row.getTranslationY() + row.getContentTranslation();
+        if (usingLinearInterpolation) {
+            // If we interpolate from the notification position, this might lead to a slightly
+            // odd interpolation, since the notification position changes as well. Let's interpolate
+            // from a fixed distance. We can only do this if we don't animate and the icon is
+            // always in the interpolated positon.
+            notificationIconPosition = mMaxShelfEnd - getIntrinsicHeight() - iconTransformDistance;
+        }
         float notificationIconSize = 0.0f;
         int iconTopPadding;
         if (rowIcon != null) {
@@ -404,15 +403,8 @@
         notificationIconPosition += iconTopPadding;
         float shelfIconPosition = getTranslationY() + icon.getTop();
         shelfIconPosition += ((1.0f - icon.getIconScale()) * icon.getHeight()) / 2.0f;
-        float transitionDistance = getIntrinsicHeight() * 1.5f;
-        if (row == mAmbientState.getLastVisibleBackgroundChild()) {
-            transitionDistance = Math.min(transitionDistance, row.getMinHeight()
-                    - getIntrinsicHeight());
-        }
-        float transformationStartPosition = getTranslationY() - transitionDistance;
         float iconYTranslation = NotificationUtils.interpolate(
-                Math.min(notificationIconPosition, transformationStartPosition + iconTopPadding)
-                        - shelfIconPosition,
+                notificationIconPosition - shelfIconPosition,
                 0,
                 transitionAmount);
         float shelfIconSize = icon.getHeight() * icon.getIconScale();
@@ -557,21 +549,28 @@
                 : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
+    public void setMaxShelfEnd(float maxShelfEnd) {
+        mMaxShelfEnd = maxShelfEnd;
+    }
+
     private class ShelfState extends ExpandableViewState {
         private float openedAmount;
         private boolean hasItemsInStableShelf;
+        private float maxShelfEnd;
 
         @Override
         public void applyToView(View view) {
             super.applyToView(view);
-            updateAppearance();
+            setMaxShelfEnd(maxShelfEnd);
             setOpenedAmount(openedAmount);
+            updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
         }
 
         @Override
         public void animateTo(View child, AnimationProperties properties) {
             super.animateTo(child, properties);
+            setMaxShelfEnd(maxShelfEnd);
             setOpenedAmount(openedAmount);
             updateAppearance();
             setHasItemsInStableShelf(hasItemsInStableShelf);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index d323e4f..e99c641 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -409,8 +409,8 @@
         public int visibleState;
         public boolean justAdded = true;
         public boolean needsCannedAnimation;
-        public boolean keepClampedPosition;
         public boolean useFullTransitionAmount;
+        public boolean useLinearTransitionAmount;
         public boolean translateContent;
 
         @Override