Merge "Assert keyguard gone at beginning and end of PortraitLandscapeRunner" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 7032d5f..c13c68c 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -147,3 +147,10 @@
   description: "Enables widget suggestions in widget picker to be displayed in categories"
   bug: "318410881"
 }
+
+flag {
+    name: "use_activity_overlay"
+    namespace: "launcher"
+    description: "Use an activity for home screen overlay"
+    bug: "273828110"
+}
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index b9b4461..436fe3b 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -28,6 +28,7 @@
 import android.content.ClipDescription;
 import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.WindowInsetsController;
 import android.view.WindowManager;
@@ -35,6 +36,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.dragndrop.SimpleDragLayer;
+import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.widget.BaseWidgetSheet;
@@ -43,9 +45,13 @@
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
 import java.util.ArrayList;
+import java.util.Locale;
 
 /** An Activity that can host Launcher's widget picker. */
 public class WidgetPickerActivity extends BaseActivity {
+    private static final String TAG = "WidgetPickerActivity";
+    private static final boolean DEBUG = false;
+
     /**
      * Name of the extra that indicates that a widget being dragged.
      *
@@ -54,10 +60,19 @@
      */
     private static final String EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag";
 
+    // Intent extras that specify the desired widget width and height. If these are not specified in
+    // the intent, then widgets will not be filtered for size.
+    private static final String EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width";
+    private static final String EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height";
+
+
     private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
     private WidgetsModel mModel;
     private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
 
+    private int mDesiredWidgetWidth;
+    private int mDesiredWidgetHeight;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -82,6 +97,13 @@
         widgetSheet.disableNavBarScrim(true);
         widgetSheet.addOnCloseListener(this::finish);
 
+        // A value of 0 for either size means that no filtering will occur in that dimension. If
+        // both values are 0, then no size filtering will occur.
+        mDesiredWidgetWidth =
+                getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_WIDTH, 0);
+        mDesiredWidgetHeight =
+                getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_HEIGHT, 0);
+
         refreshAndBindWidgets();
     }
 
@@ -160,9 +182,108 @@
             final ArrayList<WidgetsListBaseEntry> widgets =
                     mModel.getFilteredWidgetsListForPicker(
                             app.getContext(),
-                            /*widgetItemFilter=*/ item -> item.widgetInfo != null
+                            /*widgetItemFilter=*/ widget -> {
+                                final WidgetAcceptabilityVerdict verdict =
+                                        isWidgetAcceptable(widget);
+                                verdict.maybeLogVerdict();
+                                return verdict.isAcceptable;
+                            }
                     );
             MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
         });
     }
+
+    private WidgetAcceptabilityVerdict isWidgetAcceptable(WidgetItem widget) {
+        final AppWidgetProviderInfo info = widget.widgetInfo;
+        if (info == null) {
+            return rejectWidget(widget, "shortcut");
+        }
+
+        if (mDesiredWidgetWidth == 0 && mDesiredWidgetHeight == 0) {
+            // Accept the widget if the desired dimensions are unspecified.
+            return acceptWidget(widget);
+        }
+
+        final boolean isHorizontallyResizable =
+                (info.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
+        if (mDesiredWidgetWidth > 0 && isHorizontallyResizable) {
+            if (info.maxResizeWidth > 0 && info.maxResizeWidth < mDesiredWidgetWidth) {
+                return rejectWidget(
+                        widget,
+                        String.format(
+                                Locale.ENGLISH,
+                                "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
+                                info.maxResizeWidth,
+                                mDesiredWidgetWidth));
+            }
+
+            final int minWidth = info.minResizeWidth > 0 ? info.minResizeWidth : info.minWidth;
+            if (minWidth > mDesiredWidgetWidth) {
+                return rejectWidget(
+                        widget,
+                        String.format(
+                                Locale.ENGLISH,
+                                "minWidth[%d] > mDesiredWidgetWidth[%d]",
+                                minWidth,
+                                mDesiredWidgetWidth));
+            }
+        }
+
+        final boolean isVerticallyResizable =
+                (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
+        if (mDesiredWidgetHeight > 0 && isVerticallyResizable) {
+            if (info.maxResizeHeight > 0 && info.maxResizeHeight < mDesiredWidgetHeight) {
+                return rejectWidget(
+                        widget,
+                        String.format(
+                                Locale.ENGLISH,
+                                "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
+                                info.maxResizeHeight,
+                                mDesiredWidgetHeight));
+            }
+
+            final int minHeight = info.minResizeHeight > 0 ? info.minResizeHeight : info.minHeight;
+            if (minHeight > mDesiredWidgetHeight) {
+                return rejectWidget(
+                        widget,
+                        String.format(
+                                Locale.ENGLISH,
+                                "minHeight[%d] > mDesiredWidgetHeight[%d]",
+                                minHeight,
+                                mDesiredWidgetHeight));
+            }
+        }
+
+        if (!isHorizontallyResizable
+                && !isVerticallyResizable
+                && (info.minWidth < mDesiredWidgetWidth || info.minHeight < mDesiredWidgetHeight)) {
+            return rejectWidget(widget, "too small and not resizeable");
+        }
+
+        return acceptWidget(widget);
+    }
+
+    private static WidgetAcceptabilityVerdict rejectWidget(
+            WidgetItem widget, String rejectionReason) {
+        return new WidgetAcceptabilityVerdict(false, widget.label, rejectionReason);
+    }
+
+    private static WidgetAcceptabilityVerdict acceptWidget(WidgetItem widget) {
+        return new WidgetAcceptabilityVerdict(true, widget.label, "");
+    }
+
+    private record WidgetAcceptabilityVerdict(
+            boolean isAcceptable, String widgetLabel, String reason) {
+        void maybeLogVerdict() {
+            // Only log a verdict if a reason is specified.
+            if (DEBUG && !reason.isEmpty()) {
+                Log.i(TAG, String.format(
+                        Locale.ENGLISH,
+                        "%s: %s because %s",
+                        widgetLabel,
+                        isAcceptable ? "accepted" : "rejected",
+                        reason));
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 27224f2..c961302 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -45,7 +45,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimUtils;
 import com.android.quickstep.util.SplitAnimationTimings;
 import com.android.quickstep.views.ClearAllButton;
@@ -130,7 +130,7 @@
         }
 
         // Create transition animations to split select
-        PagedOrientationHandler orientationHandler =
+        RecentsPagedOrientationHandler orientationHandler =
                 ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
         Pair<FloatProperty, FloatProperty> taskViewsFloat =
                 orientationHandler.getSplitSelectTaskOffset(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index ec84550..ef5096b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -36,13 +36,13 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.BaseSwipeDetector;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.FlingBlockCheck;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.VibrationConstants;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -225,7 +225,8 @@
             mCurrentAnimation.dispatchOnCancel();
         }
 
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         mCurrentAnimationIsGoingUp = goingUp;
         BaseDragLayer dl = mActivity.getDragLayer();
         final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl);
@@ -269,7 +270,8 @@
 
     @Override
     public void onDragStart(boolean start, float startDisplacement) {
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         if (mCurrentAnimation == null) {
             reInitAnimationController(orientationHandler.isGoingUp(startDisplacement, mIsRtl));
             mDisplacementShift = 0;
@@ -283,7 +285,8 @@
 
     @Override
     public boolean onDrag(float displacement) {
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         float totalDisplacement = displacement + mDisplacementShift;
         boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
                 orientationHandler.isGoingUp(totalDisplacement, mIsRtl);
@@ -346,7 +349,8 @@
         if (blockedFling) {
             fling = false;
         }
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
         float progress = mCurrentAnimation.getProgressFraction();
         float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 377b866..ca82a2d 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -62,6 +62,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.views.ScrimView;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
@@ -128,7 +129,7 @@
 
     public abstract int getSwipeUpDestinationAndLength(
             DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler);
+            RecentsPagedOrientationHandler orientationHandler);
 
     /** Called when the animation to home has fully settled. */
     public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 5c96000..693d6ae 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -32,10 +32,10 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.FallbackTaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.GestureState.GestureEndTarget;
 import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
@@ -60,7 +60,7 @@
     /** 2 */
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index feaa063..70b9183 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -46,11 +46,11 @@
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.GestureState.GestureEndTarget;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
@@ -74,7 +74,7 @@
 
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout()
                 && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 65c8662..dffb882 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -14,8 +14,8 @@
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
@@ -56,7 +56,7 @@
                 }
                 Rect focusedTaskRect = new Rect();
                 LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
-                        focusedTaskRect, PagedOrientationHandler.PORTRAIT);
+                        focusedTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
                 return response;
             }
@@ -67,7 +67,7 @@
                 }
                 Rect gridTaskRect = new Rect();
                 LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
-                        gridTaskRect, PagedOrientationHandler.PORTRAIT);
+                        gridTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
                 response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
                 return response;
             }
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index e481165..b920c10 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
@@ -151,7 +152,7 @@
     @UiThread
     public abstract void onCurrentShiftUpdated();
 
