Merge "Enabling testQuickSwitchFromApp after causes of flakiness were fixed" into ub-launcher3-master
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index d747bb8..6d105ac 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -71,6 +71,7 @@
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
         android:fullBackupOnly="true"
+        android:backupInForeground="true"
         android:fullBackupContent="@xml/backupscheme"
         android:hardwareAccelerated="true"
         android:icon="@drawable/ic_launcher_home"
diff --git a/OWNERS b/OWNERS
index bf4cd0b..3069afa 100644
--- a/OWNERS
+++ b/OWNERS
@@ -29,5 +29,5 @@
 xuqiu@google.com
 sreyasr@google.com
 
-per-file FeatureFlags.java = sunnygoyal@google.com, adamcohen@google.com
-per-file BaseFlags.java = sunnygoyal@google.com, adamcohen@google.com
+per-file FeatureFlags.java, globs = set noparent
+per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
index ef272ed..686189e 100644
--- a/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
+++ b/quickstep/recents_ui_overrides/res/layout/fallback_recents_activity.xml
@@ -28,4 +28,9 @@
         android:clipToPadding="false"
         android:outlineProvider="none"
         android:theme="@style/HomeScreenElementTheme" />
+
+    <include
+        android:id="@+id/overview_actions_view"
+        layout="@layout/overview_actions_holder" />
+
 </com.android.quickstep.fallback.RecentsRootView>
diff --git a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
index a572cad..eac0bfa 100644
--- a/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
+++ b/quickstep/recents_ui_overrides/res/layout/overview_panel.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
      Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,17 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.InsettableFrameLayout
+<com.android.quickstep.views.LauncherRecentsView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content">
-    <com.android.quickstep.views.LauncherRecentsView
-        android:id="@+id/overview_panel_recents"
-        android:theme="@style/HomeScreenElementTheme"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:accessibilityPaneTitle="@string/accessibility_recent_apps"
-        android:visibility="invisible" />
-</com.android.launcher3.InsettableFrameLayout>
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:theme="@style/HomeScreenElementTheme"
+    android:visibility="invisible" />
diff --git a/quickstep/recents_ui_overrides/res/values/dimens.xml b/quickstep/recents_ui_overrides/res/values/dimens.xml
index de97d08..61c576e 100644
--- a/quickstep/recents_ui_overrides/res/values/dimens.xml
+++ b/quickstep/recents_ui_overrides/res/values/dimens.xml
@@ -23,10 +23,4 @@
 
     <!-- Minimum distance to swipe to trigger accessibility gesture -->
     <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
-
-    <!-- Swipe up to home related -->
-    <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
-    <dimen name="swipe_up_y_overshoot">10dp</dimen>
-    <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
-
 </resources>
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
index 1d1c7bb..e9ce692 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/BaseSwipeUpHandler.java
@@ -17,7 +17,6 @@
 
 import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
@@ -32,6 +31,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Build;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -78,18 +78,16 @@
     private static final String TAG = "BaseSwipeUpHandler";
     protected static final Rect TEMP_RECT = new Rect();
 
-    // Start resisting when swiping past this factor of mTransitionDragLength.
-    private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = ENABLE_OVERVIEW_ACTIONS.get()
-            ? 2.8f : 1.4f;
-    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
-    private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = ENABLE_OVERVIEW_ACTIONS.get()
-            ? 3.6f : 1.8f;
     private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
 
     // The distance needed to drag to reach the task size in recents.
     protected int mTransitionDragLength;
     // How much further we can drag past recents, as a factor of mTransitionDragLength.
     protected float mDragLengthFactor = 1;
+    // Start resisting when swiping past this factor of mTransitionDragLength.
+    private float mDragLengthFactorStartPullback = 1f;
+    // This is how far down we can scale down, where 0f is full screen and 1f is recents.
+    private float mDragLengthFactorMaxPullback = 1f;
 
     protected final Context mContext;
     protected final RecentsAnimationDeviceState mDeviceState;
@@ -161,12 +159,12 @@
         } else {
             float translation = Math.max(displacement, 0);
             shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
-            if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
+            if (shift > mDragLengthFactorStartPullback) {
                 float pullbackProgress = Utilities.getProgress(shift,
-                        DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
+                        mDragLengthFactorStartPullback, mDragLengthFactor);
                 pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
-                shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
-                        * (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
+                shift = mDragLengthFactorStartPullback + pullbackProgress
+                        * (mDragLengthFactorMaxPullback - mDragLengthFactorStartPullback);
             }
         }
 
@@ -344,6 +342,10 @@
             //   their ability to scale past the target rect.
             float dragFactor = (float) dp.heightPx / mTransitionDragLength;
             mDragLengthFactor = displayRotation == 0 ? dragFactor : Math.min(1.0f, dragFactor);
+            Pair<Float, Float> dragFactorStartAndMaxProgress =
+                    mActivityInterface.getSwipeUpPullbackStartAndMaxProgress();
+            mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first;
+            mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second;
         }
     }
 
@@ -448,7 +450,7 @@
             RotationHelper.mapInverseRectFromNormalOrientation(startRect,
                 mDp.widthPx, mDp.heightPx, mOrientedState.getDisplayRotation());
         }
