Separating various UI properties into state variables

> Using workspace scale and translation for all-apps
> Without quickstep, workspace has the parallex effect as before
> With quickstep, workspace scales down to match the recents card width
> Using a single animator for recents views in case of state transtion and
  controlled transition to prevent going into inconsistant state.

Change-Id: I1864de6892052ca771f4d0062e3d60c28840a72d
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 80%
rename from src/com/android/launcher3/states/AllAppsState.java
rename to quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..1064492 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
 
 import android.view.View;
 
@@ -30,8 +31,6 @@
  */
 public class AllAppsState extends LauncherState {
 
-    public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
     private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
 
     public AllAppsState(int id) {
@@ -57,4 +56,15 @@
     public View getFinalFocus(Launcher launcher) {
         return launcher.getAppsView();
     }
+
+    @Override
+    public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+        // TODO: interpolate
+        return LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(launcher);
+    }
+
+    @Override
+    public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+        return (i) -> 0;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index a70ee70..3458a3f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -17,10 +17,12 @@
 
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
 
+import android.graphics.Rect;
 import android.view.View;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.quickstep.RecentsView;
 
@@ -29,7 +31,7 @@
  */
 public class OverviewState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE
+    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM
             | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
 
     public OverviewState(int id) {
@@ -38,8 +40,20 @@
 
     @Override
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
-        // TODO: Find a better transition
-        return new float[] {0f, 0};
+        Rect pageRect = new Rect();
+        RecentsView.getPageRect(launcher, pageRect);
+        Workspace ws = launcher.getWorkspace();
+        float childWidth = ws.getNormalChildWidth();
+        if (childWidth <= 0 || pageRect.isEmpty()) {
+            return super.getWorkspaceScaleAndTranslation(launcher);
+        }
+
+        Rect insets = launcher.getDragLayer().getInsets();
+        float scale = pageRect.width() / childWidth;
+
+        float halfHeight = ws.getHeight() / 2;
+        float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
+        return new float[] {scale, pageRect.top - childTop};
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index da1eff9..b59e4ee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,39 +15,91 @@
  */
 package com.android.launcher3.uioverrides;
 
-import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.view.View;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
 import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsView;
 
 public class RecentsViewStateController implements StateHandler {
 
     private final Launcher mLauncher;
+    private final RecentsView mRecentsView;
+
+    private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::applyProgress);
+    // The fraction representing the visibility of the RecentsView. This allows delaying the
+    // overall transition while the RecentsView is being shown or hidden.
+    private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::applyProgress);
 
     public RecentsViewStateController(Launcher launcher) {
         mLauncher = launcher;
+        mRecentsView = launcher.getOverviewPanel();
+        mRecentsView.setStateController(this);
     }
 
     @Override
     public void setState(LauncherState state) {
-        setState(state, NO_ANIM_PROPERTY_SETTER);
+        setVisibility(state == LauncherState.OVERVIEW);
+        setTransitionProgress(state == LauncherState.OVERVIEW ? 1 : 0);
     }
 
     @Override
     public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
             AnimatorSet anim, AnimationConfig config) {
-        setState(toState, new AnimatedPropertySetter(config.duration, layerViews, anim));
+        ObjectAnimator progressAnim =
+                mTransitionProgress.animateToValue(toState == LauncherState.OVERVIEW ? 1 : 0);
+        progressAnim.setDuration(config.duration);
+        progressAnim.setInterpolator(Interpolators.LINEAR);
+        anim.play(progressAnim);
+
+        ObjectAnimator visibilityAnim = animateVisibility(toState == LauncherState.OVERVIEW);
+        visibilityAnim.setDuration(config.duration);
+        visibilityAnim.setInterpolator(Interpolators.LINEAR);
+        anim.play(visibilityAnim);
     }
 
-    private void setState(LauncherState state, PropertySetter setter) {
-        setter.setViewAlpha(null, mLauncher.getOverviewPanel(),
-                state == LauncherState.OVERVIEW ? 1 : 0);
+    public void setVisibility(boolean isVisible) {
+        mVisibilityMultiplier.cancelAnimation();
+        mRecentsView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+        mVisibilityMultiplier.updateValue(isVisible ? 1 : 0);
+    }
+
+    public ObjectAnimator animateVisibility(boolean isVisible) {
+        ObjectAnimator anim = mVisibilityMultiplier.animateToValue(isVisible ? 1 : 0);
+        if (isVisible) {
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    mRecentsView.setVisibility(View.VISIBLE);
+                }
+            });
+        } else {
+            anim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    mRecentsView.setVisibility(View.GONE);
+                }
+            });
+        }
+        return anim;
+    }
+
+    public void setTransitionProgress(float progress) {
+        mTransitionProgress.cancelAnimation();
+        mTransitionProgress.updateValue(progress);
+    }
+
+    private void applyProgress() {
+        mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 1f6781e..214b3f3 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -47,9 +47,7 @@
     }
 
     public ObjectAnimator animateToValue(float v) {
-        if (mValueAnimator != null) {
-            mValueAnimator.cancel();
-        }
+        cancelAnimation();
         mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v);
         mValueAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -73,6 +71,12 @@
         }
     }
 
