Merge "Exiting tests after a test fails to deinitialize" into ub-launcher3-master
diff --git a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 70739ef..c579c8a 100644
--- a/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/go/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -85,6 +85,10 @@
             // TODO handle assistant
         }
 
+        public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
+                boolean gestureSwipeLeft) {
+        }
+
         /** Deprecated methods **/
         public void onQuickStep(MotionEvent motionEvent) { }
 
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 5518f09..4974dcb 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -106,7 +106,7 @@
   RESIZE_HANDLE = 8;
   VERTICAL_SCROLL = 9;
   HOME_INTENT = 10; // Deprecated, use enum Command instead
-  BACK_BUTTON = 11; // Deprecated, use enum Command instead
+  BACK_BUTTON = 11;
   QUICK_SCRUB_BUTTON = 12;
   CLEAR_ALL_BUTTON = 13;
   CANCEL_TARGET = 14;
@@ -114,6 +114,7 @@
   SPLIT_SCREEN_TARGET = 16;
   REMOTE_ACTION_SHORTCUT = 17;
   APP_USAGE_SETTINGS = 18;
+  BACK_GESTURE = 19;
 }
 
 enum TipType {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
index f507d0f..518a2a6 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/RecentsUiFactory.java
@@ -59,7 +59,7 @@
     private static final float RECENTS_PREPARE_SCALE = 1.33f;
 
     public static TouchController[] createTouchControllers(Launcher launcher) {
-        Mode mode = SysUINavigationMode.INSTANCE.get(launcher).getMode();
+        Mode mode = SysUINavigationMode.getMode(launcher);
 
         ArrayList<TouchController> list = new ArrayList<>();
         list.add(launcher.getDragController());
@@ -106,7 +106,7 @@
      * @param launcher the launcher activity
      */
     public static void prepareToShowOverview(Launcher launcher) {
-        if (FeatureFlags.SWIPE_HOME.get()) {
+        if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
             // Overview lives on the side, so doesn't scale in from above.
             return;
         }
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index d8f1628..225ae84 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -20,8 +20,9 @@
 import android.os.RemoteException;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.quickstep.RecentsModel;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -76,7 +77,7 @@
 
     @Override
     public int getVisibleElements(Launcher launcher) {
-        if (FeatureFlags.SWIPE_HOME.get()) {
+        if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
             return super.getVisibleElements(launcher);
         }
         // Hide shelf content (e.g. QSB) because we fade it in when swiping up.
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 91a31dd..81090c1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -36,11 +36,12 @@
 import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 
@@ -105,7 +106,7 @@
     private void setupInterpolators(AnimatorSetBuilder animatorSetBuilder) {
         animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2);
         animatorSetBuilder.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2);
-        if (FeatureFlags.SWIPE_HOME.get()) {
+        if (SysUINavigationMode.getMode(mLauncher) == Mode.NO_BUTTON) {
             // Overview lives to the left of workspace, so translate down later than over
             animatorSetBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2);
             animatorSetBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2);
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 62d954b..8b4aa07 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -123,7 +123,7 @@
                     if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
                             .isEventOverView(view, ev)) {
                         mTaskBeingDragged = view;
-                        if (!SysUINavigationMode.INSTANCE.get(mActivity).getMode().hasGestures) {
+                        if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
                             // Don't allow swipe down to open if we don't support swipe up
                             // to enter overview.
                             directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
index 31d6042..21e98f2 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityControllerHelper.java
@@ -192,7 +192,11 @@
 
     @Override
     public int getContainerType() {
-        return LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER;
+        RecentsActivity activity = getCreatedActivity();
+        boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
+        return visible
+                ? LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER
+                : LauncherLogProto.ContainerType.APP;
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 766f484..e903b6f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -16,6 +16,7 @@
 package com.android.quickstep;
 
 import static android.view.View.TRANSLATION_Y;
+
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -24,7 +25,6 @@
 import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -45,16 +45,15 @@
 import com.android.launcher3.LauncherInitListener;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.SpringObjectAnimator;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.views.FloatingIconView;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
@@ -76,8 +75,7 @@
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
         LayoutUtils.calculateLauncherTaskSize(context, dp, outRect);
-        if (dp.isVerticalBarLayout()
-                && SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
+        if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
             Rect targetInsets = dp.getInsets();
             int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
             return dp.hotseatBarSizePx + hotseatInset;
@@ -254,8 +252,8 @@
 
         AnimatorSet anim = new AnimatorSet();
         if (!activity.getDeviceProfile().isVerticalBarLayout()
-                && !FeatureFlags.SWIPE_HOME.get()) {
-            // Don't animate the shelf when SWIPE_HOME is true, because we update it atomically.
+                && SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
+            // Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
             Animator shiftAnim = createShelfProgressAnim(activity,
                     fromState.getVerticalProgress(activity),
                     endState.getVerticalProgress(activity));
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index aada84f..990bcff 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -45,10 +45,10 @@
 import android.view.ViewConfiguration;
 import android.view.WindowManager;
 
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.RaceConditionTracker;
 import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget;
 import com.android.quickstep.util.CachedEventDispatcher;
 import com.android.quickstep.util.MotionPauseDetector;
@@ -83,6 +83,7 @@
     private final InputConsumerController mInputConsumer;
     private final SwipeSharedState mSwipeSharedState;
     private final InputMonitorCompat mInputMonitorCompat;
+    private final SysUINavigationMode.Mode mMode;
 
     private final int mDisplayRotation;
     private final Rect mStableInsets = new Rect();
@@ -127,6 +128,7 @@
         mRunningTask = runningTaskInfo;
         mRecentsModel = recentsModel;
         mHomeIntent = homeIntent;
+        mMode = SysUINavigationMode.getMode(base);
 
         mMotionPauseDetector = new MotionPauseDetector(base);
         mOnCompleteCallback = onCompleteCallback;
@@ -250,7 +252,7 @@
                     // Move
                     mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
 
-                    if (FeatureFlags.SWIPE_HOME.get()) {
+                    if (mMode == Mode.NO_BUTTON) {
                         boolean isLandscape = isNavBarOnLeft() || isNavBarOnRight();
                         float orthogonalDisplacement = !isLandscape
                                 ? ev.getX() - mDownPos.x
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 311824f..87ae091 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -53,6 +53,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.logging.EventLogArray;
+import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.quickstep.SysUINavigationMode.Mode;
@@ -141,6 +142,14 @@
             });
         }
 
+        public void onBackAction(boolean completed, int downX, int downY, boolean isButton,
+                boolean gestureSwipeLeft) {
+            final ActivityControlHelper activityControl =
+                    mOverviewComponentObserver.getActivityControlHelper();
+            UserEventDispatcher.newInstance(getBaseContext()).logActionBack(completed, downX, downY,
+                    isButton, gestureSwipeLeft, activityControl.getContainerType());
+        }
+
         /** Deprecated methods **/
         public void onQuickStep(MotionEvent motionEvent) { }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index b1db780..a974135 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -25,7 +25,6 @@
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
-import static com.android.launcher3.config.FeatureFlags.SWIPE_HOME;
 import static com.android.launcher3.util.RaceConditionTracker.ENTER;
 import static com.android.launcher3.util.RaceConditionTracker.EXIT;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
@@ -85,6 +84,7 @@
 import com.android.quickstep.ActivityControlHelper.AnimationFactory;
 import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
 import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ClipAnimationHelper;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.RemoteAnimationTargetSet;
@@ -232,6 +232,8 @@
     private final ActivityControlHelper<T> mActivityControlHelper;
     private final ActivityInitListener mActivityInitListener;
 
+    private final SysUINavigationMode.Mode mMode;
+
     private final int mRunningTaskId;
     private ThumbnailData mTaskSnapshot;
 
@@ -272,6 +274,7 @@
         mClipAnimationHelper = new ClipAnimationHelper(context);
         mTransformParams = new ClipAnimationHelper.TransformParams();
 
+        mMode = SysUINavigationMode.getMode(context);
         initStateCallbacks();
     }
 
@@ -584,7 +587,7 @@
         final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
         if (passed != mPassedOverviewThreshold) {
             mPassedOverviewThreshold = passed;
-            if (mRecentsView != null && !SWIPE_HOME.get()) {
+            if (mRecentsView != null && mMode != Mode.NO_BUTTON) {
                 mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
             }
@@ -744,7 +747,7 @@
         }
         final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW;
         if (!isFling) {
-            if (SWIPE_HOME.get()) {
+            if (mMode == Mode.NO_BUTTON) {
                 if (mIsShelfPeeking) {
                     endTarget = RECENTS;
                 } else if (goingToNewTask) {
@@ -766,7 +769,7 @@
             startShift = currentShift;
             interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
         } else {
-            if (SWIPE_HOME.get() && endVelocity < 0 && !mIsShelfPeeking) {
+            if (mMode == Mode.NO_BUTTON && endVelocity < 0 && !mIsShelfPeeking) {
                 // If swiping at a diagonal, base end target on the faster velocity.
                 endTarget = goingToNewTask && Math.abs(velocity.x) > Math.abs(endVelocity)
                         ? NEW_TASK : HOME;
@@ -817,7 +820,7 @@
             if (mRecentsView != null) {
                 duration = Math.max(duration, mRecentsView.getScroller().getDuration());
             }
-            if (SWIPE_HOME.get()) {
+            if (mMode == Mode.NO_BUTTON) {
                 setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration);
             }
         } else if (endTarget == NEW_TASK || endTarget == LAST_TASK) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
index 6b3f028..777e592 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -17,12 +17,18 @@
 
 import android.annotation.TargetApi;
 import android.content.Context;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewDebug;
+import android.view.WindowInsets;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
@@ -33,6 +39,9 @@
     private static final int MIN_SIZE = 10;
     private final RecentsActivity mActivity;
 
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private final RectF mTouchExcludeRegion = new RectF();
+
     private final Point mLastKnownSize = new Point(MIN_SIZE, MIN_SIZE);
 
     public RecentsRootView(Context context, AttributeSet attrs) {
@@ -88,4 +97,29 @@
         mActivity.getDeviceProfile().updateInsets(mInsets);
         super.setInsets(mInsets);
     }
+
+    @Override
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        if (Utilities.ATLEAST_Q) {
+            Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+            mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
+                    gestureInsets.right, gestureInsets.bottom);
+        }
+        return super.dispatchApplyWindowInsets(insets);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            float x = ev.getX();
+            float y = ev.getY();
+            if (y < mTouchExcludeRegion.top
+                    || x < mTouchExcludeRegion.left
+                    || x > (getWidth() - mTouchExcludeRegion.right)
+                    || y > (getHeight() - mTouchExcludeRegion.bottom)) {
+                return false;
+            }
+        }
+        return super.dispatchTouchEvent(ev);
+    }
 }
\ No newline at end of file
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 329436b..1ccc3f1 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -130,7 +130,7 @@
             ClipAnimationHelper helper) {
         AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
 
-        if (!SysUINavigationMode.INSTANCE.get(mActivity).getMode().hasGestures) {
+        if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
             // Hotseat doesn't move when opening recents with the button,
             // so don't animate it here either.
             return anim;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 6d730b6..482bbde 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -37,14 +37,17 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
 import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.QuickstepAppTransitionManagerImpl;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.systemui.shared.system.ActivityCompat;
@@ -186,4 +189,13 @@
                 out.toByteArray(), Base64.NO_WRAP | Base64.NO_PADDING));
         return true;
     }
+
+    public static ScaleAndTranslation getOverviewScaleAndTranslationForNormalState(Launcher l) {
+        if (SysUINavigationMode.getMode(l) == Mode.NO_BUTTON) {
+            float offscreenTranslationX = l.getDragLayer().getWidth()
+                    - l.getOverviewPanel().getPaddingStart();
+            return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
+        }
+        return new ScaleAndTranslation(1.1f, 0f, 0f);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index ce472c6..286ddc0 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -27,10 +27,8 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.DiscoveryBounce;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.UiThreadHelper;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 
 import androidx.annotation.WorkerThread;
@@ -150,8 +148,6 @@
     }
 
     private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
-        FeatureFlags.SWIPE_HOME.updateStorage(mContext, mode == Mode.NO_BUTTON);
-
         mSwipeUpEnabled = mode.hasGestures;
         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
         mBgHandler.obtainMessage(MSG_APPLY_FLAGS).sendToTarget();
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
index 1953ecb..dbae794 100644
--- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java
+++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
@@ -48,6 +48,10 @@
         }
     }
 
+    public static Mode getMode(Context context) {
+        return INSTANCE.get(context).getMode();
+    }
+
     public static MainThreadInitializedObject<SysUINavigationMode> INSTANCE =
             new MainThreadInitializedObject<>(SysUINavigationMode::new);
 
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index a06209a..bfe31d1 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -27,6 +27,8 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
 
 import java.lang.annotation.Retention;
 
@@ -116,7 +118,7 @@
     }
 
     public static int getShelfTrackingDistance(Context context, DeviceProfile dp) {
-        if (FeatureFlags.SWIPE_HOME.get()) {
+        if (SysUINavigationMode.getMode(context) == Mode.NO_BUTTON) {
             // Track the bottom of the window rather than the top of the shelf.
             int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
             int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index fe05c4f..d74e880 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -34,9 +34,11 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ScrimView;
+import com.android.quickstep.SysUINavigationMode;
+import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 
 /**
  * Scrim used for all-apps and shelf in Overview
@@ -45,7 +47,7 @@
  *    From normal state to overview state, the shelf just fades in and does not move
  *    From overview state to all-apps state the shelf moves up and fades in to cover the screen
  */
-public class ShelfScrimView extends ScrimView {
+public class ShelfScrimView extends ScrimView implements NavigationModeChangeListener {
 
     // If the progress is more than this, shelf follows the finger, otherwise it moves faster to
     // cover the whole screen
@@ -78,6 +80,8 @@
     private final Path mRemainingScreenPath = new Path();
     private boolean mRemainingScreenPathValid = false;
 
+    private Mode mSysUINavigationMode;
+
     public ShelfScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mMaxScrimAlpha = Math.round(OVERVIEW.getWorkspaceScrimAlpha(mLauncher) * 255);
@@ -98,6 +102,24 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(getContext())
+                .addModeChangeListener(this));
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        SysUINavigationMode.INSTANCE.get(getContext()).removeModeChangeListener(this);
+    }
+
+    @Override
+    public void onNavigationModeChanged(Mode newMode) {
+        mSysUINavigationMode = newMode;
+    }
+
+    @Override
     public void reInitUi() {
         DeviceProfile dp = mLauncher.getDeviceProfile();
         mDrawingFlatColor = dp.isVerticalBarLayout();
@@ -137,7 +159,7 @@
         if (mProgress >= 1) {
             mRemainingScreenColor = 0;
             mShelfColor = 0;
-            if (FeatureFlags.SWIPE_HOME.get()
+            if (mSysUINavigationMode == Mode.NO_BUTTON
                     && mLauncher.getStateManager().getState() == BACKGROUND_APP) {
                 // Show the shelf background when peeking during swipe up.
                 mShelfColor = setColorAlphaBound(mEndScrim, mMidAlpha);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 6623861..4112ccf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -60,7 +60,7 @@
     }
 
     private void startTestApps() throws Exception {
-        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING));
+        startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MARKET));
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS));
 
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 8e2ffe9..f9a8d1b 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -24,6 +24,9 @@
 import com.android.launcher3.util.FocusLogic;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
     private static final int SNAP_DURATION = 150;
     private static final float DIMMED_HANDLE_ALPHA = 0f;
@@ -45,6 +48,7 @@
     private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;
 
     private final View[] mDragHandles = new View[HANDLE_COUNT];
+    private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
 
     private LauncherAppWidgetHostView mWidgetView;
     private CellLayout mCellLayout;
@@ -106,6 +110,10 @@
                 .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
         mTouchTargetWidth = 2 * mBackgroundPadding;
         mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
+
+        for (int i = 0; i < HANDLE_COUNT; i++) {
+            mSystemGestureExclusionRects.add(new Rect());
+        }
     }
 
     @Override
@@ -118,6 +126,19 @@
         }
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        if (Utilities.ATLEAST_Q) {
+            for (int i = 0; i < HANDLE_COUNT; i++) {
+                View dragHandle = mDragHandles[i];
+                mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
+                        dragHandle.getRight(), dragHandle.getBottom());
+            }
+            setSystemGestureExclusionRects(mSystemGestureExclusionRects);
+        }
+    }
+
     public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
         Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
         AbstractFloatingView.closeAllOpenViews(launcher);
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 9f6e5cd..e738eb7 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -8,11 +8,15 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.WindowInsets;
 
 public class LauncherRootView extends InsettableFrameLayout {
 
@@ -23,6 +27,9 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private final Rect mConsumedInsets = new Rect();
 
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private final RectF mTouchExcludeRegion = new RectF();
+
     private View mAlignedView;
     private WindowStateListener mWindowStateListener;
 
@@ -145,6 +152,31 @@
         }
     }
 