-        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
+        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
         if (isFloatingIconView) {
             FloatingIconView fiv = (FloatingIconView) floatingView;
             anim.addAnimatorListener(fiv);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
index f19ec69..ccc2150 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityInterface.java
@@ -38,6 +38,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.UserHandle;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -54,7 +55,6 @@
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.appprediction.PredictionUiStateManager;
-import com.android.launcher3.touch.PortraitPagedViewHandler;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.views.FloatingIconView;
@@ -80,6 +80,8 @@
 public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
 
     private Runnable mAdjustInterpolatorsRunnable;
+    private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
+            BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
 
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
@@ -94,6 +96,11 @@
     }
 
     @Override
+    public Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
+        return mSwipeUpPullbackStartAndMaxProgress;
+    }
+
+    @Override
     public void onTransitionCancelled(boolean activityVisible) {
         Launcher launcher = getCreatedActivity();
         if (launcher == null) {
@@ -385,6 +392,14 @@
                 return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1);
             });
         };
+
+        // Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
+        float pullbackStartProgress = (0.75f - fromScaleAndTranslation.scale)
+                / (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
+        float pullbackMaxProgress = (0.5f - fromScaleAndTranslation.scale)
+                / (endScaleAndTranslation.scale - fromScaleAndTranslation.scale);
+        mSwipeUpPullbackStartAndMaxProgress = new Pair<>(
+                pullbackStartProgress, pullbackMaxProgress);
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
index 682c92c..dde7605 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -17,7 +17,6 @@
 
 import android.animation.Animator;
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.RectF;
 
@@ -106,7 +105,7 @@
     private float mMinVisChange;
     private float mYOvershoot;
 
-    public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) {
+    public RectFSpringAnim(RectF startRect, RectF targetRect, Context context) {
         mStartRect = startRect;
         mTargetRect = targetRect;
         mCurrentCenterX = mStartRect.centerX();
@@ -114,8 +113,9 @@
         mTrackingBottomY = startRect.bottom < targetRect.bottom;
         mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;
 
-        mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change);
-        mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot);
+        ResourceProvider rp = DynamicResource.provider(context);
+        mMinVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
+        mYOvershoot = rp.getDimension(R.dimen.swipe_up_y_overshoot);
     }
 
     public void onTargetPositionChanged() {
@@ -160,7 +160,7 @@
         float endX = mTargetRect.centerX();
         float minXValue = Math.min(startX, endX);
         float maxXValue = Math.max(startX, endX);
-        mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, startX, endX,
+        mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
                 velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);
 
         float startVelocityY = velocityPxPerMs.y * 1000;
@@ -170,13 +170,13 @@
         float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
         float minYValue = Math.min(startY, endY - mYOvershoot);
         float maxYValue = Math.max(startY, endY);
-        mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
+        mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, startVelocityY,
                 mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);
 
         float minVisibleChange = Math.abs(1f / mStartRect.height());
         ResourceProvider rp = DynamicResource.provider(context);
-        float damping = rp.getFloat(R.dimen.swipe_up_rect_damping_ratio);
-        float stiffness = rp.getFloat(R.dimen.swipe_up_rect_stiffness);
+        float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
+        float stiffness = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
 
         mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
                 .setSpring(new SpringForce(1f)
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 2942bef..9bc95d7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -29,6 +29,7 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.config.FeatureFlags.UNSTABLE_SPRINGS;
 import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
@@ -66,6 +67,7 @@
 import android.util.FloatProperty;
 import android.util.Property;
 import android.util.SparseBooleanArray;
+import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -84,6 +86,7 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
+import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -113,6 +116,7 @@
 import com.android.quickstep.RecentsAnimationTargets;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RecentsModel.TaskVisualsChangeListener;
+import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
@@ -206,7 +210,7 @@
     private boolean mDwbToastShown;
     protected boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
-    private boolean mFreezeViewVisibility;
+    protected boolean mFreezeViewVisibility;
 
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
@@ -325,6 +329,8 @@
 
     // Keeps track of the index where the first TaskView should be
     private int mTaskViewStartIndex = 0;
+    private View mActionsView;
+    private boolean mGestureRunning = false;
 
     private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
             (inMultiWindowMode) -> {
@@ -383,6 +389,11 @@
                 int rotation = RotationHelper.getRotationFromDegrees(i);
                 if (mPreviousRotation != rotation) {
                     animateRecentsRotationInPlace(rotation);
+                    if (rotation == 0) {
+                        showActionsView();
+                    } else {
+                        hideActionsView();
+                    }
                     mPreviousRotation = rotation;
                 }
             }
@@ -473,6 +484,7 @@
                 mIPinnedStackAnimationListener);
         Launcher launcher = Launcher.getLauncher(getContext());
         launcher.getRotationHelper().addForcedRotationCallback(mForcedRotationChangedListener);
+        addActionsView();
     }
 
     @Override