+    public void cancelAnimation() {
+        if (mValueAnimator != null) {
+            mValueAnimator.cancel();
+        }
+    }
+
     public ObjectAnimator getCurrentAnimation() {
         return mValueAnimator;
     }
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 4c3a9ad..75db45b 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -42,6 +42,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.states.InternalStateHandler;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.launcher3.util.TraceHelper;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.Task;
@@ -94,6 +95,7 @@
     private Launcher mLauncher;
     private SnapshotDragView mDragView;
     private RecentsView mRecentsView;
+    private RecentsViewStateController mStateController;
     private Hotseat mHotseat;
     private RecentsTaskLoadPlan mLoadPlan;
 
@@ -178,11 +180,13 @@
         mDragView.setPivotX(0);
         mDragView.setPivotY(0);
         mRecentsView = mLauncher.getOverviewPanel();
+        mStateController = mRecentsView.getStateController();
         mHotseat = mLauncher.getHotseat();
 
         // Optimization
         mLauncher.getAppsView().setVisibility(View.GONE);
-        mRecentsView.setVisibility(View.GONE);
+        mStateController.setTransitionProgress(1);
+        mStateController.setVisibility(false);
         TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
     }
 
@@ -209,17 +213,9 @@
         }
 
         if (mTargetRect.isEmpty()) {
+            RecentsView.getPageRect(mLauncher, mTargetRect);
             DragLayer dl = mLauncher.getDragLayer();
             mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight());
-            Rect targetPadding = RecentsView.getPadding(mLauncher);
-            Rect insets = dl.getInsets();
-            mTargetRect.set(
-                    targetPadding.left + insets.left,
-                    targetPadding.top + insets.top,
-                    mSourceRect.right - targetPadding.right - insets.right,
-                    mSourceRect.bottom - targetPadding.bottom - insets.bottom);
-            mTargetRect.top += mLauncher.getResources()
-                    .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
         }
 
         float shift = mCurrentShift.value * mActivityMultiplier.value;
@@ -246,12 +242,15 @@
 
     private void setTaskPlanToUi() {
         mRecentsView.update(mLoadPlan);
-        mRecentsView.setVisibility(View.VISIBLE);
-
-        // Animate alpha
-        mRecentsView.setAlpha(0);
-        mRecentsView.animate().alpha(1).setDuration(RECENTS_VIEW_VISIBILITY_DURATION)
-                .withEndAction(() -> mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE));
+        ObjectAnimator anim = mStateController.animateVisibility(true /* isVisible */)
+                .setDuration(RECENTS_VIEW_VISIBILITY_DURATION);
+        anim.addListener(new AnimationSuccessListener() {
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE);
+            }
+        });
+        anim.start();
     }
 
     @UiThread
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 34ed7f1..c0fd2cf 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -27,6 +27,8 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.RecentsTaskLoader;
 import com.android.systemui.shared.recents.model.Task;
@@ -70,6 +72,8 @@
         }
     };
 
+    private RecentsViewStateController mStateController;
+
     public RecentsView(Context context) {
         this(context, null);
     }
@@ -111,6 +115,14 @@
         updateTaskStackListenerState();
     }
 
+    public void setStateController(RecentsViewStateController stateController) {
+        mStateController = stateController;
+    }
+
+    public RecentsViewStateController getStateController() {
+        return mStateController;
+    }
+
     public void setOverviewStateEnabled(boolean enabled) {
         mOverviewStateEnabled = enabled;
         updateTaskStackListenerState();
@@ -171,7 +183,7 @@
         }
     }
 
