Merging from ub-launcher3-rvc-dev @ build 6595814 am: efdc4e2318 am: 9cb1795a71 am: ad4bd43b8f am: 9269333de9

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/11885879

Change-Id: Ie7d2e841b2d41504e07633f116d80b4e3adde59f
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index ff5bf0d..84dd06a 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -86,6 +86,7 @@
         <receiver
             android:name="com.android.launcher3.InstallShortcutReceiver"
             android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"
+            android:exported="true"
             android:enabled="@bool/enable_install_shortcut_api" >
             <intent-filter>
                 <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
@@ -94,14 +95,16 @@
 
         <!-- Intent received when a session is committed -->
         <receiver
-            android:name="com.android.launcher3.SessionCommitReceiver" >
+            android:name="com.android.launcher3.SessionCommitReceiver"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.content.pm.action.SESSION_COMMITTED" />
             </intent-filter>
         </receiver>
 
         <!-- Intent received used to initialize a restored widget -->
-        <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" >
+        <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_HOST_RESTORED"/>
             </intent-filter>
@@ -117,6 +120,7 @@
             android:name="com.android.launcher3.notification.NotificationListener"
             android:label="@string/notification_dots_service_title"
             android:enabled="@bool/notification_dots_enabled"
+            android:exported="true"
             android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
             <intent-filter>
                 <action android:name="android.service.notification.NotificationListenerService" />
@@ -130,6 +134,7 @@
             android:theme="@style/AppItemActivityTheme"
             android:excludeFromRecents="true"
             android:autoRemoveFromRecents="true"
+            android:exported="true"
             android:label="@string/action_add_to_workspace" >
             <intent-filter>
                 <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
@@ -165,6 +170,7 @@
             android:name="com.android.launcher3.settings.SettingsActivity"
             android:label="@string/settings_button_text"
             android:theme="@style/HomeSettingsTheme"
+            android:exported="true"
             android:autoRemoveFromRecents="true">
             <intent-filter>
                 <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
@@ -187,6 +193,7 @@
             android:name="com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher"
             android:theme="@style/AppTheme"
             android:launchMode="singleTop"
+            android:exported="true"
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index b031ffb..8e01f82 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -53,6 +53,7 @@
             android:resizeableActivity="true"
             android:resumeWhilePausing="true"
             android:taskAffinity=""
+            android:exported="true"
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 527bfc3..078205b 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -53,6 +53,7 @@
             android:resizeableActivity="true"
             android:resumeWhilePausing="true"
             android:taskAffinity="${packageName}.launcher"
+            android:exported="true"
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index b2286f1..7f63a37 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -17,93 +17,87 @@
 ** limitations under the License.
 */
 -->
-<manifest
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="com.android.launcher3" >
 
-    <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
-    <uses-permission android:name="android.permission.VIBRATE" />
-    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     xmlns:tools="http://schemas.android.com/tools"
+     package="com.android.launcher3">
 
-    
-    <application
-        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
-        android:fullBackupOnly="true"
-        android:fullBackupContent="@xml/backupscheme"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/ic_launcher_home"
-        android:label="@string/derived_app_name"
-        android:theme="@style/AppTheme"
-        android:largeHeap="@bool/config_largeHeap"
-        android:restoreAnyVersion="true"
-        android:supportsRtl="true" >
+    <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
+    <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
 
-        <service
-            android:name="com.android.quickstep.TouchInteractionService"
-            android:permission="android.permission.STATUS_BAR_SERVICE"
-            android:directBootAware="true" >
+
+    <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+         android:fullBackupOnly="true"
+         android:fullBackupContent="@xml/backupscheme"
+         android:hardwareAccelerated="true"
+         android:icon="@drawable/ic_launcher_home"
+         android:label="@string/derived_app_name"
+         android:theme="@style/AppTheme"
+         android:largeHeap="@bool/config_largeHeap"
+         android:restoreAnyVersion="true"
+         android:supportsRtl="true">
+
+        <service android:name="com.android.quickstep.TouchInteractionService"
+             android:permission="android.permission.STATUS_BAR_SERVICE"
+             android:directBootAware="true"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.QUICKSTEP_SERVICE" />
+                <action android:name="android.intent.action.QUICKSTEP_SERVICE"/>
             </intent-filter>
         </service>
 
         <activity android:name="com.android.quickstep.RecentsActivity"
