Large icons now scale nicer when expanding bundles

Fixes: 	27597173
Change-Id: I5df234d58903b87cbef5df8812e48992b435fca8
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 123dc69..e8f0925 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -48,13 +48,30 @@
     }
 
     public static void fadeOut(View view, float fadeOutAmount) {
+        fadeOut(view, fadeOutAmount, true /* remap */);
+    }
+
+    /**
+     * Fade out a view by a given progress amount
+     * @param view the view to fade out
+     * @param fadeOutAmount how much the view is faded out. 0 means not at all and 1 means fully
+     *                      faded out
+     * @param remap whether the fade amount should be remapped to the shorter duration
+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
+     *
+     * @see #fadeIn(View, float, boolean)
+     */
+    public static void fadeOut(View view, float fadeOutAmount, boolean remap) {
         view.animate().cancel();
         if (fadeOutAmount == 1.0f) {
             view.setVisibility(View.INVISIBLE);
         } else if (view.getVisibility() == View.INVISIBLE) {
             view.setVisibility(View.VISIBLE);
         }
-        fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+        if (remap) {
+            fadeOutAmount = mapToFadeDuration(fadeOutAmount);
+        }
         float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount);
         view.setAlpha(alpha);
         updateLayerType(view, alpha);
@@ -92,11 +109,28 @@
     }
 
     public static void fadeIn(View view, float fadeInAmount) {
+        fadeIn(view, fadeInAmount, true /* remap */);
+    }
+
+    /**
+     * Fade in a view by a given progress amount
+     * @param view the view to fade in
+     * @param fadeInAmount how much the view is faded in. 0 means not at all and 1 means fully
+     *                     faded in.
+     * @param remap whether the fade amount should be remapped to the shorter duration
+     * {@link #ANIMATION_DURATION_LENGTH} from the normal fade duration
+     * {@link StackStateAnimator#ANIMATION_DURATION_STANDARD} in order to have a faster fading.
+     *
+     * @see #fadeOut(View, float, boolean)
+     */
+    public static void fadeIn(View view, float fadeInAmount, boolean remap) {
         view.animate().cancel();
         if (view.getVisibility() == View.INVISIBLE) {
             view.setVisibility(View.VISIBLE);
         }
-        fadeInAmount = mapToFadeDuration(fadeInAmount);
+        if (remap) {
+            fadeInAmount = mapToFadeDuration(fadeInAmount);
+        }
         float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount);
         view.setAlpha(alpha);
         updateLayerType(view, alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 1ff2b13..cd6c31f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -116,8 +116,7 @@
                     ownState.transformViewTo(otherState, transformationAmount);
                     otherState.recycle();
                 } else {
-                    // there's no other view available
-                    CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount);
+                    ownState.disappear(transformationAmount, notification);
                 }
                 ownState.recycle();
             }
@@ -174,13 +173,7 @@
                     ownState.transformViewFrom(otherState, transformationAmount);
                     otherState.recycle();
                 } else {
-                    // There's no other view, lets fade us in
-                    // Certain views need to prepare the fade in and make sure its children are
-                    // completely visible. An example is the notification header.
-                    if (transformationAmount == 0.0f) {
-                        ownState.prepareFadeIn();
-                    }
-                    CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount);
+                    ownState.appear(transformationAmount, notification);
                 }
                 ownState.recycle();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 45027c0..e6b3fb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,12 +21,17 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * A transform state of a image view.
 */
 public class ImageTransformState extends TransformState {
+    public static final long ANIMATION_DURATION_LENGTH = 210;
 
     public static final int ICON_TAG = R.id.image_icon_tag;
     private static Pools.SimplePool<ImageTransformState> sInstancePool
@@ -49,6 +54,52 @@
         return super.sameAs(otherState);
     }
 
+    @Override
+    public void appear(float transformationAmount, TransformableView otherView) {
+        if (otherView instanceof HybridNotificationView) {
+            if (transformationAmount == 0.0f) {
+                mTransformedView.setPivotY(0);
+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
+                prepareFadeIn();
+            }
+            transformationAmount = mapToDuration(transformationAmount);
+            CrossFadeHelper.fadeIn(mTransformedView, transformationAmount, false /* remap */);
+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
+                    transformationAmount);
+            mTransformedView.setScaleX(transformationAmount);
+            mTransformedView.setScaleY(transformationAmount);
+        } else {
+            super.appear(transformationAmount, otherView);
+        }
+    }
+
+    @Override
+    public void disappear(float transformationAmount, TransformableView otherView) {
+        if (otherView instanceof HybridNotificationView) {
+            if (transformationAmount == 0.0f) {
+                mTransformedView.setPivotY(0);
+                mTransformedView.setPivotX(mTransformedView.getWidth() / 2);
+            }
+            transformationAmount = mapToDuration(1.0f - transformationAmount);
+            CrossFadeHelper.fadeOut(mTransformedView, 1.0f - transformationAmount,
+                    false /* remap */);
+            transformationAmount = Interpolators.LINEAR_OUT_SLOW_IN.getInterpolation(
+                    transformationAmount);
+            mTransformedView.setScaleX(transformationAmount);
+            mTransformedView.setScaleY(transformationAmount);
+        } else {
+            super.disappear(transformationAmount, otherView);
+        }
+    }
+
+    private static float mapToDuration(float scaleAmount) {
+        // Assuming a linear interpolator, we can easily map it to our new duration
+        scaleAmount = (scaleAmount * StackStateAnimator.ANIMATION_DURATION_STANDARD
+                - (StackStateAnimator.ANIMATION_DURATION_STANDARD - ANIMATION_DURATION_LENGTH))
+                        / ANIMATION_DURATION_LENGTH;
+        return Math.max(Math.min(scaleAmount, 1.0f), 0.0f);
+    }
+
     public Icon getIcon() {
         return mIcon;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index f0f5c8d..770ec95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -30,6 +30,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
 
 /**
@@ -357,6 +358,7 @@
 
     public int[] getLaidOutLocationOnScreen() {
         int[] location = getLocationOnScreen();
+        // remove translation
         location[0] -= mTransformedView.getTranslationX();
         location[1] -= mTransformedView.getTranslationY();
         return location;
@@ -364,6 +366,10 @@
 
     public int[] getLocationOnScreen() {
         mTransformedView.getLocationOnScreen(mOwnPosition);
+
+        // remove scale
+        mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
+        mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
         return mOwnPosition;
     }
 
@@ -371,6 +377,20 @@
         return false;
     }
 
+    public void appear(float transformationAmount, TransformableView otherView) {
+        // There's no other view, lets fade us in
+        // Certain views need to prepare the fade in and make sure its children are
+        // completely visible. An example is the notification header.
+        if (transformationAmount == 0.0f) {
+            prepareFadeIn();
+        }
+        CrossFadeHelper.fadeIn(mTransformedView, transformationAmount);
+    }
+
+    public void disappear(float transformationAmount, TransformableView otherView) {
+        CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
+    }
+
     public static TransformState createFrom(View view) {
         if (view instanceof TextView) {
             TextViewTransformState result = TextViewTransformState.obtain();