Update interpolators and durations for state animations

When we enter overview (overview appears, workspace disappears):
- Workspace scales down from 1f to .8f with OvershootInterpolator(1.2f) at 200 ms
- Workspace fades from 1f to 0 with OvershootInterpolator(1.2f) at 200 ms
- Overview scales down from 1.33f to 1f with OvershootInterpolator(1.2f) at 200 ms
- Overview fades from 0 to 1f with OvershootInterpolator(1.2f) at 200 ms

When we exit overview (overview disappears, workspace appears):
- Workspace scales up from .92f to .1f with DecelerateInterpolator() at 200 ms
- Workspace fades from 0 to 1f with AccelerateInterpolator() at 200 ms
- Overview scales up from 1f to 1.1f with AccelerateInterpolator() at 180ms
- Overview fades from 1f to 0 with DecelerateInterpolator(1.7f) at 200 ms

Parallax while the finger moves: Workspace translates half the distance as the shelf

Bug: 79776746
Change-Id: I319d982cf202bcd6dbbcd68ffc5c0c7853629c7e
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 5052674..fbe27b0 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -186,7 +186,7 @@
      *   translationY factor where 0 is top aligned and 0.5 is centered vertically
      */
     public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
-        return new float[] {1.2f, 0.2f};
+        return new float[] {1.1f, 0f};
     }
 
     public void onStateEnabled(Launcher launcher) {
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index cf0c7fc..e6fc4c6 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -16,7 +16,17 @@
 
 package com.android.launcher3;
 
+import static android.view.View.VISIBLE;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 
 import android.animation.Animator;
@@ -237,8 +247,10 @@
         // transition plays in reverse and use the same duration as previous state.
         mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
 
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        prepareForAtomicAnimation(mState, state, builder);
         AnimatorSet animation = createAnimationToNewWorkspaceInternal(
-                state, new AnimatorSetBuilder(), onCompleteRunnable);
+                state, builder, onCompleteRunnable);
         Runnable runnable = new StartAnimRunnable(animation, state.getFinalFocus(mLauncher));
         if (delay > 0) {
             mUiHandler.postDelayed(runnable, delay);
@@ -248,6 +260,43 @@
     }
 
     /**
+     * Prepares for a non-user controlled animation from fromState to toState. Preparations include:
+     * - Setting interpolators for various animations included in the state transition.
+     * - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
+     */
+    public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
+            AnimatorSetBuilder builder) {
+        if (fromState == NORMAL && toState.overviewUi) {
+            builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+
+            // Start from a higher overview scale, but only if we're invisible so we don't jump.
+            UiFactory.prepareToShowOverview(mLauncher);
+        } else if (fromState.overviewUi && toState == NORMAL) {
+            builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+            builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+            builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+            builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
+            Workspace workspace = mLauncher.getWorkspace();
+
+            // Start from a higher workspace scale, but only if we're invisible so we don't jump.
+            boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
+            if (isWorkspaceVisible) {
+                CellLayout currentChild = (CellLayout) workspace.getChildAt(
+                        workspace.getCurrentPage());
+                isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
+                        && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
+            }
+            if (!isWorkspaceVisible) {
+                workspace.setScaleX(0.92f);
+                workspace.setScaleY(0.92f);
+            }
+        }
+    }
+
+    /**
      * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
      * state transition.
      * @param state the final state for the transition.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 9f26e4a..e734e70 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -20,6 +20,10 @@
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS;
 import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS;
@@ -30,7 +34,6 @@
 import com.android.launcher3.LauncherState.PageAlphaProvider;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 
@@ -50,12 +53,13 @@
     }
 
     public void setState(LauncherState toState) {
-        setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimationConfig());
+        setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(),
+                new AnimationConfig());
     }
 
     public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
             AnimationConfig config) {
-        setWorkspaceProperty(toState, config.getPropertySetter(builder), config);
+        setWorkspaceProperty(toState, config.getPropertySetter(builder), builder, config);
     }
 
     public float getFinalScale() {
@@ -66,26 +70,28 @@
      * Starts a transition animation for the workspace.
      */
     private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
-            AnimationConfig config) {
+            AnimatorSetBuilder builder, AnimationConfig config) {
         float[] scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
         mNewScale = scaleAndTranslation[0];
         PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
         final int childCount = mWorkspace.getChildCount();
         for (int i = 0; i < childCount; i++) {
             applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
-                    propertySetter, config);
+                    propertySetter, builder, config);
         }
 
-
         int elements = state.getVisibleElements(mLauncher);
+        Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
+                pageAlphaProvider.interpolator);
         boolean playAtomicComponent = config.playAtomicComponent();
         if (playAtomicComponent) {
-            propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_OUT);
+            Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
+            propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
             float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
             propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha,
-                    pageAlphaProvider.interpolator);
+                    fadeInterpolator);
             propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
-                    hotseatIconsAlpha, pageAlphaProvider.interpolator);
+                    hotseatIconsAlpha, fadeInterpolator);
         }
 
         if (!config.playNonAtomicComponent()) {
@@ -93,43 +99,42 @@
             return;
         }
 