-    protected PagedOrientationHandler getOrientationHandler() {
+    protected RecentsPagedOrientationHandler getOrientationHandler() {
         // OrientationHandler should be independent of remote target, can directly take one
         return mRemoteTargetHandles[0].getTaskViewSimulator()
                 .getOrientationState().getOrientationHandler();
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 73b786f..9c84df8 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -47,9 +47,9 @@
 import com.android.launcher3.model.WellbeingModel;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.popup.SystemShortcut.AppInfo;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskThumbnailView;
@@ -281,7 +281,7 @@
             final int intentFlags = task.key.baseIntent.getFlags();
             final TaskView taskView = taskContainer.getTaskView();
             final RecentsView recentsView = taskView.getRecentsView();
-            final PagedOrientationHandler orientationHandler =
+            final RecentsPagedOrientationHandler orientationHandler =
                     recentsView.getPagedOrientationHandler();
 
             boolean notEnoughTasksToSplit =
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java
similarity index 96%
rename from src/com/android/launcher3/touch/LandscapePagedViewHandler.java
rename to quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java
index f7afcb9..e41832b 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.touch;
+package com.android.quickstep.orientation;
 
 import static android.view.Gravity.BOTTOM;
 import static android.view.Gravity.CENTER_VERTICAL;
@@ -54,16 +54,18 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.views.IconAppChipView;
 
 import java.util.Collections;
 import java.util.List;
 
-public class LandscapePagedViewHandler implements PagedOrientationHandler {
+public class LandscapePagedViewHandler implements RecentsPagedOrientationHandler {
 
     @Override
     public <T> T getPrimaryValue(T x, T y) {
@@ -398,7 +400,7 @@
 
     @Override
     public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
-        boolean layoutChild) {
+            boolean layoutChild) {
         final int childHeight = child.getMeasuredHeight();
         final int childBottom = childStart + childHeight;
         final int childWidth = child.getMeasuredWidth();
@@ -574,21 +576,21 @@
     }
 
     @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
+    public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
             FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
-        boolean isRtl = iconAppChipMenuView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        boolean isRtl = iconAppChipView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         iconMenuParams.gravity = (isRtl ? START : END) | (isRtl ? BOTTOM : TOP);
         iconMenuParams.setMarginStart(isRtl ? iconMenuMargin : 0);
         iconMenuParams.topMargin = iconMenuMargin;
         iconMenuParams.bottomMargin = isRtl ? iconMenuMargin : 0;
         iconMenuParams.setMarginEnd(iconMenuMargin);
 
-        iconAppChipMenuView.setPivotX(isRtl ? iconMenuParams.width - (iconMenuParams.height / 2f)
+        iconAppChipView.setPivotX(isRtl ? iconMenuParams.width - (iconMenuParams.height / 2f)
                 : iconMenuParams.width / 2f);
-        iconAppChipMenuView.setPivotY(
+        iconAppChipView.setPivotY(
                 isRtl ? (iconMenuParams.height / 2f) : iconMenuParams.width / 2f);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
+        iconAppChipView.setTranslationY(0);
+        iconAppChipView.setRotation(getDegreesRotated());
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
similarity index 90%
rename from src/com/android/launcher3/touch/PortraitPagedViewHandler.java
rename to quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index 8301981..3d7065b 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.touch;
+package com.android.quickstep.orientation;
 
 import static android.view.Gravity.BOTTOM;
 import static android.view.Gravity.CENTER_HORIZONTAL;
@@ -33,7 +33,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
 
-import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -42,26 +41,27 @@
 import android.util.FloatProperty;
 import android.util.Pair;
 import android.view.Gravity;
-import android.view.MotionEvent;
 import android.view.Surface;
-import android.view.VelocityTracker;
 import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.DefaultPagedViewHandler;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.quickstep.views.IconAppChipView;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class PortraitPagedViewHandler implements PagedOrientationHandler {
+public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
+        RecentsPagedOrientationHandler {
 
     private final Matrix mTmpMatrix = new Matrix();
     private final RectF mTmpRectF = new RectF();
@@ -75,27 +75,6 @@
     public <T> T getSecondaryValue(T x, T y) {
         return y;
     }
-
-    @Override
-    public int getPrimaryValue(int x, int y) {
-        return x;
-    }
-
-    @Override
-    public int getSecondaryValue(int x, int y) {
-        return y;
-    }
-
-    @Override
-    public float getPrimaryValue(float x, float y) {
-        return x;
-    }
-
-    @Override
-    public float getSecondaryValue(float x, float y) {
-        return y;
-    }
-
     @Override
     public boolean isLayoutNaturalToLauncher() {
         return true;
@@ -116,16 +95,6 @@
     }
 
     @Override
-    public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
-        action.call(target, param, 0);
-    }
-
-    @Override
-    public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
-        action.call(target, param, 0);
-    }
-
-    @Override
     public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
         action.call(target, 0, param);
     }
@@ -137,21 +106,6 @@
     }
 
     @Override
-    public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
-        return event.getX(pointerIndex);
-    }
-
-    @Override
-    public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
-        return velocityTracker.getXVelocity(pointerId);
-    }
-
-    @Override
-    public int getMeasuredSize(View view) {
-        return view.getMeasuredWidth();
-    }
-
-    @Override
     public int getPrimarySize(View view) {
         return view.getWidth();
     }
@@ -192,26 +146,6 @@
     }
 
     @Override
-    public int getPrimaryScroll(View view) {
-        return view.getScrollX();
-    }
-
-    @Override
-    public float getPrimaryScale(View view) {
-        return view.getScaleX();
-    }
-
-    @Override
-    public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
-        event.setMaxScrollX(maxScroll);
-    }
-
-    @Override
-    public boolean getRecentsRtlSetting(Resources resources) {
-        return !Utilities.isRtl(resources);
-    }
-
-    @Override
     public float getDegreesRotated() {
         return 0;
     }
@@ -231,27 +165,6 @@
         view.setScaleY(scale);
     }
 
-    @Override
-    public int getChildStart(View view) {
-        return view.getLeft();
-    }
-
-    @Override
-    public int getCenterForPage(View view, Rect insets) {
-        return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
-            - insets.bottom - view.getPaddingBottom()) / 2;
-    }
-
-    @Override
-    public int getScrollOffsetStart(View view, Rect insets) {
-        return insets.left + view.getPaddingLeft();
-    }
-
-    @Override
-    public int getScrollOffsetEnd(View view, Rect insets) {
-        return view.getWidth() - view.getPaddingRight() - insets.right;
-    }
-
     public int getSecondaryTranslationDirectionFactor() {
         return -1;
     }
@@ -400,20 +313,6 @@
     }
 
     /* -------------------- */
-
-    @Override
-    public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
-        boolean layoutChild) {
-        final int childWidth = child.getMeasuredWidth();
-        final int childRight = childStart + childWidth;
-        final int childHeight = child.getMeasuredHeight();
-        final int childTop = pageCenter - childHeight / 2;
-        if (layoutChild) {
-            child.layout(childStart, childTop, childRight, childTop + childHeight);
-        }
-        return new ChildBounds(childWidth, childHeight, childRight, childTop);
-    }
-
     @Override
     public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
         return dp.heightPx - rect.bottom;
@@ -713,7 +612,7 @@
     }
 
     @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
+    public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
             FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
         iconMenuParams.gravity = TOP | START;
         iconMenuParams.setMarginStart(iconMenuMargin);
@@ -721,10 +620,10 @@
         iconMenuParams.bottomMargin = 0;
         iconMenuParams.setMarginEnd(0);
 