-            android:excludeFromRecents="true"
-            android:launchMode="singleTask"
-            android:clearTaskOnLaunch="true"
-            android:stateNotNeeded="true"
-            android:theme="@style/LauncherTheme"
-            android:screenOrientation="unspecified"
-            android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
-            android:resizeableActivity="true"
-            android:resumeWhilePausing="true"
-            android:taskAffinity="" />
+             android:excludeFromRecents="true"
+             android:launchMode="singleTask"
+             android:clearTaskOnLaunch="true"
+             android:stateNotNeeded="true"
+             android:theme="@style/LauncherTheme"
+             android:screenOrientation="unspecified"
+             android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+             android:resizeableActivity="true"
+             android:resumeWhilePausing="true"
+             android:taskAffinity=""/>
 
         <!-- Content provider to settings search. The autority should be same as the packageName -->
-        <provider
-            android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
-            android:authorities="${packageName}"
-            android:grantUriPermissions="true"
-            android:multiprocess="true"
-            android:permission="android.permission.READ_SEARCH_INDEXABLES"
-            android:exported="true">
+        <provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
+             android:authorities="${packageName}"
+             android:grantUriPermissions="true"
+             android:multiprocess="true"
+             android:permission="android.permission.READ_SEARCH_INDEXABLES"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
+                <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER"/>
             </intent-filter>
         </provider>
 
         <!-- FileProvider used for sharing images. -->
-        <provider
-            android:name="androidx.core.content.FileProvider"
-            android:authorities="${packageName}.overview.fileprovider"
-            android:exported="false"
-            android:grantUriPermissions="true">
-            <meta-data
-                android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/overview_file_provider_paths" />
+        <provider android:name="androidx.core.content.FileProvider"
+             android:authorities="${packageName}.overview.fileprovider"
+             android:exported="false"
+             android:grantUriPermissions="true">
+            <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
+                 android:resource="@xml/overview_file_provider_paths"/>
         </provider>
 
-        <service
-            android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
-            tools:node="remove" />
+        <service android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
+             tools:node="remove"/>
 
-        <activity
-            android:name="com.android.launcher3.proxy.ProxyActivityStarter"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
-            android:launchMode="singleTask"
-            android:clearTaskOnLaunch="true"
-            android:exported="false" />
+        <activity android:name="com.android.launcher3.proxy.ProxyActivityStarter"
+             android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
+             android:launchMode="singleTask"
+             android:clearTaskOnLaunch="true"
+             android:exported="false"/>
 
-        <activity
-            android:name="com.android.quickstep.interaction.GestureSandboxActivity"
-            android:autoRemoveFromRecents="true"
-            android:excludeFromRecents="true"
-            android:taskAffinity="${packageName}.launcher"
-            android:screenOrientation="portrait">
+        <activity android:name="com.android.quickstep.interaction.GestureSandboxActivity"
+             android:autoRemoveFromRecents="true"
+             android:excludeFromRecents="true"
+             android:taskAffinity="${packageName}.launcher"
+             android:screenOrientation="portrait"
+             android:exported="true">
             <intent-filter>
-                <action android:name="com.android.quickstep.action.GESTURE_SANDBOX" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="com.android.quickstep.action.GESTURE_SANDBOX"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 37314ea..52e6fab 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -75,6 +75,7 @@
 import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
 import com.android.quickstep.inputconsumers.AssistantInputConsumer;
 import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
+import com.android.quickstep.inputconsumers.OneHandedModeInputConsumer;
 import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
 import com.android.quickstep.inputconsumers.OverscrollInputConsumer;
 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -503,6 +504,12 @@
                     newGestureState = DEFAULT_STATE;
                     mUncheckedConsumer = InputConsumer.NO_OP;
                 }
+            } else if (mDeviceState.canTriggerOneHandedAction(event)
+                    && !mDeviceState.isOneHandedModeActive()) {
+                // Consume gesture event for triggering one handed feature.
+                mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
+                        InputConsumer.NO_OP, mInputMonitorCompat);
+                newGestureState = DEFAULT_STATE;
             } else {
                 newGestureState = DEFAULT_STATE;
                 mUncheckedConsumer = InputConsumer.NO_OP;
@@ -621,6 +628,11 @@
                 base = new ScreenPinnedInputConsumer(this, newGestureState);
             }
 