-    public static Rect getPadding(Launcher launcher) {
+    private static Rect getPadding(Launcher launcher) {
         DeviceProfile profile = launcher.getDeviceProfile();
         Rect stableInsets = new Rect();
         WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
@@ -185,6 +197,19 @@
         return padding;
     }
 
+    public static void getPageRect(Launcher launcher, Rect outRect) {
+        DragLayer dl = launcher.getDragLayer();
+        Rect targetPadding = getPadding(launcher);
+        Rect insets = dl.getInsets();
+        outRect.set(
+                targetPadding.left + insets.left,
+                targetPadding.top + insets.top,
+                dl.getWidth() - targetPadding.right - insets.right,
+                dl.getHeight() - targetPadding.bottom - insets.bottom);
+        outRect.top += launcher.getResources()
+                .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+    }
+
     @Override
     public void computeScroll() {
         super.computeScroll();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 6b6029d..a9b1619 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1003,7 +1003,7 @@
         int stateOrdinal = savedState.getInt(RUNTIME_STATE, NORMAL.ordinal);
         LauncherState[] stateValues = LauncherState.values();
         LauncherState state = stateValues[stateOrdinal];
-        if (!state.doNotRestore) {
+        if (!state.disableRestore) {
             mStateManager.goToState(state, false /* animated */);
         }
 
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 01d53da..dfb935f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,7 +21,7 @@
 
 import android.view.View;
 
-import com.android.launcher3.states.AllAppsState;
+import com.android.launcher3.uioverrides.AllAppsState;
 import com.android.launcher3.states.SpringLoadedState;
 import com.android.launcher3.uioverrides.OverviewState;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -37,13 +37,16 @@
     protected static final int FLAG_SHOW_SCRIM = 1 << 0;
     protected static final int FLAG_MULTI_PAGE = 1 << 1;
     protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
-    protected static final int FLAG_DO_NOT_RESTORE = 1 << 3;
+    protected static final int FLAG_DISABLE_RESTORE = 1 << 3;
     protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4;
+    protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5;
+
+    protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = (i) -> 1f;
 
     private static final LauncherState[] sAllStates = new LauncherState[4];
 
     public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
-            0, 1f, FLAG_DO_NOT_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
+            0, 1f, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
 
     public static final LauncherState ALL_APPS = new AllAppsState(1);
 
@@ -61,7 +64,7 @@
     /**
      * True if the state can be persisted across activity restarts.
      */
-    public final boolean doNotRestore;
+    public final boolean disableRestore;
 
     /**
      * True if workspace has multiple pages visible.
@@ -94,6 +97,12 @@
      */
     public final boolean workspaceIconsCanBeDragged;
 
+    /**
+     * True if the workspace pages should not be clipped relative to the workspace bounds
+     * for this state.
+     */
+    public final boolean disablePageClipping;
+
     public LauncherState(int id, int containerType, int transitionDuration, float verticalProgress,
             int flags) {
         this.containerType = containerType;
@@ -104,8 +113,9 @@
         this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-        this.doNotRestore = (flags & FLAG_DO_NOT_RESTORE) != 0;
+        this.disableRestore = (flags & FLAG_DISABLE_RESTORE) != 0;
         this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
+        this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
 
         this.verticalProgress = verticalProgress;
 
@@ -135,7 +145,20 @@
         return launcher.getWorkspace().getCurrentPageDescription();
     }
 
+    public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+        if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
+            return DEFAULT_ALPHA_PROVIDER;
+        }
+        int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen();
+        return (childIndex) ->  childIndex != centerPage ? 0 : 1f;
+    }
+
     protected static void dispatchWindowStateChanged(Launcher launcher) {
         launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
     }
+
+    public interface PageAlphaProvider {
+
+        float getPageAlpha(int pageIndex);
+    }
 }
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 1e6016b..2cad95e 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -158,14 +158,14 @@
         mConfig.reset();
 
         if (!animated) {
-            setState(state);
+            onStateTransitionStart(state);
             for (StateHandler handler : getStateHandlers()) {
                 handler.setState(state);
             }
             if (mStateListener != null) {
                 mStateListener.onStateSetImmediately(state);
             }
-            mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+            onStateTransitionEnd(state);
 
             // Run any queued runnable
             if (onCompleteRunnable != null) {
@@ -217,7 +217,7 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 // Change the internal state only when the transition actually starts
-                setState(state);
+                onStateTransitionStart(state);
                 if (mStateListener != null) {
                     mStateListener.onStateTransitionStart(state);
                 }
@@ -237,19 +237,28 @@
                 if (onCompleteRunnable != null) {
                     onCompleteRunnable.run();
                 }
-
-                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+                onStateTransitionEnd(state);
             }
         });
         mConfig.setAnimation(animation);
         return mConfig.mCurrentAnimation;
     }
 