+    @Override
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        if (Utilities.ATLEAST_Q) {
+            Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+            mTouchExcludeRegion.set(gestureInsets.left, gestureInsets.top,
+                    gestureInsets.right, gestureInsets.bottom);
+        }
+        return super.dispatchApplyWindowInsets(insets);
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            float x = ev.getX();
+            float y = ev.getY();
+            if (y < mTouchExcludeRegion.top
+                    || x < mTouchExcludeRegion.left
+                    || x > (getWidth() - mTouchExcludeRegion.right)
+                    || y > (getHeight() - mTouchExcludeRegion.bottom)) {
+                return false;
+            }
+        }
+        return super.dispatchTouchEvent(ev);
+    }
+
     public interface WindowStateListener {
 
         void onWindowFocusChanged(boolean hasFocus);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index c65a871..124574c 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -199,12 +199,7 @@
     }
 
     public ScaleAndTranslation getOverviewScaleAndTranslation(Launcher launcher) {
-        if (FeatureFlags.SWIPE_HOME.get()) {
-            float offscreenTranslationX = launcher.getDragLayer().getWidth()
-                    - launcher.getOverviewPanel().getPaddingStart();
-            return new ScaleAndTranslation(1f, offscreenTranslationX, 0f);
-        }
-        return new ScaleAndTranslation(1.1f, 0f, 0f);
+        return UiFactory.getOverviewScaleAndTranslationForNormalState(launcher);
     }
 
     public void onStateEnabled(Launcher launcher) {
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 656151f..5150b7c 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -110,10 +110,6 @@
     public static final TogglableFlag ENABLE_QUICKSTEP_LIVE_TILE = new TogglableFlag(
             "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
 
-    public static final ToggleableGlobalSettingsFlag SWIPE_HOME
-            = new ToggleableGlobalSettingsFlag("SWIPE_HOME", false,
-            "Swiping up on the nav bar goes home. Swipe and hold goes to recent apps.");
-
     public static final TogglableFlag ENABLE_HINTS_IN_OVERVIEW = new TogglableFlag(
             "ENABLE_HINTS_IN_OVERVIEW", false,
             "Show chip hints and gleams on the overview screen");
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 6ccde62..c8a4e2a 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -34,7 +34,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewParent;
+
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
@@ -54,8 +55,6 @@
 import java.util.Locale;
 import java.util.UUID;
 
-import androidx.annotation.Nullable;
-
 /**
  * Manages the creation of {@link LauncherEvent}.
  * To debug this class, execute following command before side loading a new apk.
@@ -359,6 +358,27 @@
         dispatchUserEvent(event, null);
     }
 
+    public void logActionBack(boolean completed, int downX, int downY, boolean isButton,
+            boolean gestureSwipeLeft, int containerType) {
+        int actionTouch = isButton ? Action.Touch.TAP : Action.Touch.SWIPE;
+        Action action = newCommandAction(actionTouch);
+        action.command = Action.Command.BACK;
+        action.dir = isButton
+                ? Action.Direction.NONE
+                : gestureSwipeLeft
+                        ? Action.Direction.LEFT
+                        : Action.Direction.RIGHT;
+        Target target = newControlTarget(isButton
+                ? LauncherLogProto.ControlType.BACK_BUTTON
+                : LauncherLogProto.ControlType.BACK_GESTURE);
+        target.spanX = downX;
+        target.spanY = downY;
+        target.cardinality = completed ? 1 : 0;
+        LauncherEvent event = newLauncherEvent(action, target, newContainerTarget(containerType));
+
+        dispatchUserEvent(event, null);
+    }
+
     /**
      * Currently logs following containers: workspace, allapps, widget tray.
      * @param reason
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 9939c25..c01b54a 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -21,6 +21,7 @@
 import android.os.CancellationSignal;
 
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState.ScaleAndTranslation;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.util.TouchController;
@@ -67,4 +68,9 @@
     public static void prepareToShowOverview(Launcher launcher) { }
 
     public static void setBackButtonAlpha(Launcher launcher, float alpha, boolean animate) { }
+
+
+    public static ScaleAndTranslation getOverviewScaleAndTranslationForNormalState(Launcher l) {
+        return new ScaleAndTranslation(1.1f, 0f, 0f);
+    }
 }
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 91ebd9b..d29d29c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -207,8 +207,8 @@
         // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there.
         executeOnLauncher(launcher -> assertFalse("Initial workspace state is scrollable",
                 isWorkspaceScrollable(launcher)));
-        assertNull("Messages app was found on empty workspace",
-                workspace.tryGetWorkspaceAppIcon("Messages"));
+        assertNull("Play Store app was found on empty workspace",
+                workspace.tryGetWorkspaceAppIcon("Play Store"));
 
         workspace.ensureWorkspaceIsScrollable();
 
@@ -218,8 +218,8 @@
         executeOnLauncher(
                 launcher -> assertTrue("ensureScrollable didn't make workspace scrollable",
                         isWorkspaceScrollable(launcher)));
-        assertNotNull("ensureScrollable didn't add Messages app",
-                workspace.tryGetWorkspaceAppIcon("Messages"));
+        assertNotNull("ensureScrollable didn't add Play Store app",
+                workspace.tryGetWorkspaceAppIcon("Play Store"));
 
         // Test flinging workspace.
         workspace.flingBackward();
@@ -235,10 +235,10 @@
         assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
 
         // Test starting a workspace app.
-        final AppIcon app = workspace.tryGetWorkspaceAppIcon("Messages");
-        assertNotNull("No Messages app in workspace", app);
+        final AppIcon app = workspace.tryGetWorkspaceAppIcon("Play Store");
+        assertNotNull("No Play Store app in workspace", app);
         assertNotNull("AppIcon.launch returned null",
-                app.launch(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING)));
+                app.launch(resolveSystemApp(Intent.CATEGORY_APP_MARKET)));
         executeOnLauncher(launcher -> assertTrue(
                 "Launcher activity is the top activity; expecting another activity to be the top "
                         + "one",
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 22b5564..91443d0 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -50,8 +50,8 @@
      */
     @NonNull
     public AllApps switchToAllApps() {
-        try(LauncherInstrumentation.Closable c =
-                    mLauncher.addContextLayer("want to switch from workspace to all apps")) {
+        try (LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to switch from workspace to all apps")) {
             verifyActiveContainer();
             final UiObject2 hotseat = mHotseat;
             final Point start = hotseat.getVisibleCenter();
@@ -114,7 +114,7 @@
         if (!isWorkspaceScrollable(workspace)) {
             dragIconToWorkspace(
                     mLauncher,
-                    getHotseatAppIcon("Messages"),
+                    getHotseatAppIcon("Play Store"),
                     new Point(mLauncher.getDevice().getDisplayWidth(),
                             workspace.getVisibleBounds().centerY()),
                     (int) (ICON_DRAG_SPEED * mLauncher.getDisplayDensity()));