@@ -636,6 +648,7 @@
         if (getTaskViewCount() != requiredTaskCount) {
             if (indexOfChild(mClearAllButton) != -1) {
                 removeView(mClearAllButton);
+                hideActionsView();
             }
             for (int i = getTaskViewCount(); i < requiredTaskCount; i++) {
                 addView(mTaskViewPool.getView());
@@ -645,6 +658,7 @@
             }
             if (requiredTaskCount > 0) {
                 addView(mClearAllButton);
+                showActionsView();
             }
         }
 
@@ -684,6 +698,7 @@
         if (indexOfChild(mClearAllButton) != -1) {
             removeView(mClearAllButton);
         }
+        hideActionsView();
     }
 
     public int getTaskViewCount() {
@@ -931,6 +946,7 @@
         setEnableDrawingLiveTile(false);
         setRunningTaskHidden(true);
         setRunningTaskIconScaledDown(true);
+        mGestureRunning = true;
     }
 
     /**
@@ -1000,6 +1016,7 @@
         }
         setRunningTaskHidden(false);
         animateUpRunningTaskIconScale();
+        mGestureRunning = false;
     }
 
     /**
@@ -1016,6 +1033,7 @@
             addView(taskView, mTaskViewStartIndex);
             if (wasEmpty) {
                 addView(mClearAllButton);
+                showActionsView();
             }
             // The temporary running task is only used for the duration between the start of the
             // gesture and the task list is loaded and applied
@@ -1341,6 +1359,7 @@
 
                     if (getTaskViewCount() == 0) {
                         removeView(mClearAllButton);
+                        hideActionsView();
                         startHome();
                     } else {
                         snapToPageImmediately(pageToSnapTo);
@@ -1485,15 +1504,17 @@
             }
         }
         mClearAllButton.setContentAlpha(mContentAlpha);
-
         int alphaInt = Math.round(alpha * 255);
         mEmptyMessagePaint.setAlpha(alphaInt);
         mEmptyIcon.setAlpha(alphaInt);
-
         if (alpha > 0) {
             setVisibility(VISIBLE);
+            if (!mGestureRunning) {
+                showActionsView();
+            }
         } else if (!mFreezeViewVisibility) {
             setVisibility(GONE);
+            hideActionsView();
         }
     }
 
@@ -1507,6 +1528,11 @@
 
             if (!mFreezeViewVisibility) {
                 setVisibility(mContentAlpha > 0 ? VISIBLE : GONE);
+                if (mContentAlpha > 0) {
+                    showActionsView();
+                } else {
+                    hideActionsView();
+                }
             }
         }
     }
@@ -2057,6 +2083,7 @@
         void onEmptyMessageUpdated(boolean isEmpty);
     }
 
+
     private static class PinnedStackAnimationListener<T extends BaseActivity> extends
             IPinnedStackAnimationListener.Stub {
         private T mActivity;
@@ -2072,4 +2099,34 @@
             mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
         }
     }
+
+    private void showActionsView() {
+        if (mActionsView != null && getTaskViewCount() > 0) {
+            mActionsView.setVisibility(VISIBLE);
+        }
+    }
+
+    private void hideActionsView() {
+        if (mActionsView != null) {
+            mActionsView.setVisibility(GONE);
+        }
+    }
+
+    private void addActionsView() {
+        if (mActionsView == null && ENABLE_OVERVIEW_ACTIONS.get()
+                && SysUINavigationMode.removeShelfFromOverview(mActivity)) {
+            mActionsView = ((ViewGroup) getParent()).findViewById(R.id.overview_actions_view);
+            if (mActionsView != null) {
+                Rect rect = new Rect();
+                getTaskSize(rect);
+                InsettableFrameLayout.LayoutParams layoutParams =
+                        new InsettableFrameLayout.LayoutParams(rect.width(),
+                                getResources().getDimensionPixelSize(
+                                        R.dimen.overview_actions_height));
+                layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+                mActionsView.setLayoutParams(layoutParams);
+                showActionsView();
+            }
+        }
+    }
 }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 9150cc7..e09e01f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -16,6 +16,20 @@
 
 package com.android.quickstep.views;
 
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.CENTER_HORIZONTAL;
+import static android.view.Gravity.CENTER_VERTICAL;
+import static android.view.Gravity.END;
+import static android.view.Gravity.START;
+import static android.view.Gravity.TOP;
+import static android.widget.Toast.LENGTH_SHORT;
+
+import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -39,14 +53,11 @@
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.states.RotationHelper;
@@ -76,20 +87,6 @@
 import java.util.List;
 import java.util.function.Consumer;
 
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_HORIZONTAL;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.widget.Toast.LENGTH_SHORT;
-import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-
 /**
  * A task in the Recents view.
  */
@@ -173,8 +170,6 @@
     private final float mWindowCornerRadius;
     private final BaseDraggingActivity mActivity;
 
-    @Nullable private View mActionsView;
-
     private ObjectAnimator mIconAndDimAnimator;
     private float mIconScaleAnimStartProgress = 0;
     private float mFocusTransitionProgress = 1;
@@ -193,8 +188,6 @@
     private float mFooterVerticalOffset = 0;
     private float mFooterAlpha = 1;
     private int mStackHeight;