+            if (mDeviceState.canTriggerOneHandedAction(event)) {
+                base = new OneHandedModeInputConsumer(this, mDeviceState, base,
+                        mInputMonitorCompat);
+            }
+
             if (mDeviceState.isAccessibilityMenuAvailable()) {
                 base = new AccessibilityInputConsumer(this, mDeviceState, base,
                         mInputMonitorCompat);
@@ -629,6 +641,11 @@
             if (mDeviceState.isScreenPinningActive()) {
                 base = mResetGestureInputConsumer;
             }
+
+            if (mDeviceState.canTriggerOneHandedAction(event)) {
+                base = new OneHandedModeInputConsumer(this, mDeviceState, base,
+                        mInputMonitorCompat);
+            }
         }
         return base;
     }
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
new file mode 100644
index 0000000..46249d9
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OneHandedModeInputConsumer.java
@@ -0,0 +1,163 @@
+/*
+ * 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.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.launcher3.Utilities.squaredHypot;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+/**
+ * Touch consumer for handling gesture event to launch one handed
+ * One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode
+ */
+public class OneHandedModeInputConsumer extends DelegateInputConsumer {
+
+    private static final String TAG = "OneHandedModeInputConsumer";
+    private static final int ANGLE_MAX = 150;
+    private static final int ANGLE_MIN = 30;
+
+    private final Context mContext;
+    private final RecentsAnimationDeviceState mDeviceState;
+
+    private final float mDragDistThreshold;
+    private final float mSquaredSlop;
+
+    private final PointF mDownPos = new PointF();
+    private final PointF mLastPos = new PointF();
+    private final PointF mStartDragPos = new PointF();
+
+    private boolean mPassedSlop;
+
+    public OneHandedModeInputConsumer(Context context, RecentsAnimationDeviceState deviceState,
+            InputConsumer delegate, InputMonitorCompat inputMonitor) {
+        super(delegate, inputMonitor);
+        mContext = context;
+        mDeviceState = deviceState;
+        mDragDistThreshold = context.getResources().getDimensionPixelSize(
+                R.dimen.gestures_onehanded_drag_threshold);
+        mSquaredSlop = Utilities.squaredTouchSlop(context);
+    }
+
+    @Override
+    public int getType() {
+        return TYPE_ONE_HANDED | mDelegate.getType();
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case ACTION_DOWN: {
+                mDownPos.set(ev.getX(), ev.getY());
+                mLastPos.set(mDownPos);
+                break;
+            }
+            case ACTION_MOVE: {
+                if (mState == STATE_DELEGATE_ACTIVE) {
+                    break;
+                }
+                if (!mDelegate.allowInterceptByParent()) {
+                    mState = STATE_DELEGATE_ACTIVE;
+                    break;
+                }
+
+                mLastPos.set(ev.getX(), ev.getY());
+                if (!mPassedSlop) {
+                    if (squaredHypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y)
+                            > mSquaredSlop) {
+                        mStartDragPos.set(mLastPos.x, mLastPos.y);
+                        if ((!mDeviceState.isOneHandedModeActive() && isValidStartAngle(
+                                mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))
+                                || (mDeviceState.isOneHandedModeActive() && isValidExitAngle(
+                                mDownPos.x - mLastPos.x, mDownPos.y - mLastPos.y))) {
+                            mPassedSlop = true;
+                            setActive(ev);
+                        } else {
+                            mState = STATE_DELEGATE_ACTIVE;
+                        }
+                    }
+                } else {
+                    float distance = (float) Math.hypot(mLastPos.x - mStartDragPos.x,
+                            mLastPos.y - mStartDragPos.y);
+                    if (distance > mDragDistThreshold && mPassedSlop) {
+                        onStopGestureDetected();
+                    }
+                }
+                break;
+            }
+            case ACTION_UP:
+            case ACTION_CANCEL: {
+                if (mLastPos.y >= mStartDragPos.y && mPassedSlop) {
+                    onStartGestureDetected();
+                }
+
+                mPassedSlop = false;
+                mState = STATE_INACTIVE;
+                break;
+            }
+        }
+
+        if (mState != STATE_ACTIVE) {
+            mDelegate.onMotionEvent(ev);
+        }
+    }
+
+    private void onStartGestureDetected() {
+        if (mDeviceState.isOneHandedModeActive()) {
+            return;
+        }
+
+        if (mDeviceState.isOneHandedModeEnabled()) {
+            SystemUiProxy.INSTANCE.get(mContext).startOneHandedMode();
+            return;
+        }
+
+        // Hook one-handed gesture to expand notification panel by default
+        SystemUiProxy.INSTANCE.get(mContext).expandNotificationPanel();
+    }
+
+    private void onStopGestureDetected() {
+        if (!mDeviceState.isOneHandedModeEnabled() || !mDeviceState.isOneHandedModeActive()) {
+            return;
+        }
+
+        SystemUiProxy.INSTANCE.get(mContext).stopOneHandedMode();
+    }
+
+    private boolean isValidStartAngle(float deltaX, float deltaY) {
+        final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+        return angle > -(ANGLE_MAX) && angle < -(ANGLE_MIN);
+    }
+
+    private boolean isValidExitAngle(float deltaX, float deltaY) {
+        final float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+        return angle > ANGLE_MIN && angle < ANGLE_MAX;
+    }
+}
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9d70316..6737c5f 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -76,6 +76,10 @@
     <dimen name="gestures_assistant_drag_threshold">55dp</dimen>
     <dimen name="gestures_assistant_fling_threshold">55dp</dimen>
 