-    private void setState(LauncherState state) {
+    private void onStateTransitionStart(LauncherState state) {
         mState.onStateDisabled(mLauncher);
         mState = state;
         mState.onStateEnabled(mLauncher);
         mLauncher.getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
+
+        if (state.disablePageClipping) {
+            // Only disable clipping if needed, otherwise leave it as previous value.
+            mLauncher.getWorkspace().setClipChildren(false);
+        }
+    }
+
+    private void onStateTransitionEnd(LauncherState state) {
+        mLauncher.getWorkspace().setClipChildren(!state.disablePageClipping);
+        mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
     }
 
     /**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9f6efb3..b23568e 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -593,6 +593,11 @@
                 - mInsets.top - mInsets.bottom;
     }
 
+    public int getNormalChildWidth() {
+        return  getViewportWidth() - getPaddingLeft() - getPaddingRight()
+                - mInsets.left - mInsets.right;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (getChildCount() == 0) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 749afd0..3d59bad 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -193,10 +193,6 @@
     private static final int HOTSEAT_STATE_ALPHA_INDEX = 2;
 
     /**
-     * These values correspond to {@link Direction#X} & {@link Direction#Y}
-     */
-    private final float[] mPageAlpha = new float[] {1, 1};
-    /**
      * Hotseat alpha can be changed when moving horizontally, vertically, changing states.
      * The values correspond to {@link Direction#X}, {@link Direction#Y} &
      * {@link #HOTSEAT_STATE_ALPHA_INDEX} respectively.
@@ -436,7 +432,6 @@
         mCurrentPage = DEFAULT_PAGE;
         DeviceProfile grid = mLauncher.getDeviceProfile();
         setWillNotDraw(false);
-        setClipChildren(false);
         setClipToPadding(false);
 
         setupLayoutTransition();
@@ -1191,33 +1186,21 @@
         // TODO(adamcohen): figure out a final effect here. We may need to recommend
         // different effects based on device performance. On at least one relatively high-end
         // device I've tried, translating the launcher causes things to get quite laggy.
-        setWorkspaceTranslationAndAlpha(Direction.X, transX, alpha);
+        setWorkspaceTranslationAndAlpha(transX, alpha);
         setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
     }
 
     /**
-     * Moves the workspace UI in the Y direction.
-     * @param translation the amount of shift.
-     * @param alpha the alpha for the workspace page
-     */
-    public void setWorkspaceYTranslationAndAlpha(float translation, float alpha) {
-        setWorkspaceTranslationAndAlpha(Direction.Y, translation, alpha);
-    }
-
-    /**
      * Moves the workspace UI in the provided direction.
-     * @param direction the direction to move the workspace
-     * @param translation the amount of shift.
+     * @param translation the amount of horizontal shift.
      * @param alpha the alpha for the workspace page
      */
-    private void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
-        Property<View, Float> property = direction.viewProperty;
-        mPageAlpha[direction.ordinal()] = alpha;
-        float finalAlpha = mPageAlpha[0] * mPageAlpha[1];
+    private void setWorkspaceTranslationAndAlpha(float translation, float alpha) {
+        float finalAlpha = alpha;
 
         View currentChild = getChildAt(getCurrentPage());
         if (currentChild != null) {
-            property.set(currentChild, translation);
+            currentChild.setTranslationX(translation);
             currentChild.setAlpha(finalAlpha);
         }
 
@@ -1225,7 +1208,7 @@
         if (Float.compare(translation, 0) == 0) {
             for (int i = getChildCount() - 1; i >= 0; i--) {
                 View child = getChildAt(i);
-                property.set(child, translation);
+                child.setTranslationX(0);
                 child.setAlpha(finalAlpha);
             }
         }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8edec40..edf5ada 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -26,11 +26,11 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.content.res.Resources;
 import android.util.Property;
 import android.view.View;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.launcher3.LauncherState.PageAlphaProvider;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimationLayerSet;
 import com.android.launcher3.anim.Interpolators;
@@ -97,18 +97,13 @@
     private final Launcher mLauncher;
     private final Workspace mWorkspace;
 
-    private final boolean mWorkspaceFadeInAdjacentScreens;
-
     private float mNewScale;
 
     public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
         mLauncher = launcher;
         mWorkspace = workspace;
-
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-        Resources res = launcher.getResources();
-        mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha);
-        mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
+        mWorkspaceScrimAlpha = launcher.getResources()
+                .getInteger(R.integer.config_workspaceScrimAlpha);
     }
 
     public void setState(LauncherState toState) {
@@ -134,10 +129,10 @@
         mNewScale = scaleAndTranslationY[0];
         final float finalWorkspaceTranslationY = scaleAndTranslationY[1];
 
-        int toPage = mWorkspace.getPageNearestToCenterOfScreen();
+        PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
         final int childCount = mWorkspace.getChildCount();
         for (int i = 0; i < childCount; i++) {
-            applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, toPage,
+            applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
                     propertySetter);
         }
 