-    private boolean mHideActionsView;
-    private PagedOrientationHandler mOrientationHandler;
 
     public TaskView(Context context) {
         this(context, null);
@@ -246,18 +239,6 @@
         TaskView.LayoutParams thumbnailParams = (LayoutParams) mSnapshotView.getLayoutParams();
         thumbnailParams.bottomMargin = LayoutUtils.thumbnailBottomMargin(context);
         mSnapshotView.setLayoutParams(thumbnailParams);
-
-
-        if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(context)) {
-            mActionsView = mSnapshotView.getTaskOverlay().getActionsView();
-            if (mActionsView != null) {
-                TaskView.LayoutParams params = new TaskView.LayoutParams(LayoutParams.MATCH_PARENT,
-                        getResources().getDimensionPixelSize(R.dimen.overview_actions_height),
-                        BOTTOM);
-                addView(mActionsView, params);
-                mActionsView.setAlpha(0);
-            }
-        }
     }
 
     public boolean isTaskOverlayModal() {
@@ -457,7 +438,6 @@
         int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
         LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
         int rotation = RotationHelper.getDegreesFromRotation(iconRotation);
-        mHideActionsView = true;
         switch (iconRotation) {
             case Surface.ROTATION_90:
                 iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
@@ -479,13 +459,11 @@
                 iconParams.gravity = TOP | CENTER_HORIZONTAL;
                 iconParams.leftMargin = iconParams.topMargin = iconParams.rightMargin =
                     iconParams.bottomMargin = 0;
-                mHideActionsView = false;
                 break;
         }
         mSnapshotView.setLayoutParams(snapshotParams);
         mIconView.setLayoutParams(iconParams);
         mIconView.setRotation(rotation);
-        updateActionsViewVisibility(!mHideActionsView);
     }
 
     private void setIconAndDimTransitionProgress(float progress, boolean invert) {
@@ -502,11 +480,6 @@
         mIconView.setScaleX(scale);
         mIconView.setScaleY(scale);
 
-
-        if (mActionsView != null && isRunningTask()) {
-            mActionsView.setAlpha(scale);
-        }
-
         mFooterVerticalOffset = 1.0f - scale;
         for (FooterWrapper footer : mFooters) {
             if (footer != null) {
@@ -597,31 +570,8 @@
             mMenuView.setScaleX(getScaleX());
             mMenuView.setScaleY(getScaleY());
         }
-
-        // This is not the proper implementation and will be replaced with a proper layout.
-        if (mActionsView != null) {
-            if (mFocusTransitionProgress == 1f) {
-                mActionsView.setAlpha(1 - curveInterpolation / MAX_PAGE_SCRIM_ALPHA);
-            }
-            maintainActionViewPosition(curveScaleForCurveInterpolation);
-        }
-
     }
 
-    private void maintainActionViewPosition(float curveScaleForCurveInterpolation) {
-        float inverseCurveScaleFactor = curveScaleForCurveInterpolation == 0 ? 0 :
-                (1f / curveScaleForCurveInterpolation);
-        mActionsView.setScaleX(inverseCurveScaleFactor);
-        mActionsView.setScaleY(inverseCurveScaleFactor);
-        mActionsView.setTranslationX(inverseCurveScaleFactor * (-getX()
-                + getRecentsView().getScrollX() + getRecentsView().scrollOffsetLeft()));
-        mActionsView.setTranslationY(
-                (1f - curveScaleForCurveInterpolation) * (mSnapshotView.getHeight()
-                        + mActionsView.getHeight()) / 2f
-                        + inverseCurveScaleFactor * (-getTranslationY()));
-    }
-
-
     /**
      * Sets the footer at the specific index and returns the previously set footer.
      */
@@ -903,7 +853,6 @@
         mFullscreenProgress = progress;
         boolean isFullscreen = mFullscreenProgress > 0;
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
-        updateActionsViewVisibility(progress < 1 && !mHideActionsView);
         setClipChildren(!isFullscreen);
         setClipToPadding(!isFullscreen);
 
@@ -937,12 +886,6 @@
         invalidateOutline();
     }
 
-    private void updateActionsViewVisibility(boolean isVisible) {
-        if (mActionsView != null) {
-            mActionsView.setVisibility(isVisible ? VISIBLE : GONE);
-        }
-    }
-
     public boolean isRunningTask() {
         if (getRecentsView() == null) {
             return false;
@@ -990,5 +933,4 @@
             mScale = scale;
         }
     }
-
 }
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index fa0e840..fb0cd17 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -36,6 +36,7 @@
 
 import com.android.launcher3.LauncherState.ScaleAndTranslation;
 import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.accessibility.SystemActions;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WellbeingModel;
 import com.android.launcher3.popup.SystemShortcut;
@@ -53,6 +54,7 @@
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.quickstep.util.ShelfPeekAnim;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.util.stream.Stream;
 
@@ -62,6 +64,8 @@
 public abstract class BaseQuickstepLauncher extends Launcher
         implements NavigationModeChangeListener {
 
+    protected SystemActions mSystemActions;
+
     /**
      * Reusable command for applying the back button alpha on the background thread.
      */
@@ -74,6 +78,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mSystemActions = new SystemActions(this);
 
         SysUINavigationMode.Mode mode = SysUINavigationMode.INSTANCE.get(this)
                 .addModeChangeListener(this);
@@ -132,6 +137,12 @@
     }
 
     @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        mSystemActions.onActivityResult(requestCode);