+    <!-- One-Handed Mode -->
+    <!-- Threshold for draging distance to enable one-handed mode -->
+    <dimen name="gestures_onehanded_drag_threshold">20dp</dimen>
+
     <!-- Distance to move elements when swiping up to go home from launcher -->
     <dimen name="home_pullback_distance">28dp</dimen>
 
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index ec720d5..67711c0 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -35,6 +35,7 @@
     int TYPE_RESET_GESTURE = 1 << 8;
     int TYPE_OVERSCROLL = 1 << 9;
     int TYPE_SYSUI_OVERLAY = 1 << 10;
+    int TYPE_ONE_HANDED = 1 << 11;
 
     String[] NAMES = new String[] {
            "TYPE_NO_OP",                    // 0
@@ -47,7 +48,8 @@
             "TYPE_OVERVIEW_WITHOUT_FOCUS",  // 7
             "TYPE_RESET_GESTURE",           // 8
             "TYPE_OVERSCROLL",              // 9
-            "TYPE_SYSUI_OVERLAY"         // 10
+            "TYPE_SYSUI_OVERLAY",           // 10
+            "TYPE_ONE_HANDED",              // 11
     };
 
     InputConsumer NO_OP = () -> TYPE_NO_OP;
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 3375c53..b49bc5a 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -63,6 +63,7 @@
     private SparseArray<OrientationRectF> mSwipeTouchRegions = new SparseArray<>(MAX_ORIENTATIONS);
     private final RectF mAssistantLeftRegion = new RectF();
     private final RectF mAssistantRightRegion = new RectF();
+    private final RectF mOneHandedModeRegion = new RectF();
     private int mCurrentDisplayRotation;
     private boolean mEnableMultipleRegions;
     private Resources mResources;
@@ -196,10 +197,10 @@
 
         Point size = display.realSize;
         int rotation = display.rotation;
+        int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
         OrientationRectF orientationRectF =
                 new OrientationRectF(0, 0, size.x, size.y, rotation);
         if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
-            int touchHeight = getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
             orientationRectF.top = orientationRectF.bottom - touchHeight;
 
             final int assistantWidth = mResources
@@ -228,10 +229,11 @@
                             + getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
                     break;
                 default:
-                    orientationRectF.top = orientationRectF.bottom
-                            - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE);
+                    orientationRectF.top = orientationRectF.bottom - touchHeight;
             }
         }
+        // One handed gestural only active on portrait mode
+        mOneHandedModeRegion.set(0, orientationRectF.bottom - touchHeight, size.x, size.y);
 
         return orientationRectF;
     }
@@ -242,6 +244,10 @@
 
     }
 
+    boolean touchInOneHandedModeRegion(MotionEvent ev) {
+        return mOneHandedModeRegion.contains(ev.getX(), ev.getY());
+    }
+
     private int getNavbarSize(String resName) {
         return ResourceUtils.getNavbarSize(resName, mResources);
     }
@@ -332,6 +338,7 @@
             regions.append(rectF.mRotation).append(" ");
         }
         pw.println(regions.toString());
