Fix jump in animation for hotseat while re-arranging icons

While re-arranging icons the hotseat remains in scale 1.0f, while the workspace reduces it's scale (as defined by SpringLoadedState.java). Previously, the code to aggregate animations was assuming hotseat and workspace always had the same scale.

MultiScaleProperty.get() was being used to set the starting value of the animation. Previously, it was returning the last aggregated value. However, this value was correct only for the workspace, but not for the hotseat. Returning the current view scale makes it always correct.

Bug: 220271046
Test: Dragged icons from hotseat to workspace, and verified animation didn't jump
Change-Id: Ic01776c1d8e3967624626ed7c44d194a06295790
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 4300392..c43172c 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -67,18 +67,16 @@
             };
 
     /**
-     * Property to set the scale of workspace and hotseat. The value is based on a combination
+     * Property to set the scale of workspace. The value is based on a combination
      * of all the ones set, to have a smooth experience even in the case of overlapping scaling
      * animation.
      */
-    public static final MultiScalePropertyFactory<View> SCALE_PROPERTY_FACTORY =
-            new MultiScalePropertyFactory<View>("scale_property") {
-                @Override
-                protected void apply(View view, float scale) {
-                    view.setScaleX(scale);
-                    view.setScaleY(scale);
-                }
-            };
+    public static final MultiScalePropertyFactory<Workspace> WORKSPACE_SCALE_PROPERTY_FACTORY =
+            new MultiScalePropertyFactory<Workspace>("workspace_scale_property");
+
+    /** Property to set the scale of hotseat. */
+    public static final MultiScalePropertyFactory<Hotseat> HOTSEAT_SCALE_PROPERTY_FACTORY =
+            new MultiScalePropertyFactory<Hotseat>("hotseat_scale_property");
 
     public static final int SCALE_INDEX_UNFOLD_ANIMATION = 1;
     public static final int SCALE_INDEX_UNLOCK_ANIMATION = 2;
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 98e785f..d94e84c 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,11 +18,12 @@
 
 import static androidx.dynamicanimation.animation.DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE;
 
+import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE;
-import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherState.FLAG_HAS_SYS_UI_SCRIM;
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
@@ -64,8 +65,11 @@
  */
 public class WorkspaceStateTransitionAnimation {
 
-    private static final FloatProperty<View> WORKSPACE_STATE_SCALE_PROPERTY =
-            SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
+    private static final FloatProperty<Workspace> WORKSPACE_SCALE_PROPERTY =
+            WORKSPACE_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
+
+    private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
+            HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WORKSPACE_STATE);
 
     private final Launcher mLauncher;
     private final Workspace mWorkspace;
@@ -120,9 +124,9 @@
                 && fromState == HINT_STATE && state == NORMAL;
         if (shouldSpring) {
             ((PendingAnimation) propertySetter).add(getSpringScaleAnimator(mLauncher,
-                    mWorkspace, mNewScale));
+                    mWorkspace, mNewScale, WORKSPACE_SCALE_PROPERTY));
         } else {
-            propertySetter.setFloat(mWorkspace, WORKSPACE_STATE_SCALE_PROPERTY, mNewScale,
+            propertySetter.setFloat(mWorkspace, WORKSPACE_SCALE_PROPERTY, mNewScale,
                     scaleInterpolator);
         }
 
@@ -130,11 +134,12 @@
         float hotseatScale = hotseatScaleAndTranslation.scale;
         if (shouldSpring) {
             PendingAnimation pa = (PendingAnimation) propertySetter;
-            pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale));
+            pa.add(getSpringScaleAnimator(mLauncher, hotseat, hotseatScale,
+                    HOTSEAT_SCALE_PROPERTY));
         } else {
             Interpolator hotseatScaleInterpolator = config.getInterpolator(ANIM_HOTSEAT_SCALE,
                     scaleInterpolator);
-            propertySetter.setFloat(hotseat, WORKSPACE_STATE_SCALE_PROPERTY, hotseatScale,
+            propertySetter.setFloat(hotseat, HOTSEAT_SCALE_PROPERTY, hotseatScale,
                     hotseatScaleInterpolator);
         }
 
@@ -198,9 +203,18 @@
     }
 
     /**
+     * Returns a spring based animator for the scale property of {@param workspace}.
+     */
+    public static ValueAnimator getWorkspaceSpringScaleAnimator(Launcher launcher,
+            Workspace workspace, float scale) {
+        return getSpringScaleAnimator(launcher, workspace, scale, WORKSPACE_SCALE_PROPERTY);
+    }
+
+    /**
      * Returns a spring based animator for the scale property of {@param v}.
      */