+    }
+
+    @Override
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
         // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
@@ -148,6 +159,12 @@
     }
 
     @Override
+    protected void onUiChangedWhileSleeping() {
+        // Remove the snapshot because the content view may have obvious changes.
+        ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this);
+    }
+
+    @Override
     public void startIntentSenderForResult(IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
         if (requestCode != -1) {
@@ -188,6 +205,15 @@
             // removes the task itself.
             startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
         }
+
+        // Register all system actions once they are available
+        mSystemActions.register();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mSystemActions.unregister();
     }
 
     @Override
@@ -196,7 +222,10 @@
 
         if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
             // Overview is above all other launcher elements, including qsb, so move it to the top.
-            getOverviewPanelContainer().bringToFront();
+            getOverviewPanel().bringToFront();
+            if (getActionsView() != null) {
+                getActionsView().bringToFront();
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/accessibility/SystemActions.java b/quickstep/src/com/android/launcher3/accessibility/SystemActions.java
new file mode 100644
index 0000000..669877f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/accessibility/SystemActions.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.R;
+
+/**
+ * Manages the launcher system actions presented to accessibility services.
+ */
+public class SystemActions {
+
+    /**
+     * System Action ID to show all apps.  This ID should follow the ones in
+     * com.android.systemui.accessibility.SystemActions.
+     */
+    private static final int SYSTEM_ACTION_ID_ALL_APPS = 100;
+
+    private Launcher mLauncher;
+    private AccessibilityManager mAccessibilityManager;
+    private RemoteAction mAllAppsAction;
+    private boolean mRegistered;
+
+    public SystemActions(Launcher launcher) {
+        mLauncher = launcher;
+        mAccessibilityManager = (AccessibilityManager) launcher.getSystemService(
+                Context.ACCESSIBILITY_SERVICE);
+        mAllAppsAction = new RemoteAction(
+                Icon.createWithResource(launcher, R.drawable.ic_apps),
+                launcher.getString(R.string.all_apps_label),
+                launcher.getString(R.string.all_apps_label),
+                launcher.createPendingResult(SYSTEM_ACTION_ID_ALL_APPS, new Intent(),
+                        0 /* flags */));
+    }
+
+    public void register() {
+        if (mRegistered) {
+            return;
+        }
+        mAccessibilityManager.registerSystemAction(mAllAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
+        mRegistered = true;
+    }
+
+    public void unregister() {
+        if (!mRegistered) {
+            return;
+        }
+        mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
+        mRegistered = false;
+    }
+
+    public void onActivityResult(int requestCode) {
+        if (requestCode == SYSTEM_ACTION_ID_ALL_APPS) {
+            showAllApps();
+        }
+    }
+
+    private void showAllApps() {
+        LauncherStateManager stateManager = mLauncher.getStateManager();
+        stateManager.goToState(NORMAL);
+        stateManager.goToState(ALL_APPS);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 174e49b..7481445 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -52,10 +52,12 @@
         implements StateHandler {
     protected final T mRecentsView;
     protected final Launcher mLauncher;
+    protected final View mActionsView;
 
     public BaseRecentsViewStateController(@NonNull Launcher launcher) {
         mLauncher = launcher;
         mRecentsView = launcher.getOverviewPanel();
+        mActionsView = launcher.getActionsView();
     }
 
     @Override
@@ -72,6 +74,10 @@
         getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
         OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
         SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
+        if (mActionsView != null) {
+            mActionsView.setTranslationX(translationX);
+            mActionsView.setAlpha(state.overviewUi ? 1f : 0);
+        }
     }
 
     @Override
@@ -118,6 +124,11 @@
         OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
         setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
                 builder.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
+        if (mActionsView != null) {
+            setter.setFloat(mActionsView, View.TRANSLATION_X, translationX, translateXInterpolator);
+            setter.setFloat(mActionsView, View.ALPHA, toState.overviewUi ? 1 : 0,
+                    builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 64e053f..1d71fe2 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -20,6 +20,7 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Build;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -50,6 +51,15 @@
 
     int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
 
+    /**
+     * @return The progress of the swipe where we start resisting the user, where 0 is fullscreen
+     * and 1 is recents. These values should probably be greater than 1 to let the user swipe past
+     * recents before we start resisting them.
+     */
+    default Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
+        return new Pair<>(1.4f, 1.8f);
+    }
+
     void onSwipeUpToRecentsComplete();
 
     default void onSwipeUpToHomeComplete() { }
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 85ef4c6..866836e 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -33,6 +33,7 @@
 import android.content.pm.ResolveInfo;
 import android.util.SparseIntArray;
 
+import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.systemui.shared.system.PackageManagerWrapper;
 
 import java.io.PrintWriter;
@@ -44,18 +45,11 @@
  * and provide callers the relevant classes.
  */
 public final class OverviewComponentObserver {
-    private final BroadcastReceiver mUserPreferenceChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            updateOverviewTargets();
-        }
-    };
-    private final BroadcastReceiver mOtherHomeAppUpdateReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            updateOverviewTargets();
-        }
-    };
+    private final BroadcastReceiver mUserPreferenceChangeReceiver =
+            new SimpleBroadcastReceiver(this::updateOverviewTargets);
+    private final BroadcastReceiver mOtherHomeAppUpdateReceiver =
+            new SimpleBroadcastReceiver(this::updateOverviewTargets);
+
     private final Context mContext;
     private final RecentsAnimationDeviceState mDeviceState;
     private final Intent mCurrentHomeIntent;
@@ -106,6 +100,10 @@
         }
     }
 