+        pw.println("  mOneHandedModeRegion=" + mOneHandedModeRegion);
     }
 
     private class OrientationRectF extends RectF {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 79b38f2..04aba22 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -31,6 +31,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -45,10 +46,13 @@
 import android.content.res.Resources;
 import android.graphics.Region;
 import android.os.Process;
+import android.os.SystemProperties;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.view.MotionEvent;
+import android.view.Surface;
 import android.view.OrientationEventListener;
 
 import androidx.annotation.BinderThread;
@@ -90,10 +94,12 @@
     private @SystemUiStateFlags int mSystemUiStateFlags;
     private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
     private NavBarPosition mNavBarPosition;
+    private SecureSettingsObserver mOneHandedEnabledObserver;
 
     private final Region mDeferredGestureRegion = new Region();
     private boolean mAssistantAvailable;
     private float mAssistantVisibility;
+    private boolean mIsOneHandedModeEnabled;
 
     private boolean mIsUserUnlocked;
     private final ArrayList<Runnable> mUserUnlockedActions = new ArrayList<>();
@@ -231,6 +237,13 @@
             }
         }
 
+        if (SystemProperties.getBoolean("ro.support_one_handed_mode", false)) {
+            mOneHandedEnabledObserver = SecureSettingsObserver.newOneHandedSettingsObserver(
+                    mContext, this::onOneHandedEnabledSettingsChanged);
+            mOneHandedEnabledObserver.register();
+            mOneHandedEnabledObserver.dispatchOnChange();
+        }
+
         SecureSettingsObserver userSetupObserver = new SecureSettingsObserver(
                 context.getContentResolver(),
                 e -> mIsUserSetupComplete = e,
@@ -560,6 +573,13 @@
     }
 
     /**
+     * @return whether screen pinning is enabled and active
+     */
+    public boolean isOneHandedModeActive() {
+        return (mSystemUiStateFlags & SYSUI_STATE_ONE_HANDED_ACTIVE) != 0;
+    }
+
+    /**
      * Sets the region in screen space where the gestures should be deferred (ie. due to specific
      * nav bar ui).
      */
@@ -622,6 +642,28 @@
     }
 
     /**
+     * One handed gestural in quickstep only active on NO_BUTTON, TWO_BUTTONS, and portrait mode
+     *
+     * @param ev The touch screen motion event.
+     * @return whether the given motion event can trigger the one handed mode.
+     */
+    public boolean canTriggerOneHandedAction(MotionEvent ev) {
+        final DefaultDisplay.Info displayInfo = mDefaultDisplay.getInfo();
+        return (mOrientationTouchTransformer.touchInOneHandedModeRegion(ev)
+                && displayInfo.rotation != Surface.ROTATION_90
+                && displayInfo.rotation != Surface.ROTATION_270
+                && displayInfo.metrics.densityDpi < DisplayMetrics.DENSITY_600);
+    }
+
+    public boolean isOneHandedModeEnabled() {
+        return mIsOneHandedModeEnabled;
+    }
+
+    private void onOneHandedEnabledSettingsChanged(boolean isOneHandedEnabled) {
+        mIsOneHandedModeEnabled = isOneHandedEnabled;
+    }
+
+    /**
      * *May* apply a transform on the motion event if it lies in the nav bar region for another
      * orientation that is currently being tracked as a part of quickstep
      */
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 299e9e5..5b239a4 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -347,6 +347,28 @@
     }
 
     @Override
+    public void startOneHandedMode() {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.startOneHandedMode();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startOneHandedMode", e);
+            }
+        }
+    }
+
+    @Override
+    public void stopOneHandedMode() {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.stopOneHandedMode();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call stopOneHandedMode", e);
+            }
+        }
+    }
+
+    @Override
     public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
             Insets visibleInsets, Task.TaskKey task) {
         if (mSystemUiProxy != null) {
@@ -358,4 +380,15 @@
             }
         }
     }