-        iconAppChipMenuView.setPivotX(0);
-        iconAppChipMenuView.setPivotY(0);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
+        iconAppChipView.setPivotX(0);
+        iconAppChipView.setPivotY(0);
+        iconAppChipView.setTranslationY(0);
+        iconAppChipView.setRotation(getDegreesRotated());
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java
new file mode 100644
index 0000000..34756b4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2024 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.quickstep.orientation;
+
+
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.FloatProperty;
+import android.util.Pair;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.quickstep.views.IconAppChipView;
+
+import java.util.List;
+
+/**
+ * Abstraction layer to separate horizontal and vertical specific implementations
+ * for {@link com.android.quickstep.views.RecentsView}. Majority of these implementations are
+ * (should be) as simple as choosing the correct X and Y analogous methods.
+ */
+public interface RecentsPagedOrientationHandler extends PagedOrientationHandler {
+
+    RecentsPagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
+    RecentsPagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
+    RecentsPagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
+
+    <T> void setSecondary(T target, Float2DAction<T> action, float param);
+    <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
+    int getPrimarySize(View view);
+    float getPrimarySize(RectF rect);
+    int getSecondaryTranslationDirectionFactor();
+    float getDegreesRotated();
+    int getRotation();
+    boolean isLayoutNaturalToLauncher();
+
+    <T> T getPrimaryValue(T x, T y);
+    <T> T getSecondaryValue(T x, T y);
+    void setPrimaryScale(View view, float scale);
+    void setSecondaryScale(View view, float scale);
+    float getStart(RectF rect);
+    float getEnd(RectF rect);
+    int getClearAllSidePadding(View view, boolean isRtl);
+    int getSecondaryDimension(View view);
+    FloatProperty<View> getPrimaryViewTranslate();
+    FloatProperty<View> getSecondaryViewTranslate();
+    int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
+            DeviceProfile deviceProfile);
+    Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
+            FloatProperty secondary, DeviceProfile deviceProfile);
+    int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
+    List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
+    /**
+     * @param placeholderHeight height of placeholder view in portrait, width in landscape
+     */
+    void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
+            DeviceProfile dp, @StagePosition int stagePosition, Rect out);
+
+    /**
+     * Centers an icon in the split staging area, accounting for insets.
+     * @param out The icon that needs to be centered.
+     * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
+     *                        offscreen).
+     * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
+     *                        offscreen).
+     * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
+     * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
+     * @param drawableWidth The icon's drawable (final) width.
+     * @param drawableHeight The icon's drawable (final) height.
+     * @param dp The device profile, used to report rotation and hardware insets.
+     * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
+     */
+    void updateSplitIconParams(View out, float onScreenRectCenterX,
+            float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
+            int drawableWidth, int drawableHeight, DeviceProfile dp,
+            @StagePosition int stagePosition);
+
+    /**
+     * Sets positioning and rotation for a SplitInstructionsView.
+     * @param out The SplitInstructionsView that needs to be positioned.
+     * @param dp The device profile, used to report rotation and device type.
+     * @param splitInstructionsHeight The SplitInstructionView's height.
+     * @param splitInstructionsWidth  The SplitInstructionView's width.
+     */
+    void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
+            int splitInstructionsWidth);
+
+    /**
+     * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
+     * @param stagePosition the split position option (top/left, bottom/right) of the first
+     *                           task selected for entering split
+     * @param out1 the bounds for where the first selected app will be
+     * @param out2 the bounds for where the second selected app will be, complimentary to
+     *             {@param out1} based on {@param initialSplitOption}
+     */
+    void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
+            @StagePosition int stagePosition, Rect out1, Rect out2);
+
+    int getDefaultSplitPosition(DeviceProfile deviceProfile);
+
+    /**
+     * @param outRect This is expected to be the rect that has the dimensions for a non-split,
+     *                fullscreen task in overview. This will directly be modified.
+     * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
+     *                           outRect for
+     */
+    void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
+            @SplitConfigurationOptions.StagePosition int desiredStagePosition);
+
+    void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
+            int parentWidth, int parentHeight,
+            SplitBounds splitBoundsConfig, DeviceProfile dp, boolean isRtl);
+
+    // Overview TaskMenuView methods
+    void setTaskIconParams(FrameLayout.LayoutParams iconParams,
+            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
+
+    void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
+            FrameLayout.LayoutParams iconMenuParams,
+            int iconMenuMargin, int thumbnailTopMargin);
+    void setSplitIconParams(View primaryIconView, View secondaryIconView,
+            int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
+            int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
+            DeviceProfile deviceProfile, SplitBounds splitConfig);
+
+    /*
+     * The following two methods try to center the TaskMenuView in landscape by finding the center
+     * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
+     * taskMenu width is the same size as the thumbnail width (what got set below in
+     * getTaskMenuWidth()), so we directly use that in the calculations.
+     */
+    float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
+            float taskInsetMargin, View taskViewIcon);
+    float getTaskMenuY(float y, View thumbnailView, int stagePosition,
+            View taskMenuView, float taskInsetMargin, View taskViewIcon);
+    int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
+            @StagePosition int stagePosition);
+    /**
+     * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
+     * inside task menu view.
+     */
+    void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
+            LinearLayout taskMenuLayout, int dividerSpacing,
+            ShapeDrawable dividerDrawable);
+    /**
+     * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
+     * views inside task menu view.
+     */
+    void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
+            LinearLayout viewGroup, DeviceProfile deviceProfile);
+
+    /**
+     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+     * TaskView.
+     * @return A Pair of Floats representing the proper x and y translations.
+     */
+    Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
+            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
+            View[] thumbnailViews, int desiredTaskId, View banner);
+
+    // The following are only used by TaskViewTouchHandler.
+    /** @return Either VERTICAL or HORIZONTAL. */
+    SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
+    /** @return Given {@link #getUpDownSwipeDirection()}, whether POSITIVE or NEGATIVE is up. */
+    int getUpDirection(boolean isRtl);
+    /** @return Whether the displacement is going towards the top of the screen. */
+    boolean isGoingUp(float displacement, boolean isRtl);
+    /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
+    int getTaskDragDisplacementFactor(boolean isRtl);
+
+    /**
+     * Maps the velocity from the coordinate plane of the foreground app to that
+     * of Launcher's (which now will always be portrait)
+     */
+    void adjustFloatingIconStartVelocity(PointF velocity);
+
+    /**
+     * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
+     * @param outStartRect The start rect that will directly be modified
+     */
+    void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile);
+
+    /**
+     * Determine the target translation for animating the FloatingTaskView out. This value could
+     * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
+     * docked.
+     *
+     * @param floatingTask The FloatingTaskView.
+     * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
+     * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
+     * @param dp The device profile.
+     * @return A float. When an animation translates the FloatingTaskView to this position, it will
+     * appear to tuck away off the edge of the screen.
+     */
+    float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
+            @StagePosition int stagePosition, DeviceProfile dp);
+
+    /**
+     * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+     * either x or y), depending on how the view is oriented.
+     *
+     * @param floatingTask The FloatingTaskView to be translated.
+     * @param translation The target translation value.
+     * @param dp The current device profile.
+     */
+    void setFloatingTaskPrimaryTranslation(View floatingTask, float translation, DeviceProfile dp);
+
+    /**
+     * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+     * either x or y), depending on how the view is oriented.
+     *
+     * @param floatingTask The FloatingTaskView in question.
+     * @param dp The current device profile.
+     * @return The current translation value.
+     */
+    Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp);
+}
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java
similarity index 95%
rename from src/com/android/launcher3/touch/SeascapePagedViewHandler.java
rename to quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java
index 7077ad9..7e53cf1 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.touch;
+package com.android.quickstep.orientation;
 
 import static android.view.Gravity.BOTTOM;
 import static android.view.Gravity.CENTER_VERTICAL;
@@ -42,10 +42,12 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.views.IconAppChipView;
 
 import java.util.Collections;
 import java.util.List;
@@ -234,9 +236,9 @@
     }
 
     @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
+    public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
             FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
-        boolean isRtl = iconAppChipMenuView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        boolean isRtl = iconAppChipView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         iconMenuParams.gravity = (isRtl ? TOP : BOTTOM) | (isRtl ? END : START);
         iconMenuParams.setMarginStart(0);
         iconMenuParams.topMargin = isRtl ? iconMenuMargin : 0;
@@ -244,12 +246,12 @@
         iconMenuParams.setMarginEnd(isRtl ? thumbnailTopMargin : 0);
 
         // Use half menu height to place the pivot within the X/Y center of icon in the menu.