+    private void updateOverviewTargets(Intent unused) {
+        updateOverviewTargets();
+    }
+
     /**
      * Update overview intent and {@link BaseActivityInterface} based off the current launcher home
      * component.
@@ -131,11 +129,8 @@
             mOverviewIntent = mMyHomeIntent;
             mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
 
-            if (mUpdateRegisteredPackage != null) {
-                // Remove any update listener as we don't care about other packages.
-                mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
-                mUpdateRegisteredPackage = null;
-            }
+            // Remove any update listener as we don't care about other packages.
+            unregisterOtherHomeAppUpdateReceiver();
         } else {
             // The default home app is a different launcher. Use the fallback Overview instead.
 
@@ -149,13 +144,9 @@
             // Listen for package updates of this app (and remove any previously attached
             // package listener).
             if (defaultHome == null) {
-                if (mUpdateRegisteredPackage != null) {
-                    mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
-                }
+                unregisterOtherHomeAppUpdateReceiver();
             } else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
-                if (mUpdateRegisteredPackage != null) {
-                    mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
-                }
+                unregisterOtherHomeAppUpdateReceiver();
 
                 mUpdateRegisteredPackage = defaultHome.getPackageName();
                 mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter(
@@ -170,7 +161,10 @@
      */
     public void onDestroy() {
         mContext.unregisterReceiver(mUserPreferenceChangeReceiver);
+        unregisterOtherHomeAppUpdateReceiver();
+    }
 
+    private void unregisterOtherHomeAppUpdateReceiver() {
         if (mUpdateRegisteredPackage != null) {
             mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
             mUpdateRegisteredPackage = null;
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 9a053f2..ccfa3fc 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -3,8 +3,6 @@
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -13,12 +11,12 @@
 import android.app.PendingIntent;
 import android.app.usage.UsageStatsManager;
 import android.content.Intent;
+import android.os.Build;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.Launcher;
-import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.views.DigitalWellBeingToast;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -35,9 +33,10 @@
             resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
 
     @Test
-    // b/150303529
-    @TestStabilityRule.Stability(flavors = UNBUNDLED_POSTSUBMIT | PLATFORM_POSTSUBMIT)
     public void testToast() throws Exception {
+        // b/150303529
+        if (Build.MODEL.contains("Cuttlefish")) return;
+
         startAppFast(CALCULATOR_PACKAGE);
 
         final UsageStatsManager usageStatsManager =
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 6c66897..196eb0f 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -44,8 +44,13 @@
             layout="@layout/hotseat" />
 
         <include
-            android:id="@+id/overview_panel_container"
-            layout="@layout/overview_panel"/>
+            android:id="@+id/overview_panel"
+            layout="@layout/overview_panel"
+            android:visibility="gone" />
+
+        <include
+            android:id="@+id/overview_actions_view"
+            layout="@layout/overview_actions_holder" />
 
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
diff --git a/res/layout/overview_actions_holder.xml b/res/layout/overview_actions_holder.xml
new file mode 100644
index 0000000..5946bf6
--- /dev/null
+++ b/res/layout/overview_actions_holder.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<Space
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="0dp"
+    android:layout_height="0dp" />
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index 7fff711..2637f03 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,9 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout
-      xmlns:android="http://schemas.android.com/apk/res/android"
-      android:id="@+id/overview_panel_recents"
-      android:layout_width="0dp"
-      android:layout_height="0dp"
-      android:visibility="gone" />
\ No newline at end of file
+<Space
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="0dp"
+    android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index 35e5e6d..df0f233 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -133,12 +133,21 @@
     <item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.75</item>
     <item name="horizontal_spring_stiffness" type="dimen" format="float">200</item>
 
-    <item name="swipe_up_rect_damping_ratio" type="dimen" format="float">0.75</item>
-    <item name="swipe_up_rect_stiffness" type="dimen" format="float">200</item>
+    <item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
+    <item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
+
+    <item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
+    <item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
+    <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
 
     <item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
     <item name="staggered_stiffness" type="dimen" format="float">150</item>
 
+    <!-- Swipe up to home related -->
+    <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
+    <dimen name="swipe_up_y_overshoot">10dp</dimen>
+    <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
+
     <array name="dynamic_resources">
         <item>@dimen/all_apps_spring_damping_ratio</item>
         <item>@dimen/all_apps_spring_stiffness</item>
@@ -152,10 +161,17 @@
         <item>@dimen/horizontal_spring_damping_ratio</item>
         <item>@dimen/horizontal_spring_stiffness</item>
 
-        <item>@dimen/swipe_up_rect_damping_ratio</item>
-        <item>@dimen/swipe_up_rect_stiffness</item>
+        <item>@dimen/swipe_up_rect_scale_damping_ratio</item>
+        <item>@dimen/swipe_up_rect_scale_stiffness</item>
+
+        <item>@dimen/swipe_up_rect_xy_fling_friction</item>
+        <item>@dimen/swipe_up_rect_xy_damping_ratio</item>
+        <item>@dimen/swipe_up_rect_xy_stiffness</item>
 
         <item>@dimen/staggered_damping_ratio</item>
         <item>@dimen/staggered_stiffness</item>
+
+        <item>@dimen/swipe_up_fling_min_visible_change</item>
+        <item>@dimen/swipe_up_y_overshoot</item>
     </array>
 </resources>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d6e8710..20ebc7a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -80,7 +80,6 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.OvershootInterpolator;
-import android.widget.FrameLayout;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -274,7 +273,7 @@
 
     // UI and state for the overview panel
     private View mOverviewPanel;
-    private FrameLayout mOverviewPanelContainer;
+    private View mActionsView;
 
     @Thunk
     boolean mWorkspaceLoading = true;
@@ -834,6 +833,7 @@
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY, false);
             }
         }