+
+    @Override
+    public void expandNotificationPanel() {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.expandNotificationPanel();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call expandNotificationPanel", e);
+            }
+        }
+    }
 }
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
deleted file mode 100644
index 0758148..0000000
--- a/res/values-rm/strings.xml
+++ /dev/null
@@ -1,203 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/*
-* Copyright (C) 2008 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.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for application_name (5181331383435256801) -->
-    <skip />
-    <!-- no translation found for home (7658288663002113681) -->
-    <skip />
-    <!-- no translation found for uid_name (7820867637514617527) -->
-    <skip />
-    <string name="folder_name" msgid="7371454440695724752"></string>
-    <!-- no translation found for activity_not_found (8071924732094499514) -->
-    <skip />
-    <!-- no translation found for widgets_tab_label (2921133187116603919) -->
-    <skip />
-    <!-- no translation found for widget_adder (3201040140710381657) -->
-    <skip />
-    <!-- no translation found for toggle_weight_watcher (5645299835184636119) -->
-    <skip />
-    <!-- no translation found for long_press_widget_to_add (7699152356777458215) -->
-    <skip />
-    <!-- no translation found for market (2619650989819296998) -->
-    <skip />
-    <!-- no translation found for widget_dims_format (2370757736025621599) -->
-    <skip />
-    <!-- no translation found for external_drop_widget_error (3165821058322217155) -->
-    <skip />
-    <!-- no translation found for external_drop_widget_pick_title (3486317258037690630) -->
-    <skip />
-    <!-- no translation found for rename_folder_label (3727762225964550653) -->
-    <skip />
-    <!-- no translation found for rename_folder_title (3771389277707820891) -->
-    <skip />
-    <!-- no translation found for rename_action (5559600076028658757) -->
-    <skip />
-    <!-- no translation found for cancel_action (7009134900002915310) -->
-    <skip />
-    <!-- no translation found for menu_item_add_item (1264911265836810421) -->
-    <skip />
-    <!-- no translation found for group_applications (3797214114206693605) -->
-    <skip />
-    <!-- no translation found for group_shortcuts (6012256992764410535) -->
-    <skip />
-    <!-- no translation found for group_widgets (1569030723286851002) -->
-    <skip />
-    <!-- no translation found for completely_out_of_space (6106288382070760318) -->
-    <skip />
-    <!-- no translation found for out_of_space (4691004494942118364) -->
-    <skip />
-    <!-- no translation found for hotseat_out_of_space (7448809638125333693) -->
-    <skip />
-    <!-- no translation found for invalid_hotseat_item (5779907847267573691) -->
-    <skip />
-    <!-- no translation found for shortcut_installed (1701742129426969556) -->
-    <skip />
-    <!-- no translation found for shortcut_uninstalled (8176767991305701821) -->
-    <skip />
-    <!-- no translation found for shortcut_duplicate (9167217446062498127) -->
-    <skip />
-    <!-- no translation found for title_select_shortcut (6680642571148153868) -->
-    <skip />
-    <!-- no translation found for title_select_application (3280812711670683644) -->
-    <skip />
-    <!-- no translation found for all_apps_button_label (9110807029020582876) -->
-    <skip />
-    <!-- no translation found for all_apps_home_button_label (252062713717058851) -->
-    <skip />
-    <!-- no translation found for delete_zone_label_workspace (4009607676751398685) -->
-    <skip />
-    <!-- no translation found for delete_zone_label_all_apps (8083826390278958980) -->
-    <skip />
-    <!-- no translation found for delete_target_label (1822697352535677073) -->
-    <skip />
-    <!-- no translation found for delete_target_uninstall_label (5100785476250872595) -->
-    <skip />
-    <!-- no translation found for info_target_label (8053346143994679532) -->
-    <skip />
-    <!-- no translation found for accessibility_search_button (1628520399424565142) -->
-    <skip />
-    <!-- no translation found for accessibility_voice_search_button (4637324840434406584) -->
-    <skip />
-    <!-- no translation found for accessibility_all_apps_button (2603132375383800483) -->
-    <skip />
-    <!-- no translation found for accessibility_delete_button (6466114477993744621) -->
-    <skip />
-    <!-- no translation found for delete_zone_label_all_apps_system_app (449755632749610895) -->
-    <skip />
-    <!-- no translation found for cab_menu_delete_app (7435191475867183689) -->
-    <skip />
-    <!-- no translation found for cab_menu_app_info (8593722221450362342) -->
-    <skip />
-    <!-- no translation found for cab_app_selection_text (374688303047985416) -->
-    <skip />
-    <!-- no translation found for cab_widget_selection_text (1833458597831541241) -->
-    <skip />
-    <!-- no translation found for cab_folder_selection_text (7999992513806132118) -->
-    <skip />
-    <!-- no translation found for cab_shortcut_selection_text (2103811025667946450) -->
-    <skip />
-    <!-- no translation found for permlab_install_shortcut (5632423390354674437) -->
-    <skip />
-    <!-- no translation found for permdesc_install_shortcut (923466509822011139) -->
-    <skip />
-    <!-- no translation found for permlab_uninstall_shortcut (864595034498083837) -->
-    <skip />
-    <!-- no translation found for permdesc_uninstall_shortcut (5134129545001836849) -->
-    <skip />
-    <!-- no translation found for permlab_read_settings (1941457408239617576) -->
-    <skip />
-    <!-- no translation found for permdesc_read_settings (5833423719057558387) -->
-    <skip />
-    <!-- no translation found for permlab_write_settings (3574213698004620587) -->
-    <skip />
-    <!-- no translation found for permdesc_write_settings (5440712911516509985) -->
-    <skip />
-    <!-- no translation found for gadget_error_text (6081085226050792095) -->
-    <skip />
-    <!-- no translation found for uninstall_system_app_text (4172046090762920660) -->
-    <skip />
-    <!-- no translation found for dream_name (1530253749244328964) -->
-    <skip />
-    <!-- no translation found for folder_hint_text (6617836969016293992) -->
-    <skip />
-    <!-- no translation found for workspace_description_format (2950174241104043327) -->
-    <skip />
-    <!-- no translation found for default_scroll_format (7475544710230993317) -->
-    <skip />
-    <!-- no translation found for workspace_scroll_format (8458889198184077399) -->
-    <skip />
-    <!-- no translation found for apps_customize_apps_scroll_format (370005296147130238) -->
-    <skip />
-    <!-- no translation found for apps_customize_widgets_scroll_format (3106209519974971521) -->
-    <skip />
-    <!-- no translation found for first_run_cling_title (2459738000155917941) -->
-    <skip />
-    <!-- no translation found for first_run_cling_description (6447072552696253358) -->
-    <skip />
-    <!-- no translation found for first_run_cling_create_screens_hint (6950729526680114157) -->
-    <skip />
-    <!-- no translation found for migration_cling_title (9181776667882933767) -->
-    <skip />
-    <!-- no translation found for migration_cling_description (2752413805582227644) -->
-    <skip />
-    <!-- no translation found for migration_cling_copy_apps (946331230090919440) -->
-    <skip />
-    <!-- no translation found for migration_cling_use_default (2626475813981258626) -->
-    <skip />
-    <!-- no translation found for workspace_cling_title (5626202359865825661) -->
-    <skip />
-    <!-- no translation found for workspace_cling_move_item (528201129978005352) -->
-    <skip />
-    <!-- no translation found for folder_cling_title (3894908818693254164) -->
-    <skip />
-    <!-- no translation found for folder_cling_create_folder (6158215559475836131) -->
-    <skip />
-    <!-- no translation found for cling_dismiss (8962359497601507581) -->
-    <skip />
-    <!-- no translation found for folder_opened (94695026776264709) -->
-    <skip />
-    <!-- no translation found for folder_tap_to_close (1884479294466410023) -->
-    <skip />
-    <!-- no translation found for folder_tap_to_rename (9191075570492871147) -->
-    <skip />
-    <!-- no translation found for folder_closed (4100806530910930934) -->
-    <skip />
-    <!-- no translation found for folder_renamed (1794088362165669656) -->
-    <skip />
-    <!-- no translation found for folder_name_format (6629239338071103179) -->
-    <skip />
-    <!-- no translation found for widget_button_text (2880537293434387943) -->
-    <skip />
-    <!-- no translation found for wallpaper_button_text (8404103075899945851) -->
-    <skip />
-    <!-- no translation found for settings_button_text (8119458837558863227) -->
-    <skip />
-    <!-- no translation found for package_state_enqueued (6227252464303085641) -->
-    <skip />
-    <!-- no translation found for package_state_downloading (4088770468458724721) -->
-    <skip />
-    <!-- no translation found for package_state_installing (7588193972189849870) -->
-    <skip />
-    <!-- no translation found for package_state_unknown (7592128424511031410) -->
-    <skip />
-    <!-- no translation found for package_state_error (7672093962724223588) -->
-    <skip />
-</resources>
diff --git a/src/com/android/launcher3/util/SecureSettingsObserver.java b/src/com/android/launcher3/util/SecureSettingsObserver.java
index 48aa02b..08a8e6d 100644
--- a/src/com/android/launcher3/util/SecureSettingsObserver.java
+++ b/src/com/android/launcher3/util/SecureSettingsObserver.java
@@ -29,6 +29,8 @@
 
     /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
     public static final String NOTIFICATION_BADGING = "notification_badging";
+    /** Hidden field Settings.Secure.ONE_HANDED_MODE_ENABLED */
+    public static final String ONE_HANDED_ENABLED = "one_handed_mode_enabled";
 
     private final ContentResolver mResolver;
     private final String mKeySetting;