-        float iconCenter = iconAppChipMenuView.getHeight() / 2f;
-        iconAppChipMenuView.setPivotX(isRtl ? iconMenuParams.width / 2f : iconCenter);
-        iconAppChipMenuView.setPivotY(
+        float iconCenter = iconAppChipView.getHeight() / 2f;
+        iconAppChipView.setPivotX(isRtl ? iconMenuParams.width / 2f : iconCenter);
+        iconAppChipView.setPivotY(
                 isRtl ? iconMenuParams.width / 2f : iconCenter - iconMenuMargin);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
+        iconAppChipView.setTranslationY(0);
+        iconAppChipView.setRotation(getDegreesRotated());
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index cb35ec8..bc8b571 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -43,7 +43,7 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.AllAppsSwipeController;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.RecentsView;
 
 /**
@@ -200,7 +200,7 @@
     public static <SCALE, TRANSLATION> PendingAnimation createRecentsResistanceAnim(
             RecentsParams<SCALE, TRANSLATION> params) {
         Rect startRect = new Rect();
-        PagedOrientationHandler orientationHandler = params.recentsOrientedState
+        RecentsPagedOrientationHandler orientationHandler = params.recentsOrientedState
                 .getOrientationHandler();
         params.recentsOrientedState.getActivityInterface()
                 .calculateTaskSize(params.context, params.dp, startRect, orientationHandler);
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 0f3c029..839320e 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -27,6 +27,7 @@
 import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
+import android.util.Log;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -58,6 +59,8 @@
  * ratio.
  */
 public class AppPairsController {
+    private static final String TAG = "AppPairsController";
+
     // Used for encoding and decoding the "rank" attribute
     private static final int BITMASK_SIZE = 16;
     private static final int BITMASK_FOR_SNAP_POSITION = (1 << BITMASK_SIZE) - 1;
@@ -89,13 +92,23 @@
 
         @PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
         if (!isPersistentSnapPosition(snapPosition)) {
-            throw new RuntimeException("tried to save an app pair with illegal snapPosition");
+            // if we received an illegal snap position, log an error and do not create the app pair.
+            Log.wtf(TAG, "tried to save an app pair with illegal snapPosition " + snapPosition);
+            return;
         }
 
         app1.rank = encodeRank(SPLIT_POSITION_TOP_OR_LEFT, snapPosition);
         app2.rank = encodeRank(SPLIT_POSITION_BOTTOM_OR_RIGHT, snapPosition);
         FolderInfo newAppPair = FolderInfo.createAppPair(app1, app2);
 
+        if (newAppPair.contents.size() != 2) {
+            // if app pair doesn't have exactly 2 members, log an error and do not create the app
+            // pair.
+            Log.wtf(TAG,
+                    "tried to save an app pair with " + newAppPair.contents.size() + " members");
+            return;
+        }
+
         IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
         MODEL_EXECUTOR.execute(() -> {
             newAppPair.contents.forEach(member -> {
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 79656c2..ec1eeb1 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -21,10 +21,10 @@
 import android.view.ViewGroup;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 
 public class LayoutUtils {
 
@@ -40,7 +40,7 @@
     }
 
     public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         // Track the bottom of the window.
         Rect taskSize = new Rect();
         LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index f6ad692..cba628b 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -53,6 +53,7 @@
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 
 import java.lang.annotation.Retention;
 import java.util.function.IntConsumer;
@@ -75,7 +76,8 @@
     @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
     public @interface SurfaceRotation {}
 
-    private PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+    private RecentsPagedOrientationHandler mOrientationHandler =
+            RecentsPagedOrientationHandler.PORTRAIT;
 
     private @SurfaceRotation int mTouchRotation = ROTATION_0;
     private @SurfaceRotation int mDisplayRotation = ROTATION_0;
@@ -225,13 +227,13 @@
     private boolean updateHandler() {
         mRecentsActivityRotation = inferRecentsActivityRotation(mDisplayRotation);
         if (mRecentsActivityRotation == mTouchRotation || isRecentsActivityRotationAllowed()) {
-            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+            mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT;
         } else if (mTouchRotation == ROTATION_90) {
-            mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
+            mOrientationHandler = RecentsPagedOrientationHandler.LANDSCAPE;
         } else if (mTouchRotation == ROTATION_270) {
-            mOrientationHandler = PagedOrientationHandler.SEASCAPE;
+            mOrientationHandler = RecentsPagedOrientationHandler.SEASCAPE;
         } else {
-            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+            mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT;
         }
         if (DEBUG) {
             Log.d(TAG, "current RecentsOrientedState: " + this);
@@ -413,7 +415,7 @@
         return scale;
     }
 
-    public PagedOrientationHandler getOrientationHandler() {
+    public RecentsPagedOrientationHandler getOrientationHandler() {
         return mOrientationHandler;
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index fba847f..32ef904 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -25,7 +25,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 
 public class ClearAllButton extends Button {
 
@@ -81,7 +81,8 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                getRecentsView().getPagedOrientationHandler();
         mSidePadding = orientationHandler.getClearAllSidePadding(getRecentsView(), mIsRtl);
     }
 
@@ -131,7 +132,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
         if (orientationSize == 0) {
             return;
@@ -219,7 +221,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         orientationHandler.getPrimaryViewTranslate().set(this,
                 orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
                         + mNormalTranslationPrimary + getFullscreenTrans(
@@ -232,7 +235,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         orientationHandler.getSecondaryViewTranslate().set(this,
                 orientationHandler.getSecondaryValue(0f, getOriginalTranslationY()));
     }
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 937a728..840382d 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -50,8 +50,8 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.lang.annotation.Retention;
@@ -321,7 +321,7 @@
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
                 mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
-        PagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
         Pair<Float, Float> translations = orientationHandler
                 .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
                         mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index efc0a35..12a073f 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -43,9 +43,9 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimUtils;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.SplitAnimationTimings;
@@ -95,7 +95,7 @@
     private final StatefulActivity mActivity;
     private final boolean mIsRtl;
     private final FullscreenDrawParams mFullscreenParams;
-    private PagedOrientationHandler mOrientationHandler;
+    private RecentsPagedOrientationHandler mOrientationHandler;
     @SplitConfigurationOptions.StagePosition
     private int mStagePosition;
     private final Rect mTmpRect = new Rect();
@@ -220,7 +220,7 @@
         mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIconView(), childScaleY);
     }
 
-    public void updateOrientationHandler(PagedOrientationHandler orientationHandler) {
+    public void updateOrientationHandler(RecentsPagedOrientationHandler orientationHandler) {
         mOrientationHandler = orientationHandler;
         mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
     }
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
index ee09c4d..d2b0540 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -39,9 +39,9 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.RecentsOrientedState;
 
 /**
@@ -211,7 +211,8 @@
 
     @Override
     public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
-        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                orientationState.getOrientationHandler();
         boolean isRtl = isLayoutRtl();
         DeviceProfile deviceProfile =
                 ActivityContext.lookupContext(getContext()).getDeviceProfile();
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index a4bda7f..042f581 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -30,8 +30,8 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.RecentsOrientedState;
 
 /**
@@ -173,7 +173,8 @@
 
     @Override
     public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
-        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                orientationState.getOrientationHandler();
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         DeviceProfile deviceProfile =
                 ActivityContext.lookupContext(getContext()).getDeviceProfile();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 6b3484d..66d651e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -156,7 +156,6 @@
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.OverScroll;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -187,6 +186,7 @@
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.ViewUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AnimUtils;
@@ -788,7 +788,8 @@
         mDesktopTaskViewPool = new ViewPool<>(context, this, R.layout.task_desktop,
                 5 /* max size */, 1 /* initial size */);
 
-        mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
+        setOrientationHandler(mOrientationState.getOrientationHandler());
+        mIsRtl = getPagedOrientationHandler().getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
         mSplitPlaceholderSize = getResources().getDimensionPixelSize(
                 R.dimen.split_placeholder_size);
@@ -812,7 +813,6 @@
                 .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
         setWillNotDraw(false);
         updateEmptyMessage();
-        mOrientationHandler = mOrientationState.getOrientationHandler();
 
         mTaskOverlayFactory = Overrides.getObject(
                 TaskOverlayFactory.class,
@@ -918,9 +918,9 @@
         if (mAllowOverScroll && (!mEdgeGlowRight.isFinished() || !mEdgeGlowLeft.isFinished())) {
             final int restoreCount = canvas.save();
 
-            int primarySize = mOrientationHandler.getPrimaryValue(getWidth(), getHeight());
+            int primarySize = getPagedOrientationHandler().getPrimaryValue(getWidth(), getHeight());
             int scroll = OverScroll.dampedScroll(getUndampedOverScrollShift(), primarySize);
-            mOrientationHandler.setPrimary(canvas, CANVAS_TRANSLATE, scroll);
+            getPagedOrientationHandler().setPrimary(canvas, CANVAS_TRANSLATE, scroll);
 
             if (mOverScrollShift != scroll) {
                 mOverScrollShift = scroll;
@@ -944,8 +944,8 @@
     private float getUndampedOverScrollShift() {
         final int width = getWidth();
         final int height = getHeight();
-        int primarySize = mOrientationHandler.getPrimaryValue(width, height);
-        int secondarySize = mOrientationHandler.getSecondaryValue(width, height);
+        int primarySize = getPagedOrientationHandler().getPrimaryValue(width, height);
+        int secondarySize = getPagedOrientationHandler().getSecondaryValue(width, height);
 
         float effectiveShift = 0;
         if (!mEdgeGlowLeft.isFinished()) {
@@ -1270,8 +1270,8 @@
 
     public boolean isTaskViewVisible(TaskView tv) {
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int screenEnd = screenStart + getPagedOrientationHandler().getMeasuredSize(this);
             return isTaskViewWithinBounds(tv, screenStart, screenEnd);
         } else {
             // For now, just check if it's the active task or an adjacent task
@@ -1281,8 +1281,8 @@
 
     public boolean isTaskViewFullyVisible(TaskView tv) {
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int screenEnd = screenStart + getPagedOrientationHandler().getMeasuredSize(this);
             return isTaskViewFullyWithinBounds(tv, screenStart, screenEnd);
         } else {
             // For now, just check if it's the active task
@@ -1307,9 +1307,9 @@
 
     private int getSnapToLastTaskScrollDiff() {
         // Snap to a position where ClearAll is just invisible.
-        int screenStart = mOrientationHandler.getPrimaryScroll(this);
+        int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
         int clearAllScroll = getScrollForPage(indexOfChild(mClearAllButton));
-        int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
+        int clearAllWidth = getPagedOrientationHandler().getPrimarySize(mClearAllButton);
         int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
         return screenStart - lastTaskScroll;
     }
@@ -1320,20 +1320,20 @@
     }
 
     private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
-        int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsGrid());
-        int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                showAsFullscreen()));
+        int taskStart = getPagedOrientationHandler().getChildStart(tv)
+                + (int) tv.getOffsetAdjustment(showAsGrid());
+        int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(tv)
+                * tv.getSizeAdjustment(showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
         return (taskStart >= start && taskStart <= end) || (taskEnd >= start
                 && taskEnd <= end);
     }
 
     private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
-        int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsGrid());
-        int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                showAsFullscreen()));
+        int taskStart = getPagedOrientationHandler().getChildStart(tv)
+                + (int) tv.getOffsetAdjustment(showAsGrid());
+        int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(tv)
+                * tv.getSizeAdjustment(showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
         return taskStart >= start && taskEnd <= end;
     }
@@ -1628,7 +1628,7 @@
             return;
         }
 
-        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
         int currentPageScroll = getScrollForPage(mCurrentPage);
         mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
 
@@ -2021,20 +2021,20 @@
 
     private void updateOrientationHandler(boolean forceRecreateDragLayerControllers) {
         // Handle orientation changes.
-        PagedOrientationHandler oldOrientationHandler = mOrientationHandler;
-        mOrientationHandler = mOrientationState.getOrientationHandler();
+        RecentsPagedOrientationHandler oldOrientationHandler = getPagedOrientationHandler();
+        setOrientationHandler(mOrientationState.getOrientationHandler());
 
-        mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
+        mIsRtl = getPagedOrientationHandler().getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl
                 ? View.LAYOUT_DIRECTION_RTL
                 : View.LAYOUT_DIRECTION_LTR);
         mClearAllButton.setLayoutDirection(mIsRtl
                 ? View.LAYOUT_DIRECTION_LTR
                 : View.LAYOUT_DIRECTION_RTL);
-        mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
+        mClearAllButton.setRotation(getPagedOrientationHandler().getDegreesRotated());
 
         if (forceRecreateDragLayerControllers
-                || !mOrientationHandler.equals(oldOrientationHandler)) {
+                || !getPagedOrientationHandler().equals(oldOrientationHandler)) {
             // Changed orientations, update controllers so they intercept accordingly.
             mActivity.getDragLayer().recreateControllers();
             onOrientationChanged();
@@ -2081,7 +2081,7 @@
         mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(), mActivity,
                 mLastComputedGridSize);
         mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
-                mLastComputedGridTaskSize, mOrientationHandler);
+                mLastComputedGridTaskSize, getPagedOrientationHandler());
         if (isDesktopModeSupported()) {
             mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
                     mLastComputedDesktopTaskSize);
@@ -2136,7 +2136,7 @@
 
     public void getTaskSize(Rect outRect) {
         mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
-                mOrientationHandler);
+                getPagedOrientationHandler());
         mLastComputedTaskSize.set(outRect);
     }
 
@@ -2159,7 +2159,7 @@
 
     private Rect getTaskBounds(TaskView taskView) {
         int selectedPage = indexOfChild(taskView);
-        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
         int selectedPageScroll = getScrollForPage(selectedPage);
         boolean isTopRow = taskView != null && mTopRowIdSet.contains(taskView.getTaskViewId());
         Rect outRect = new Rect(mLastComputedTaskSize);
@@ -2187,7 +2187,7 @@
     /** Gets the task size for modal state. */
     public void getModalTaskSize(Rect outRect) {
         mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
-                mOrientationHandler);
+                getPagedOrientationHandler());
     }
 
     @Override
@@ -2243,7 +2243,7 @@
         if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
             return;
         }
-        int scroll = mOrientationHandler.getPrimaryScroll(this);
+        int scroll = getPagedOrientationHandler().getPrimaryScroll(this);
         mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
 
         // Clear all button alpha was set by the previous line.
@@ -2293,8 +2293,8 @@
         int visibleStart = 0;
         int visibleEnd = 0;
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int pageOrientedSize = mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int pageOrientedSize = getPagedOrientationHandler().getMeasuredSize(this);
             // For GRID_ONLY_OVERVIEW, use +/- 1 task column as visible area for preloading
             // adjacent thumbnails, otherwise use +/-50% screen width
             int extraWidth = enableGridOnlyOverview() ? getLastComputedTaskSize().width()
@@ -3232,8 +3232,8 @@
                 clampToProgress(isOnGridBottomRow(taskView) ? ACCELERATE : FINAL_FRAME, 0, 0.5f));
         FloatProperty<TaskView> secondaryViewTranslate =
                 taskView.getSecondaryDismissTranslationProperty();
-        int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
-        int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
+        int secondaryTaskDimension = getPagedOrientationHandler().getSecondaryDimension(taskView);
+        int verticalFactor = getPagedOrientationHandler().getSecondaryTranslationDirectionFactor();
 
         ResourceProvider rp = DynamicResource.provider(mActivity);
         SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
@@ -3248,7 +3248,7 @@
                 if (!mEnableDrawingLiveTile) return;
                 runActionOnRemoteHandles(
                         remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
-                                .taskSecondaryTranslation.value = mOrientationHandler
+                                .taskSecondaryTranslation.value = getPagedOrientationHandler()
                                 .getSecondaryValue(taskView.getTranslationX(),
                                         taskView.getTranslationY()
                                 ));
@@ -3262,7 +3262,7 @@
      * and then animates it into the split position that was desired
      */
     private void createInitialSplitSelectAnimation(PendingAnimation anim) {
-        mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
+        getPagedOrientationHandler().getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
                 mSplitPlaceholderInset, mActivity.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
         SplitAnimationTimings timings =
@@ -3491,7 +3491,7 @@
                 // beyond that, we'll need to snap to last task instead.
                 TaskView lastTask = getLastGridTaskView();
                 if (lastTask != null) {
-                    int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+                    int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
                     int lastTaskScroll = getScrollForPage(indexOfChild(lastTask));
                     if ((mIsRtl && primaryScroll < lastTaskScroll)
                             || (!mIsRtl && primaryScroll > lastTaskScroll)) {
@@ -3597,7 +3597,7 @@
                 if (scrollDiff != 0) {
                     FloatProperty translationProperty = child instanceof TaskView
                             ? ((TaskView) child).getPrimaryDismissTranslationProperty()
-                            : mOrientationHandler.getPrimaryViewTranslate();
+                            : getPagedOrientationHandler().getPrimaryViewTranslate();
 
                     float additionalDismissDuration =
                             ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
@@ -3633,7 +3633,7 @@
                                     remoteTargetHandle ->
                                             remoteTargetHandle.getTaskViewSimulator()
                                                     .taskPrimaryTranslation.value =
-                                                    mOrientationHandler.getPrimaryValue(
+                                                    getPagedOrientationHandler().getPrimaryValue(
                                                             child.getTranslationX(),
                                                             child.getTranslationY()
                                                     ));
@@ -3709,7 +3709,7 @@
                     if (isStagingFocusedTask) {
                         // Moves less if focused task is not in scroll position.
                         int focusedTaskScroll = getScrollForPage(dismissedIndex);
-                        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+                        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
                         int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
                         primaryTranslation +=
                                 mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
@@ -3837,7 +3837,7 @@
                             }
 
                             if (calculateScrollDiff) {
-                                int primaryScroll = mOrientationHandler.getPrimaryScroll(
+                                int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(
                                         RecentsView.this);
                                 int currentPageScroll = getScrollForPage(mCurrentPage);
                                 mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
@@ -3878,9 +3878,9 @@
                                 TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
 
                                 boolean shouldRebalance;
-                                int screenStart = mOrientationHandler.getPrimaryScroll(
+                                int screenStart = getPagedOrientationHandler().getPrimaryScroll(
                                         RecentsView.this);
-                                int taskStart = mOrientationHandler.getChildStart(taskView)
+                                int taskStart = getPagedOrientationHandler().getChildStart(taskView)
                                         + (int) taskView.getOffsetAdjustment(/*gridEnabled=*/ true);
 
                                 // Rebalance only if there is a maximum gap between the task and the
@@ -3889,10 +3889,11 @@
                                 if (mIsRtl) {
                                     shouldRebalance = taskStart <= screenStart + mPageSpacing;
                                 } else {
-                                    int screenEnd =
-                                            screenStart + mOrientationHandler.getMeasuredSize(
-                                                    RecentsView.this);
-                                    int taskSize = (int) (mOrientationHandler.getMeasuredSize(
+                                    int screenEnd = screenStart
+                                            + getPagedOrientationHandler().getMeasuredSize(
+                                            RecentsView.this);
+                                    int taskSize = (int) (
+                                            getPagedOrientationHandler().getMeasuredSize(
                                             taskView) * taskView
                                             .getSizeAdjustment(/*fullscreenEnabled=*/false));
                                     int taskEnd = taskStart + taskSize;
@@ -4287,8 +4288,8 @@
         return mOrientationState;
     }
 
-    public PagedOrientationHandler getPagedOrientationHandler() {
-        return mOrientationHandler;
+    public RecentsPagedOrientationHandler getPagedOrientationHandler() {
+        return (RecentsPagedOrientationHandler) super.getPagedOrientationHandler();
     }
 
     @Nullable
@@ -4466,7 +4467,7 @@
             View child = getChildAt(i);
             FloatProperty translationPropertyX = child instanceof TaskView
                     ? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
-                    : mOrientationHandler.getPrimaryViewTranslate();
+                    : getPagedOrientationHandler().getPrimaryViewTranslate();
             translationPropertyX.set(child, totalTranslationX);
             if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
                 runActionOnRemoteHandles(
@@ -4504,8 +4505,8 @@
                     mIsRtl ? outRect.right : outRect.left, outRect.top);
             mTempMatrix.mapRect(outRect);
         }
-        outRect.offset(mOrientationHandler.getPrimaryValue(-midPointScroll, 0),
-                mOrientationHandler.getSecondaryValue(-midPointScroll, 0));
+        outRect.offset(getPagedOrientationHandler().getPrimaryValue(-midPointScroll, 0),
+                getPagedOrientationHandler().getSecondaryValue(-midPointScroll, 0));
     }
 
     /**
@@ -4530,14 +4531,15 @@
             // to reach offscreen. Offset the task position to the task's starting point, and offset
             // by current page's scroll diff.
             int midpointScroll = getScrollForPage(midpointIndex)
-                    + mOrientationHandler.getPrimaryScroll(this) - getScrollForPage(mCurrentPage);
+                    + getPagedOrientationHandler().getPrimaryScroll(this)
+                    - getScrollForPage(mCurrentPage);
 
             getPersistentChildPosition(midpointIndex, midpointScroll, taskPosition);
-            float midpointStart = mOrientationHandler.getStart(taskPosition);
+            float midpointStart = getPagedOrientationHandler().getStart(taskPosition);
 
             getPersistentChildPosition(childIndex, midpointScroll, taskPosition);
             // Assume child does not overlap with midPointChild.
-            isStartShift = mOrientationHandler.getStart(taskPosition) < midpointStart;
+            isStartShift = getPagedOrientationHandler().getStart(taskPosition) < midpointStart;
         } else {
             // Position the task at scroll position.
             getPersistentChildPosition(childIndex, getScrollForPage(childIndex), taskPosition);
@@ -4551,27 +4553,29 @@
         // desired position, and adjust the computed distance accordingly.
         float distanceToOffscreen;
         if (isStartShift) {
-            float desiredStart = -mOrientationHandler.getPrimarySize(taskPosition);
-            distanceToOffscreen = -mOrientationHandler.getEnd(taskPosition);
+            float desiredStart = -getPagedOrientationHandler().getPrimarySize(taskPosition);
+            distanceToOffscreen = -getPagedOrientationHandler().getEnd(taskPosition);
             if (mLastComputedTaskStartPushOutDistance == null) {
                 taskPosition.offsetTo(
-                        mOrientationHandler.getPrimaryValue(desiredStart, 0f),
-                        mOrientationHandler.getSecondaryValue(desiredStart, 0f));
+                        getPagedOrientationHandler().getPrimaryValue(desiredStart, 0f),
+                        getPagedOrientationHandler().getSecondaryValue(desiredStart, 0f));
                 getMatrix().mapRect(taskPosition);
-                mLastComputedTaskStartPushOutDistance = mOrientationHandler.getEnd(taskPosition)
-                        / mOrientationHandler.getPrimaryScale(this);
+                mLastComputedTaskStartPushOutDistance = getPagedOrientationHandler().getEnd(
+                        taskPosition) / getPagedOrientationHandler().getPrimaryScale(this);
             }
             distanceToOffscreen -= mLastComputedTaskStartPushOutDistance;
         } else {
-            float desiredStart = mOrientationHandler.getPrimarySize(this);
-            distanceToOffscreen = desiredStart - mOrientationHandler.getStart(taskPosition);
+            float desiredStart = getPagedOrientationHandler().getPrimarySize(this);
+            distanceToOffscreen = desiredStart - getPagedOrientationHandler().getStart(
+                    taskPosition);
             if (mLastComputedTaskEndPushOutDistance == null) {
                 taskPosition.offsetTo(
-                        mOrientationHandler.getPrimaryValue(desiredStart, 0f),
-                        mOrientationHandler.getSecondaryValue(desiredStart, 0f));
+                        getPagedOrientationHandler().getPrimaryValue(desiredStart, 0f),
+                        getPagedOrientationHandler().getSecondaryValue(desiredStart, 0f));
                 getMatrix().mapRect(taskPosition);
-                mLastComputedTaskEndPushOutDistance = (mOrientationHandler.getStart(taskPosition)
-                        - desiredStart) / mOrientationHandler.getPrimaryScale(this);
+                mLastComputedTaskEndPushOutDistance = (getPagedOrientationHandler().getStart(
+                        taskPosition) - desiredStart)
+                        / getPagedOrientationHandler().getPrimaryScale(this);
             }
             distanceToOffscreen -= mLastComputedTaskEndPushOutDistance;
         }
@@ -4660,7 +4664,7 @@
      * of split invocation as such.
      */
     public void initiateSplitSelect(TaskView taskView) {
-        int defaultSplitPosition = mOrientationHandler
+        int defaultSplitPosition = getPagedOrientationHandler()
                 .getDefaultSplitPosition(mActivity.getDeviceProfile());
         initiateSplitSelect(taskView, defaultSplitPosition, LAUNCHER_OVERVIEW_ACTIONS_SPLIT);
     }
@@ -4803,7 +4807,7 @@
 
         int halfDividerSize = getResources()
                 .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
-        mOrientationHandler.getFinalSplitPlaceholderBounds(halfDividerSize,
+        getPagedOrientationHandler().getFinalSplitPlaceholderBounds(halfDividerSize,
                 mActivity.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds,
                 secondTaskEndingBounds);
@@ -4920,7 +4924,7 @@
      */
     public float getSplitSelectTranslation() {
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
         int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
         int splitPlaceholderSize =
                 mActivity.getResources().getDimensionPixelSize(R.dimen.split_placeholder_size);
@@ -4945,16 +4949,16 @@
     }
 
     protected void onRotateInSplitSelectionState() {
-        mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
+        getPagedOrientationHandler().getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
                 mSplitPlaceholderInset, mActivity.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
         mTempRectF.set(mTempRect);
         FloatingTaskView firstFloatingTaskView =
                 mSplitSelectStateController.getFirstFloatingTaskView();
-        firstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
+        firstFloatingTaskView.updateOrientationHandler(getPagedOrientationHandler());
         firstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
 
-        PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
         Pair<FloatProperty, FloatProperty> taskViewsFloat =
                 orientationHandler.getSplitSelectTaskOffset(
                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
@@ -5059,7 +5063,7 @@
             float displacementX = tv.getWidth() * (toScale - 1f);
             float primaryTranslation = mIsRtl ? -displacementX : displacementX;
             anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
-                    mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation));
+                    getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation));
             int runningTaskIndex = getRunningTaskIndex();
             if (runningTaskIndex != -1 && runningTaskIndex != taskIndex
                     && getRemoteTargetHandles() != null) {
@@ -5075,7 +5079,7 @@
             if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
                 PropertyValuesHolder[] properties = new PropertyValuesHolder[3];
                 properties[0] = PropertyValuesHolder.ofFloat(
-                        mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation);
+                        getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation);
                 properties[1] = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
                 properties[2] = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
 
@@ -5495,8 +5499,8 @@
         // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
         // TaskViews. This must be called after laying out ClearAllButton.
         if (layoutChildren) {
-            int clearAllWidthDiff = mOrientationHandler.getPrimaryValue(mTaskWidth, mTaskHeight)
-                    - mOrientationHandler.getPrimarySize(mClearAllButton);
+            int clearAllWidthDiff = getPagedOrientationHandler().getPrimaryValue(mTaskWidth,
+                    mTaskHeight) - getPagedOrientationHandler().getPrimarySize(mClearAllButton);
             mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
         }
 
@@ -5504,7 +5508,7 @@
 
         int clearAllIndex = indexOfChild(mClearAllButton);
         int clearAllScroll = 0;
-        int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
+        int clearAllWidth = getPagedOrientationHandler().getPrimarySize(mClearAllButton);
         if (clearAllIndex != -1 && clearAllIndex < outPageScrolls.length) {
             float scrollDiff = mClearAllButton.getScrollAdjustment(showAsFullscreen, showAsGrid);
             clearAllScroll = newPageScrolls[clearAllIndex] + (int) scrollDiff;
@@ -5613,7 +5617,7 @@
             overScrollShift = (int) Utilities.mapRange(mAdjacentPageHorizontalOffset,
                     overScrollShift, getUndampedOverScrollShift());
         }
-        return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this)
+        return getScrollForPage(pageIndex) - getPagedOrientationHandler().getPrimaryScroll(this)
                 + overScrollShift + getOffsetFromScrollPosition(pageIndex);
     }
 
@@ -5682,7 +5686,7 @@
     public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
         float degreesRotated;
         if (navbarRotation == 0) {
-            degreesRotated = mOrientationHandler.getDegreesRotated();
+            degreesRotated = getPagedOrientationHandler().getDegreesRotated();
         } else {
             degreesRotated = -navbarRotation;
         }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 77033b2..d779276 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -48,10 +48,10 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.TaskCornerRadius;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
 
@@ -215,7 +215,8 @@
 
     private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) {
         RecentsView recentsView = mActivity.getOverviewPanel();
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
 
         // Get Position
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index dff0580..077247b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -51,11 +51,11 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -513,7 +513,7 @@
             return false;
         }
 
-        if (recents.getPagedOrientationHandler() == PagedOrientationHandler.PORTRAIT) {
+        if (recents.getPagedOrientationHandler() == RecentsPagedOrientationHandler.PORTRAIT) {
             int currentRotation = recents.getPagedViewOrientedState().getRecentsActivityRotation();
             return (currentRotation - mThumbnailData.rotation) % 2 != 0;
         } else {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f2c0286..11e721e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -87,7 +87,6 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
@@ -104,6 +103,7 @@
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.util.CancellableTask;
@@ -116,6 +116,8 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 
+import kotlin.Unit;
+
 import java.lang.annotation.Retention;
 import java.util.Arrays;
 import java.util.Collections;
@@ -124,8 +126,6 @@
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 
-import kotlin.Unit;
-
 /**
  * A task in the Recents view.
  */
@@ -1660,7 +1660,7 @@
         return (RecentsView) getParent();
     }
 
-    PagedOrientationHandler getPagedOrientationHandler() {
+    RecentsPagedOrientationHandler getPagedOrientationHandler() {
         return getRecentsView().mOrientationState.getOrientationHandler();
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index f355ae7..43dca5c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -118,7 +118,8 @@
     private float mTotalMotion;
     // Used in special cases where the fling checks can be relaxed for an intentional gesture
     private boolean mAllowEasyFling;
-    protected PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+    private PagedOrientationHandler mOrientationHandler =
+            PagedOrientationHandler.DEFAULT;
 
     private final ArrayList<Runnable> mOnPageScrollsInitializedCallbacks = new ArrayList<>();
 
@@ -231,6 +232,14 @@
         return getChildAt(index);
     }
 
+    protected PagedOrientationHandler getPagedOrientationHandler() {
+        return mOrientationHandler;
+    }
+
+    protected void setOrientationHandler(PagedOrientationHandler orientationHandler) {
+        this.mOrientationHandler = orientationHandler;
+    }
+
     /**
      * Updates the scroll of the current page immediately to its final scroll position.  We use this
      * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 930196d..ae2849e 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -1156,13 +1156,15 @@
 
         applyAdapterSideAndBottomPaddings(grid);
 
+        MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
         // Ignore left/right insets on tablet because we are already centered in-screen.
-        if (grid.isPhone) {
-            MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
+        if (grid.isTablet) {
+            mlp.leftMargin = mlp.rightMargin = 0;
+        } else {
             mlp.leftMargin = insets.left;
             mlp.rightMargin = insets.right;
-            setLayoutParams(mlp);
         }
+        setLayoutParams(mlp);
 
         if (!grid.isVerticalBarLayout() || FeatureFlags.enableResponsiveWorkspace()) {
             int topPadding = grid.allAppsPadding.top;
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 1d73441..9b85a65 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -45,6 +46,8 @@
  * member apps are set into these rectangles.
  */
 public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
+    private static final String TAG = "AppPairIcon";
+
     // A view that holds the app pair icon graphic.
     private AppPairIconGraphic mIconGraphic;
     // A view that holds the app pair's title.
@@ -96,8 +99,7 @@
         icon.mAppPairName.setText(appPairInfo.title);
 
         // Set up accessibility
-        icon.setContentDescription(icon.getAccessibilityTitle(
-                appPairInfo.contents.get(0).title, appPairInfo.contents.get(1).title));
+        icon.setContentDescription(icon.getAccessibilityTitle(appPairInfo));
         icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
 
         return icon;
@@ -106,7 +108,14 @@
     /**
      * Returns a formatted accessibility title for app pairs.
      */
-    public String getAccessibilityTitle(CharSequence app1, CharSequence app2) {
+    public String getAccessibilityTitle(FolderInfo appPairInfo) {
+        if (appPairInfo.contents.size() != 2) {
+            Log.wtf(TAG, "AppPair contents not 2, size: " + appPairInfo.contents.size());
+            return "";
+        }
+
+        CharSequence app1 = appPairInfo.contents.get(0).title;
+        CharSequence app2 = appPairInfo.contents.get(1).title;
         return getContext().getString(R.string.app_pair_name_format, app1, app2);
     }
 
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index ce354b6..65c270a 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -93,7 +93,7 @@
     private fun applyIcons(contents: ArrayList<WorkspaceItemInfo>) {
         // App pair should always contain 2 members; if not 2, return to avoid a crash loop
         if (contents.size != 2) {
-            Log.w(TAG, "AppPair contents not 2, size: " + contents.size, Throwable())
+            Log.wtf(TAG, "AppPair contents not 2, size: " + contents.size, Throwable())
             return
         }
 
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index ccb8900..b41f011 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -330,12 +330,15 @@
                             PackageManagerHelper.getLoadingProgress(info),
                             PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
                     applicationInfo.intent = launchIntent;
-                    if (enableSupportForArchiving() && info.getActivityInfo().isArchived) {
+                    if (enableSupportForArchiving()) {
                         // In case an app is archived, the respective item flag corresponding to
                         // archiving should also be applied during package updates
-                        applicationInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
+                        if (info.getActivityInfo().isArchived) {
+                            applicationInfo.runtimeStatusFlags |= FLAG_ARCHIVED;
+                        } else {
+                            applicationInfo.runtimeStatusFlags &= (~FLAG_ARCHIVED);
+                        }
                     }
-
                     mDataChanged = true;
                 }
             }
diff --git a/src/com/android/launcher3/touch/DefaultPagedViewHandler.java b/src/com/android/launcher3/touch/DefaultPagedViewHandler.java
new file mode 100644
index 0000000..272ed10
--- /dev/null
+++ b/src/com/android/launcher3/touch/DefaultPagedViewHandler.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 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.touch;
+
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.Utilities;
+
+public class DefaultPagedViewHandler implements PagedOrientationHandler {
+    @Override
+    public int getPrimaryValue(int x, int y) {
+        return x;
+    }
+
+    @Override
+    public int getSecondaryValue(int x, int y) {
+        return y;
+    }
+
+    @Override
+    public float getPrimaryValue(float x, float y) {
+        return x;
+    }
+
+    @Override
+    public float getSecondaryValue(float x, float y) {
+        return y;
+    }
+
+    @Override
+    public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
+        action.call(target, param, 0);
+    }
+
+    @Override
+    public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
+        action.call(target, param, 0);
+    }
+
+    @Override
+    public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
+        return event.getX(pointerIndex);
+    }
+
+    @Override
+    public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
+        return velocityTracker.getXVelocity(pointerId);
+    }
+
+    @Override
+    public int getMeasuredSize(View view) {
+        return view.getMeasuredWidth();
+    }
+
+    @Override
+    public int getPrimaryScroll(View view) {
+        return view.getScrollX();
+    }
+
+    @Override
+    public float getPrimaryScale(View view) {
+        return view.getScaleX();
+    }
+
+    @Override
+    public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
+        event.setMaxScrollX(maxScroll);
+    }
+
+    @Override
+    public boolean getRecentsRtlSetting(Resources resources) {
+        return !Utilities.isRtl(resources);
+    }
+
+    @Override
+    public int getChildStart(View view) {
+        return view.getLeft();
+    }
+
+    @Override
+    public int getCenterForPage(View view, Rect insets) {
+        return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
+            - insets.bottom - view.getPaddingBottom()) / 2;
+    }
+
+    @Override
+    public int getScrollOffsetStart(View view, Rect insets) {
+        return insets.left + view.getPaddingLeft();
+    }
+
+    @Override
+    public int getScrollOffsetEnd(View view, Rect insets) {
+        return view.getWidth() - view.getPaddingRight() - insets.right;
+    }
+
+    @Override
+    public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
+            boolean layoutChild) {
+        final int childWidth = child.getMeasuredWidth();
+        final int childRight = childStart + childWidth;
+        final int childHeight = child.getMeasuredHeight();
+        final int childTop = pageCenter - childHeight / 2;
+        if (layoutChild) {
+            child.layout(childStart, childTop, childRight, childTop + childHeight);
+        }
+        return new ChildBounds(childWidth, childHeight, childRight, childTop);
+    }
+
+}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 74d88ba..e0c4e3c 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -19,26 +19,11 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.FloatProperty;
-import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-
-import java.util.List;
 
 /**
  * Abstraction layer to separate horizontal and vertical specific implementations
@@ -47,9 +32,7 @@
  */
 public interface PagedOrientationHandler {
 
-    PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
-    PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
-    PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
+    PagedOrientationHandler DEFAULT = new DefaultPagedViewHandler();
 
     interface Int2DAction<T> {
         void call(T target, int x, int y);
@@ -64,39 +47,18 @@
 
     <T> void setPrimary(T target, Int2DAction<T> action, int param);
     <T> void setPrimary(T target, Float2DAction<T> action, float param);
-    <T> void setSecondary(T target, Float2DAction<T> action, float param);
-    <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
     float getPrimaryDirection(MotionEvent event, int pointerIndex);
     float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
     int getMeasuredSize(View view);
-    int getPrimarySize(View view);
-    float getPrimarySize(RectF rect);
-    float getStart(RectF rect);
-    float getEnd(RectF rect);
-    int getClearAllSidePadding(View view, boolean isRtl);
-    int getSecondaryDimension(View view);
-    FloatProperty<View> getPrimaryViewTranslate();
-    FloatProperty<View> getSecondaryViewTranslate();
-
     int getPrimaryScroll(View view);
     float getPrimaryScale(View view);
     int getChildStart(View view);
     int getCenterForPage(View view, Rect insets);
     int getScrollOffsetStart(View view, Rect insets);
     int getScrollOffsetEnd(View view, Rect insets);
-    int getSecondaryTranslationDirectionFactor();
-    int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
-            DeviceProfile deviceProfile);
     ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
     void setMaxScroll(AccessibilityEvent event, int maxScroll);
     boolean getRecentsRtlSetting(Resources resources);
-    float getDegreesRotated();
-    int getRotation();
-    void setPrimaryScale(View view, float scale);
-    void setSecondaryScale(View view, float scale);
-
-    <T> T getPrimaryValue(T x, T y);
-    <T> T getSecondaryValue(T x, T y);
 
     int getPrimaryValue(int x, int y);
     int getSecondaryValue(int x, int y);
@@ -104,174 +66,6 @@
     float getPrimaryValue(float x, float y);
     float getSecondaryValue(float x, float y);
 
-    boolean isLayoutNaturalToLauncher();
-    Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
-            FloatProperty secondary, DeviceProfile deviceProfile);
-    int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
-    List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
-    /**
-     * @param placeholderHeight height of placeholder view in portrait, width in landscape
-     */
-    void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
-            DeviceProfile dp, @StagePosition int stagePosition, Rect out);
-
-    /**
-     * Centers an icon in the split staging area, accounting for insets.
-     * @param out The icon that needs to be centered.
-     * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
-     *                        offscreen).
-     * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
-     *                        offscreen).
-     * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
-     * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
-     * @param drawableWidth The icon's drawable (final) width.
-     * @param drawableHeight The icon's drawable (final) height.
-     * @param dp The device profile, used to report rotation and hardware insets.
-     * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
-     */
-    void updateSplitIconParams(View out, float onScreenRectCenterX,
-            float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
-            int drawableWidth, int drawableHeight, DeviceProfile dp,
-            @StagePosition int stagePosition);
-
-    /**
-     * Sets positioning and rotation for a SplitInstructionsView.
-     * @param out The SplitInstructionsView that needs to be positioned.
-     * @param dp The device profile, used to report rotation and device type.
-     * @param splitInstructionsHeight The SplitInstructionView's height.
-     * @param splitInstructionsWidth  The SplitInstructionView's width.
-     */
-    void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
-            int splitInstructionsWidth);
-
-    /**
-     * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
-     * @param stagePosition the split position option (top/left, bottom/right) of the first
-     *                           task selected for entering split
-     * @param out1 the bounds for where the first selected app will be
-     * @param out2 the bounds for where the second selected app will be, complimentary to
-     *             {@param out1} based on {@param initialSplitOption}
-     */
-    void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
-            @StagePosition int stagePosition, Rect out1, Rect out2);
-
-    int getDefaultSplitPosition(DeviceProfile deviceProfile);
-
-    /**
-     * @param outRect This is expected to be the rect that has the dimensions for a non-split,
-     *                fullscreen task in overview. This will directly be modified.
-     * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
-     *                           outRect for
-     */
-    void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
-            @SplitConfigurationOptions.StagePosition int desiredStagePosition);
-
-    void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
-            int parentWidth, int parentHeight,
-            SplitBounds splitBoundsConfig, DeviceProfile dp, boolean isRtl);
-
-    // Overview TaskMenuView methods
-    void setTaskIconParams(FrameLayout.LayoutParams iconParams,
-            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
-    void setIconAppChipMenuParams(View iconAppChipMenuView, FrameLayout.LayoutParams iconMenuParams,
-            int iconMenuMargin, int thumbnailTopMargin);
-    void setSplitIconParams(View primaryIconView, View secondaryIconView,
-            int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
-            int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
-            DeviceProfile deviceProfile, SplitBounds splitConfig);
-
-    /*
-     * The following two methods try to center the TaskMenuView in landscape by finding the center
-     * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
-     * taskMenu width is the same size as the thumbnail width (what got set below in
-     * getTaskMenuWidth()), so we directly use that in the calculations.
-     */
-    float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
-            float taskInsetMargin, View taskViewIcon);
-    float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin, View taskViewIcon);
-    int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
-            @StagePosition int stagePosition);
-    /**
-     * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
-     * inside task menu view.
-     */
-    void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-            LinearLayout taskMenuLayout, int dividerSpacing,
-            ShapeDrawable dividerDrawable);
-    /**
-     * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
-     * views inside task menu view.
-     */
-    void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
-            LinearLayout viewGroup, DeviceProfile deviceProfile);
-
-    /**
-     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
-     * TaskView.
-     * @return A Pair of Floats representing the proper x and y translations.
-     */
-    Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
-            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
-            View[] thumbnailViews, int desiredTaskId, View banner);
-
-    // The following are only used by TaskViewTouchHandler.
-    /** @return Either VERTICAL or HORIZONTAL. */
-    SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
-    /** @return Given {@link #getUpDownSwipeDirection()}, whether POSITIVE or NEGATIVE is up. */
-    int getUpDirection(boolean isRtl);
-    /** @return Whether the displacement is going towards the top of the screen. */
-    boolean isGoingUp(float displacement, boolean isRtl);
-    /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
-    int getTaskDragDisplacementFactor(boolean isRtl);
-
-    /**
-     * Maps the velocity from the coordinate plane of the foreground app to that
-     * of Launcher's (which now will always be portrait)
-     */
-    void adjustFloatingIconStartVelocity(PointF velocity);
-
-    /**
-     * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
-     * @param outStartRect The start rect that will directly be modified
-     */
-    void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile);
-
-    /**
-     * Determine the target translation for animating the FloatingTaskView out. This value could
-     * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
-     * docked.
-     *
-     * @param floatingTask The FloatingTaskView.
-     * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
-     * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
-     * @param dp The device profile.
-     * @return A float. When an animation translates the FloatingTaskView to this position, it will
-     * appear to tuck away off the edge of the screen.
-     */
-    float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
-            @StagePosition int stagePosition, DeviceProfile dp);
-
-    /**
-     * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
-     * either x or y), depending on how the view is oriented.
-     *
-     * @param floatingTask The FloatingTaskView to be translated.
-     * @param translation The target translation value.
-     * @param dp The current device profile.
-     */
-    void setFloatingTaskPrimaryTranslation(View floatingTask, float translation, DeviceProfile dp);
-
-    /**
-     * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
-     * either x or y), depending on how the view is oriented.
-     *
-     * @param floatingTask The FloatingTaskView in question.
-     * @param dp The current device profile.
-     * @return The current translation value.
-     */
-    Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp);
-
     class ChildBounds {
 
         public final int primaryDimension;
@@ -279,8 +73,8 @@
         public final int childPrimaryEnd;
         public final int childSecondaryEnd;
 
-        ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
-            int childSecondaryEnd) {
+        public ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
+                int childSecondaryEnd) {
             this.primaryDimension = primaryDimension;
             this.secondaryDimension = secondaryDimension;
             this.childPrimaryEnd = childPrimaryEnd;
diff --git a/src/com/android/launcher3/widget/picker/OWNERS b/src/com/android/launcher3/widget/picker/OWNERS
new file mode 100644
index 0000000..6aabbfa
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/OWNERS
@@ -0,0 +1,16 @@
+set noparent
+
+# Bug component: 1481801
+
+# People who can approve changes for submission
+#
+
+# Widget Picker OWNERS
+zakcohen@google.com
+shamalip@google.com
+wvk@google.com
+
+# Launcher OWNERS
+captaincole@google.com
+sunnygoyal@google.com
+
diff --git a/tests/src/com/android/launcher3/widget/picker/OWNERS b/tests/src/com/android/launcher3/widget/picker/OWNERS
new file mode 100644
index 0000000..775b0c7
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/OWNERS
@@ -0,0 +1,18 @@
+set noparent
+
+# Bug component: 1481801
+# People who can approve changes for submission
+#
+
+# Widget Picker OWNERS
+zakcohen@google.com
+shamalip@google.com
+wvk@google.com
+
+# For Tests
+vadimt@google.com
+
+# Launcher OWNERS
+captaincole@google.com
+sunnygoyal@google.com
+