+
         mDragLayer.clearAnimatedView();
     }
 
@@ -924,6 +924,9 @@
 
     @Override
     protected void onStop() {
+        final boolean wasActive = isUserActive();
+        final LauncherState origState = getStateManager().getState();
+        final int origDragLayerChildCount = mDragLayer.getChildCount();
         super.onStop();
 
         if (mDeferOverlayCallbacks) {
@@ -941,6 +944,20 @@
 
         // Workaround for b/78520668, explicitly trim memory once UI is hidden
         onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
+
+        if (wasActive) {
+            // The expected condition is that this activity is stopped because the device goes to
+            // sleep and the UI may have noticeable changes.
+            mDragLayer.post(() -> {
+                if ((!getStateManager().isInStableState(origState)
+                        // The drag layer may be animating (e.g. dismissing QSB).
+                        || mDragLayer.getAlpha() < 1
+                        // Maybe an ArrowPopup is closed.
+                        || mDragLayer.getChildCount() != origDragLayerChildCount)) {
+                    onUiChangedWhileSleeping();
+                }
+            });
+        }
     }
 
     @Override
@@ -1145,8 +1162,8 @@
         mFocusHandler = mDragLayer.getFocusIndicatorHelper();
         mWorkspace = mDragLayer.findViewById(R.id.workspace);
         mWorkspace.initParentViews(mDragLayer);
-        mOverviewPanel = findViewById(R.id.overview_panel_recents);
-        mOverviewPanelContainer = findViewById(R.id.overview_panel_container);
+        mOverviewPanel = findViewById(R.id.overview_panel);
+        mActionsView = findViewById(R.id.overview_actions_view);
         mHotseat = findViewById(R.id.hotseat);
 
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -1336,11 +1353,16 @@
             // Reset AllApps to its initial state only if we are not in the middle of
             // processing a multi-step drop
             if (mPendingRequestArgs == null) {
+                if (!isInState(NORMAL)) {
+                    onUiChangedWhileSleeping();
+                }
                 mStateManager.goToState(NORMAL);
             }
         }
     };
 
+    protected void onUiChangedWhileSleeping() { }
+
     private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
         mWorkspace.updateNotificationDots(updatedDots);
         mAppsView.getAppsStore().updateNotificationDots(updatedDots);
@@ -1389,8 +1411,8 @@
         return (T) mOverviewPanel;
     }
 