@@ -79,4 +81,10 @@
         return new SecureSettingsObserver(
                 context.getContentResolver(), listener, NOTIFICATION_BADGING, 1);
     }
+
+    public static SecureSettingsObserver newOneHandedSettingsObserver(Context context,
+            OnChangeListener listener) {
+        return new SecureSettingsObserver(
+                context.getContentResolver(), listener, ONE_HANDED_ENABLED, 1);
+    }
 }
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 1c8f095..f243f27 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -29,6 +29,7 @@
 
         <receiver
             android:name="com.android.launcher3.testcomponent.AppWidgetNoConfig"
+            android:exported="true"
             android:label="No Config">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -39,6 +40,7 @@
 
         <receiver
             android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
+            android:exported="true"
             android:label="Hidden widget">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -49,6 +51,7 @@
 
         <receiver
             android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
+            android:exported="true"
             android:label="With Config">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
@@ -58,12 +61,14 @@
         </receiver>
 
         <activity
-            android:name="com.android.launcher3.testcomponent.WidgetConfigActivity">
+            android:name="com.android.launcher3.testcomponent.WidgetConfigActivity"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
             </intent-filter>
         </activity>
-        <activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity">
+        <activity android:name="com.android.launcher3.testcomponent.CustomShortcutConfigActivity"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.CREATE_SHORTCUT" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -72,6 +77,7 @@
         <activity
             android:name="com.android.launcher3.testcomponent.RequestPinItemActivity"
             android:icon="@drawable/test_drawable_pin_item"