-        Interpolator translationInterpolator = !playAtomicComponent ? Interpolators.LINEAR
-                : Interpolators.ZOOM_OUT;
+        Interpolator translationInterpolator = !playAtomicComponent ? LINEAR : ZOOM_OUT;
         propertySetter.setFloat(mWorkspace, View.TRANSLATION_X,
                 scaleAndTranslation[1], translationInterpolator);
         propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
                 scaleAndTranslation[2], translationInterpolator);
 
         propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(),
-                (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0,
-                pageAlphaProvider.interpolator);
+                (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0, fadeInterpolator);
 
         // Set scrim
         WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
         propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
-                Interpolators.LINEAR);
-        propertySetter.setFloat(scrim, SYSUI_PROGRESS, state.hasSysUiScrim ? 1 : 0,
-                Interpolators.LINEAR);
+                LINEAR);
+        propertySetter.setFloat(scrim, SYSUI_PROGRESS, state.hasSysUiScrim ? 1 : 0, LINEAR);
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
         applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
-                NO_ANIM_PROPERTY_SETTER, new AnimationConfig());
+                NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new AnimationConfig());
     }
 
     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
             PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
-            AnimationConfig config) {
+            AnimatorSetBuilder builder, AnimationConfig config) {
         float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
         int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
 
         if (config.playNonAtomicComponent()) {
             propertySetter.setInt(cl.getScrimBackground(),
-                    DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_OUT);
+                    DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
         }
         if (config.playAtomicComponent()) {
+            Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
+                    pageAlphaProvider.interpolator);
             propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
-                    pageAlpha, pageAlphaProvider.interpolator);
+                    pageAlpha, fadeInterpolator);
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 0ae58db..2c3e3ee 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -3,6 +3,8 @@
 import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
 import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -172,7 +174,9 @@
             return;
         }
 
-        Interpolator interpolator = config.userControlled ? LINEAR : FAST_OUT_SLOW_IN;
+        Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
+                ? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
+                : FAST_OUT_SLOW_IN;
         ObjectAnimator anim =
                 ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, mProgress, targetProgress);
         anim.setDuration(config.duration);
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index dae2dbc..f10bce8 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.anim;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.util.SparseArray;
 import android.view.animation.Interpolator;
@@ -32,6 +31,10 @@
 public class AnimatorSetBuilder {
 
     public static final int ANIM_VERTICAL_PROGRESS = 0;
+    public static final int ANIM_WORKSPACE_SCALE = 1;
+    public static final int ANIM_WORKSPACE_FADE = 2;
+    public static final int ANIM_OVERVIEW_SCALE = 3;
+    public static final int ANIM_OVERVIEW_FADE = 4;
 
     protected final ArrayList<Animator> mAnims = new ArrayList<>();
 
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 8374f98..bace7df 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -58,7 +58,7 @@
         EXAGGERATED_EASE = new PathInterpolator(exaggeratedEase);
     }
 
-    public static final Interpolator OVERSHOOT_0 = new OvershootInterpolator(0);
+    public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
 
     public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 087549e..e29250a 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -64,8 +64,7 @@
      * Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
      */
     public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 0.5f;
-    private static final long ATOMIC_NORMAL_TO_OVERVIEW_DURATION = 120;
-    private static final long ATOMIC_OVERVIEW_TO_NORMAL_DURATION = 200;
+    protected static final long ATOMIC_DURATION = 200;
 
     protected final Launcher mLauncher;
     protected final SwipeDetector mDetector;
@@ -213,7 +212,7 @@
                     mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
                     long duration = (long) (getShiftRange() * 2);
                     mAtomicComponentsController = AnimatorPlaybackController.wrap(
-                            createAtomicAnimForState(mToState, duration), duration);
+                            createAtomicAnimForState(mFromState, mToState, duration), duration);
                     mAtomicComponentsController.dispatchOnStart();
                 }
             });
@@ -295,14 +294,13 @@
                 : 1f - ATOMIC_OVERVIEW_ANIM_THRESHOLD;
         boolean passedThreshold = progress >= threshold;
         if (passedThreshold != mPassedOverviewAtomicThreshold) {
-            LauncherState targetState = passedThreshold ? toState : fromState;
+            LauncherState atomicFromState = passedThreshold ? fromState: toState;
+            LauncherState atomicToState = passedThreshold ? toState : fromState;
             mPassedOverviewAtomicThreshold = passedThreshold;
             if (mAtomicAnim != null) {
                 mAtomicAnim.cancel();
             }
-            long duration = targetState == OVERVIEW ? ATOMIC_NORMAL_TO_OVERVIEW_DURATION
-                    : ATOMIC_OVERVIEW_TO_NORMAL_DURATION;
-            mAtomicAnim = createAtomicAnimForState(targetState, duration);
+            mAtomicAnim = createAtomicAnimForState(atomicFromState, atomicToState, ATOMIC_DURATION);
             mAtomicAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -314,8 +312,10 @@
         }
     }
 
-    private AnimatorSet createAtomicAnimForState(LauncherState targetState, long duration) {
+    private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
+            long duration) {
         AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        mLauncher.getStateManager().prepareForAtomicAnimation(fromState, targetState, builder);
         AnimationConfig config = new AnimationConfig();
         config.animComponents = ATOMIC_COMPONENT;
         config.duration = duration;