-    public FrameLayout getOverviewPanelContainer() {
-        return mOverviewPanelContainer;
+    public View getActionsView() {
+        return mActionsView;
     }
 
     public DropTargetBar getDropTargetBar() {
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 195e69b..9f25729 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -164,6 +164,15 @@
     }
 
     /**
+     * @return {@code true} if the state matches the current state and there is no active
+     *         transition to different state.
+     */
+    public boolean isInStableState(LauncherState state) {
+        return mState == state && mCurrentStableState == state
+                && (mConfig.mTargetState == null || mConfig.mTargetState == state);
+    }
+
+    /**
      * @see #goToState(LauncherState, boolean, Runnable)
      */
     public void goToState(LauncherState state) {
diff --git a/src/com/android/launcher3/anim/FlingSpringAnim.java b/src/com/android/launcher3/anim/FlingSpringAnim.java
index eaf3b1c..06d0f1c 100644
--- a/src/com/android/launcher3/anim/FlingSpringAnim.java
+++ b/src/com/android/launcher3/anim/FlingSpringAnim.java
@@ -15,32 +15,40 @@
  */
 package com.android.launcher3.anim;
 
+import android.content.Context;
+
 import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
 import androidx.dynamicanimation.animation.FlingAnimation;
 import androidx.dynamicanimation.animation.FloatPropertyCompat;
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.dynamicanimation.animation.SpringForce;
 
+import com.android.launcher3.R;
+import com.android.launcher3.util.DynamicResource;
+import com.android.systemui.plugins.ResourceProvider;
+
 /**
  * Given a property to animate and a target value and starting velocity, first apply friction to
  * the fling until we pass the target, then apply a spring force to pull towards the target.
  */
 public class FlingSpringAnim {
 
-    private static final float FLING_FRICTION = 1.5f;
-    private static final float SPRING_STIFFNESS = 200;
-    private static final float SPRING_DAMPING = 0.8f;
-
     private final FlingAnimation mFlingAnim;
     private SpringAnimation mSpringAnim;
 
     private float mTargetPosition;
 
-    public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
-            float targetPosition, float startVelocity, float minVisChange, float minValue,
-            float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
+    public <K> FlingSpringAnim(K object, Context context, FloatPropertyCompat<K> property,
+            float startPosition, float targetPosition, float startVelocity, float minVisChange,
+            float minValue, float maxValue, float springVelocityFactor,
+            OnAnimationEndListener onEndListener) {
+        ResourceProvider rp = DynamicResource.provider(context);
+        float damping = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
+        float stiffness = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness);
+        float friction = rp.getFloat(R.dimen.swipe_up_rect_xy_fling_friction);
+
         mFlingAnim = new FlingAnimation(object, property)
-                .setFriction(FLING_FRICTION)
+                .setFriction(friction)
                 // Have the spring pull towards the target if we've slowed down too much before
                 // reaching it.
                 .setMinimumVisibleChange(minVisChange)
@@ -54,8 +62,8 @@
                     .setStartValue(value)
                     .setStartVelocity(velocity * springVelocityFactor)
                     .setSpring(new SpringForce(mTargetPosition)
-                            .setStiffness(SPRING_STIFFNESS)
-                            .setDampingRatio(SPRING_DAMPING));
+                            .setStiffness(stiffness)
+                            .setDampingRatio(damping));
             mSpringAnim.addEndListener(onEndListener);
             mSpringAnim.animateToFinalPosition(mTargetPosition);
         }));
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 531426a..aab6671 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -101,7 +101,7 @@
             "Adds localized title and keyword search and ranking");
 
     public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
-            "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
+            "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
 
     public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
             "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
@@ -143,6 +143,11 @@
             "ENABLE_LSQ_VELOCITY_PROVIDER", false,
             "Use Least Square algorithm for motion pause detection.");
 
+    public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS =
+            getDebugFlag(
+            "ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS", false,
+            "Always use hardware optimization for folder animations.");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index e33d89f..69f93de 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
 import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_CUSTOM;
 import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_EMPTY;
 import static com.android.launcher3.userevent.LauncherLogProto.Target.FromFolderLabelState.FROM_FOLDER_LABEL_STATE_UNSPECIFIED;
@@ -546,6 +547,8 @@
     }
 
     private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
+        if (ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS.get()) return true;
+
         int folderCount = 0;
         final ShortcutAndWidgetContainer container = currentCellLayout.getShortcutsAndWidgets();
         for (int i = container.getChildCount() - 1; i >= 0; --i) {
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index a3fdf8d..bfeb1dc 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -38,7 +38,7 @@
     private static final DateFormat DATE_FORMAT =
             DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
 
-    private static final long MAX_LOG_FILE_SIZE = 4 << 20;  // 4 mb
+    private static final long MAX_LOG_FILE_SIZE = 8 << 20;  // 4 mb
 
     private static Handler sHandler = null;
     private static File sLogsDirectory = null;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index e93df96..c6192bc 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -35,9 +35,11 @@
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
+import android.os.Debug;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
@@ -117,6 +119,14 @@
                                 // so let's just mark the fact that the leak has happened.
                                 if (sDetectedActivityLeak == null) {
                                     sDetectedActivityLeak = violation.toString();
+                                    try {
+                                        Debug.dumpHprofData(
+                                                getInstrumentation().getTargetContext()
+                                                        .getFilesDir().getPath()
+                                                        + "/ActivityLeakHeapDump.hprof");
+                                    } catch (IOException e) {
+                                        Log.e(TAG, "dumpHprofData failed", e);
+                                    }
                                 }
                             });
             StrictMode.setVmPolicy(builder.build());
@@ -126,18 +136,6 @@
     public static void checkDetectedLeaks() {
         if (sDetectedActivityLeak != null && !sActivityLeakReported) {
             sActivityLeakReported = true;
-
-            final UiDevice device = UiDevice.getInstance(getInstrumentation());
-            try {
-                device.executeShellCommand(
-                        "am dumpheap "
-                                + device.getLauncherPackageName()
-                                + " "
-                                + getInstrumentation().getTargetContext().getFilesDir().getPath()
-                                + "/ActivityLeakHeapDump.hprof");
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 17858a0..9b12a62 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -145,7 +145,7 @@
 
     private static final String WORKSPACE_RES_ID = "workspace";
     private static final String APPS_RES_ID = "apps_view";
-    private static final String OVERVIEW_RES_ID = "overview_panel_recents";
+    private static final String OVERVIEW_RES_ID = "overview_panel";
     private static final String WIDGETS_RES_ID = "widgets_list_view";
     private static final String CONTEXT_MENU_RES_ID = "deep_shortcuts_container";
     public static final int WAIT_TIME_MS = 10000;