+            android:exported="true"
             android:label="Test Pin Item">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -102,6 +108,7 @@
             android:stateNotNeeded="true"
             android:taskAffinity=""
             android:theme="@android:style/Theme.DeviceDefault.Light"
+            android:exported="true"
             android:windowSoftInputMode="adjustPan">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -114,6 +121,7 @@
         <activity
             android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
             android:label="LauncherTestApp"
+            android:exported="true"
             android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -128,6 +136,7 @@
         </activity>
         <activity-alias android:name="Activity2"
                         android:label="TestActivity2"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -136,6 +145,7 @@
         </activity-alias>
         <activity-alias android:name="Activity3"
                         android:label="TestActivity3"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -144,6 +154,7 @@
         </activity-alias>
         <activity-alias android:name="Activity4"
                         android:label="TestActivity4"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -152,6 +163,7 @@
         </activity-alias>
         <activity-alias android:name="Activity5"
                         android:label="TestActivity5"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -160,6 +172,7 @@
         </activity-alias>
         <activity-alias android:name="Activity6"
                         android:label="TestActivity6"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -168,6 +181,7 @@
         </activity-alias>
         <activity-alias android:name="Activity7"
                         android:label="TestActivity7"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -176,6 +190,7 @@
         </activity-alias>
         <activity-alias android:name="Activity8"
                         android:label="TestActivity8"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -184,6 +199,7 @@
         </activity-alias>
         <activity-alias android:name="Activity9"
                         android:label="TestActivity9"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -192,6 +208,7 @@
         </activity-alias>
         <activity-alias android:name="Activity10"
                         android:label="TestActivity10"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -200,6 +217,7 @@
         </activity-alias>
         <activity-alias android:name="Activity11"
                         android:label="TestActivity11"
+                        android:exported="true"
                         android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/dummy_app/AndroidManifest.xml b/tests/dummy_app/AndroidManifest.xml
index f00138c..d5e2320 100644
--- a/tests/dummy_app/AndroidManifest.xml
+++ b/tests/dummy_app/AndroidManifest.xml
@@ -26,6 +26,7 @@
         <activity
             android:name="Activity1"
             android:icon="@mipmap/ic_launcher1"
+            android:exported="true"
             android:label="Aardwolf">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 081d43a..7cf6e4f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -250,7 +250,8 @@
     }
 
     public void enableCheckEventsForSuccessfulGestures() {
-        mCheckEventsForSuccessfulGestures = true;
+        // b/153824894
+        // mCheckEventsForSuccessfulGestures = true;
     }
 
     public void setOnLauncherCrashed(Runnable onLauncherCrashed) {