@@ -151,21 +146,16 @@
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
-        applyChildState(state, cl, childIndex, mWorkspace.getPageNearestToCenterOfScreen(),
+        applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
                 NO_ANIM_PROPERTY_SETTER);
     }
 
     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
-            int centerPage, PropertySetter propertySetter) {
+            PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
         propertySetter.setInt(cl.getScrimBackground(),
                 DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN);
-
-        // Only animate the page alpha when we actually fade pages
-        if (mWorkspaceFadeInAdjacentScreens) {
-            float finalAlpha = state == LauncherState.NORMAL && childIndex != centerPage ? 0 : 1f;
-            propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
-                    finalAlpha, Interpolators.ZOOM_IN);
-        }
+        propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
+                pageAlphaProvider.getPageAlpha(childIndex), Interpolators.DEACCEL_2);
     }
 
     public static class PropertySetter {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 1ec7ac0..7ce032f 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -53,10 +53,9 @@
         }
     };
 
-    private final Interpolator mWorkspaceAccelnterpolator = Interpolators.ACCEL_2;
     private final Interpolator mHotseatAccelInterpolator = Interpolators.ACCEL_1_5;
 
-    private static final float PARALLAX_COEFFICIENT = .125f;
+    public static final float PARALLAX_COEFFICIENT = .125f;
 
     private AllAppsContainerView mAppsView;
     private Workspace mWorkspace;
@@ -131,7 +130,6 @@
 
         float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
         float alpha = 1 - workspaceHotseatAlpha;
-        float workspaceAlpha = mWorkspaceAccelnterpolator.getInterpolation(workspaceHotseatAlpha);
         float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
 
         updateAllAppsBg(alpha);
@@ -146,8 +144,6 @@
                     PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent),
                     hotseatAlpha);
         }
-        mWorkspace.setWorkspaceYTranslationAndAlpha(
-                PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), workspaceAlpha);
 
         updateLightStatusBar(shiftCurrent);
     }
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 9723545..550fcf9 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -27,13 +27,14 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.states.AllAppsState;
 
 /**
  * Floating view responsible for showing discovery bounce animation
  */
 public class DiscoveryBounce extends AbstractFloatingView {
 
+    public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
+
     private final Launcher mLauncher;
     private final Animator mDiscoBounceAnimation;
 
@@ -95,7 +96,7 @@
 
     public static void showIfNeeded(Launcher launcher) {
         if (!launcher.isInState(NORMAL)
-                || launcher.getSharedPrefs().getBoolean(AllAppsState.APPS_VIEW_SHOWN, false)
+                || launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
                 || AbstractFloatingView.getTopOpenView(launcher) != null
                 || UserManagerCompat.getInstance(launcher).isDemoUser()) {
             return;
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 1d90a08..995cdaa 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -35,7 +35,8 @@
 public class SpringLoadedState extends LauncherState {
 
     private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
-            FLAG_DISABLE_ACCESSIBILITY | FLAG_DO_NOT_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
+            FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
+            FLAG_DISABLE_PAGE_CLIPPING;
 
     // Determines how long to wait after a rotation before restoring the screen orientation to
     // match the sensor state.
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 76%
copy from src/com/android/launcher3/states/AllAppsState.java
copy to src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..bd5ddfe 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
 
 import android.view.View;
 
@@ -23,6 +24,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 /**
@@ -30,8 +32,6 @@
  */
 public class AllAppsState extends LauncherState {
 
-    public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
     private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
 
     public AllAppsState(int id) {
@@ -57,4 +57,16 @@
     public View getFinalFocus(Launcher launcher) {
         return launcher.getAppsView();
     }
+
+    @Override
+    public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+        return new float[] { 1f,
+                -launcher.getAllAppsController().getShiftRange()
+                        * AllAppsTransitionController.PARALLAX_COEFFICIENT};
+    }
+
+    @Override
+    public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+        return (i) -> 0;
+    }
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index dcf7453..2cd3731 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -36,7 +36,8 @@
     // The percent to shrink the workspace during overview mode
     private static final float SCALE_FACTOR = 0.7f;
 
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE;
+    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
+            FLAG_DISABLE_PAGE_CLIPPING;
 
     public OverviewState(int id) {
         super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, 1f, STATE_FLAGS);