-    public static ValueAnimator getSpringScaleAnimator(Launcher launcher, View v, float scale) {
+    public static <T extends View> ValueAnimator getSpringScaleAnimator(Launcher launcher, T v,
+            float scale, FloatProperty<T> property) {
         ResourceProvider rp = DynamicResource.provider(launcher);
         float damping = rp.getFloat(R.dimen.hint_scale_damping_ratio);
         float stiffness = rp.getFloat(R.dimen.hint_scale_stiffness);
@@ -211,9 +225,9 @@
                 .setDampingRatio(damping)
                 .setMinimumVisibleChange(MIN_VISIBLE_CHANGE_SCALE)
                 .setEndValue(scale)
-                .setStartValue(WORKSPACE_STATE_SCALE_PROPERTY.get(v))
+                .setStartValue(property.get(v))
                 .setStartVelocity(velocityPxPerS)
-                .build(v, WORKSPACE_STATE_SCALE_PROPERTY);
+                .build(v, property);
 
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/MultiScalePropertyFactory.java b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
index f27d0f0..a7e6cc8 100644
--- a/src/com/android/launcher3/util/MultiScalePropertyFactory.java
+++ b/src/com/android/launcher3/util/MultiScalePropertyFactory.java
@@ -18,6 +18,8 @@
 
 import android.util.ArrayMap;
 import android.util.FloatProperty;
+import android.util.Log;
+import android.view.View;
 
 import com.android.launcher3.Utilities;
 
@@ -33,8 +35,10 @@
  *
  * @param <T> Type where to apply the property.
  */
-public abstract class MultiScalePropertyFactory<T> {
+public class MultiScalePropertyFactory<T extends View> {
 
+    private static final boolean DEBUG = false;
+    private static final String TAG = "MultiScaleProperty";
     private final String mName;
     private final ArrayMap<Integer, MultiScaleProperty> mProperties =
             new ArrayMap<Integer, MultiScaleProperty>();
@@ -56,7 +60,6 @@
                 (k) -> new MultiScaleProperty(index, mName + "_" + index));
     }
 
-
     /**
      * Each [setValue] will be aggregated with the other properties values created by the
      * corresponding factory.
@@ -91,11 +94,22 @@
             mLastAggregatedValue = Utilities.boundToRange(multValue, minValue, maxValue);
             mValue = newValue;
             apply(obj, mLastAggregatedValue);
+
+            if (DEBUG) {
+                Log.d(TAG, "name=" + mName
+                        + " newValue=" + newValue + " mInx=" + mInx
+                        + " aggregated=" + mLastAggregatedValue + " others= " + mProperties);
+            }
         }
 
         @Override
-        public Float get(T t) {
-            return mLastAggregatedValue;
+        public Float get(T view) {
+            // The scale of the view should match mLastAggregatedValue. Still, if it has been
+            // changed without using this property, it can differ. As this get method is usually
+            // used to set the starting point on an animation, this would result in some jumps
+            // when the view scale is different than the last aggregated value. To stay on the
+            // safe side, let's return the real view scale.
+            return view.getScaleX();
         }
 
         @Override
@@ -104,6 +118,8 @@
         }
     }
 
-    /** Applies value to object after setValue method is called. */
-    protected abstract void apply(T obj, float value);
+    protected void apply(View view, float value) {
+        view.setScaleX(value);
+        view.setScaleY(value);
+    }
 }