Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index eb62110..283743d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -51,7 +51,7 @@
  * first home screen instead of to Overview.
  */
 public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouchController {
-
+    private static final float ONE_HANDED_ACTIVATED_SLOP_MULTIPLIER = 2.5f;
 
     // How much of the movement to use for translating overview after swipe and hold.
     private static final float OVERVIEW_MOVEMENT_FACTOR = 0.25f;
@@ -260,4 +260,14 @@
     private float dpiFromPx(float pixels) {
         return Utilities.dpiFromPx(pixels, mLauncher.getResources().getDisplayMetrics().densityDpi);
     }
+
+    @Override
+    public void onOneHandedModeStateChanged(boolean activated) {
+        if (activated) {
+            mDetector.setTouchSlopMultiplier(ONE_HANDED_ACTIVATED_SLOP_MULTIPLIER);
+        } else {
+            // Reset touch slop multiplier to default 1.0f
+            mDetector.setTouchSlopMultiplier(1f /* default */);
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index be927e0..306032c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -972,6 +972,10 @@
         }
         if (endTarget == HOME) {
             duration = HOME_DURATION;
+            // Early detach the nav bar once the endTarget is determined as HOME
+            if (mRecentsAnimationController != null) {
+                mRecentsAnimationController.detachNavigationBarFromApp(true);
+            }
         } else if (endTarget == RECENTS) {
             if (mRecentsView != null) {
                 int nearestPage = mRecentsView.getDestinationPage();
@@ -1496,7 +1500,7 @@
         if (LIVE_TILE.get()) {
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
             if (mRecentsAnimationController != null) {
-                mRecentsAnimationController.getController().detachNavigationBarFromApp(true);
+                mRecentsAnimationController.detachNavigationBarFromApp(true);
             }
         } else if (!hasTargets() || mRecentsAnimationController == null) {
             // If there are no targets or the animation not started, then there is nothing to finish
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 4ae6fa8..7ab371b 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -114,6 +114,9 @@
 
     public abstract void onAssistantVisibilityChanged(float visibility);
 
+    /** Called when one handed mode activated or deactivated. */
+    public abstract void onOneHandedModeStateChanged(boolean activated);
+
     public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
             boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
 
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 4ee4398..906599f 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -73,6 +73,11 @@
         // set to zero prior to this class becoming active.
     }
 
+    @Override
+    public void onOneHandedModeStateChanged(boolean activated) {
+        // Do nothing for FallbackActivityInterface
+    }
+
     /** 6 */
     @Override
     public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 9014774..30abfbb 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -105,6 +105,15 @@
     }
 
     @Override
+    public void onOneHandedModeStateChanged(boolean activated) {
+        Launcher launcher = getCreatedActivity();
+        if (launcher == null) {
+            return;
+        }
+        launcher.onOneHandedStateChanged(activated);
+    }
+
+    @Override
     public AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
             boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback) {
         notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index fb8f9fe..0efe666 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -111,6 +111,11 @@
         if (mDeviceState.isHomeDisabled() != mIsHomeDisabled) {
             updateOverviewTargets();
         }
+
+        // Notify ALL_APPS touch controller when one handed mode state activated or deactivated
+        if (mDeviceState.isOneHandedModeEnabled()) {
+            mActivityInterface.onOneHandedModeStateChanged(mDeviceState.isOneHandedModeActive());
+        }
     }
 
     private void updateOverviewTargets(Intent unused) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 462f714..50d0569 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -155,6 +155,14 @@
     }
 
     /**
+     * @see RecentsAnimationControllerCompat#detachNavigationBarFromApp
+     */
+    @UiThread
+    public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+        UI_HELPER_EXECUTOR.execute(() -> mController.detachNavigationBarFromApp(moveHomeToTop));
+    }
+
+    /**
      * Sets the final surface transaction on a Task. This is used by Launcher to notify the system
      * that animating Activity to PiP has completed and the associated task surface should be
      * updated accordingly. This should be called before `finish`
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a0bba86..a4c60cf 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -410,6 +410,7 @@
     // TODO(b/187528071): Remove these and replace with a real scrim.
     private float mColorTint;
     private final int mTintingColor;
+    private ObjectAnimator mTintingAnimator;
 
     private int mOverScrollShift = 0;
 
@@ -3693,9 +3694,17 @@
      * tasks to be dimmed while other elements in the recents view are left alone.
      */
     public void showForegroundScrim(boolean show) {
-        ObjectAnimator anim = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
-        anim.setAutoCancel(true);
-        anim.start();
+        if (!show && mColorTint == 0) {
+            if (mTintingAnimator != null) {
+                mTintingAnimator.cancel();
+                mTintingAnimator = null;
+            }
+            return;
+        }
+
+        mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
+        mTintingAnimator.setAutoCancel(true);
+        mTintingAnimator.start();
     }
 
     /** Tint the RecentsView and TaskViews in to simulate a scrim. */
diff --git a/res/color-night-v31/widgets_picker_scrim.xml b/res/color-night-v31/widgets_picker_scrim.xml
new file mode 100644
index 0000000..be7010b
--- /dev/null
+++ b/res/color-night-v31/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2021, 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral1_900" android:alpha="0.8" />
+</selector>
diff --git a/res/color-v31/widgets_picker_scrim.xml b/res/color-v31/widgets_picker_scrim.xml
new file mode 100644
index 0000000..648824a
--- /dev/null
+++ b/res/color-v31/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2021, 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral1_200" android:alpha="0.8" />
+</selector>
diff --git a/res/color/widgets_picker_scrim.xml b/res/color/widgets_picker_scrim.xml
new file mode 100644
index 0000000..1cf97f6
--- /dev/null
+++ b/res/color/widgets_picker_scrim.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2021, 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.
+*/
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#000000" android:alpha="0.32" />
+</selector>
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index ddc9815..9439baf 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -31,7 +31,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@drawable/add_item_dialog_background"
-        android:padding="24dp"
+        android:paddingTop="24dp"
         android:theme="?attr/widgetsTheme"
         android:layout_gravity="bottom"
         android:orientation="vertical">
@@ -42,6 +42,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center_horizontal"
+            android:paddingHorizontal="24dp"
             android:textColor="?android:attr/textColorPrimary"
             android:textSize="24sp"
             android:ellipsize="end"
@@ -53,6 +54,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center_horizontal"
+            android:paddingHorizontal="24dp"
             android:paddingTop="8dp"
             android:text="@string/add_item_request_drag_hint"
             android:textSize="14sp"
diff --git a/res/layout/settings_activity.xml b/res/layout/settings_activity.xml
index c70d5bf..5edd2df 100644
--- a/res/layout/settings_activity.xml
+++ b/res/layout/settings_activity.xml
@@ -18,7 +18,8 @@
     android:id="@+id/content_parent"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
 
     <Toolbar
         android:id="@+id/action_bar"
diff --git a/robolectric_tests/src/com/android/launcher3/settings/SettingsActivityTest.java b/robolectric_tests/src/com/android/launcher3/settings/SettingsActivityTest.java
index 85bf28e..3271812 100644
--- a/robolectric_tests/src/com/android/launcher3/settings/SettingsActivityTest.java
+++ b/robolectric_tests/src/com/android/launcher3/settings/SettingsActivityTest.java
@@ -27,6 +27,7 @@
 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
 import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
@@ -109,6 +110,7 @@
 
         onView(withText("About")).check(matches(isDisplayed()));
         onView(withText("Version")).check(matches(isDisplayed()));
+        onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
     }
 
     @Test
@@ -119,6 +121,7 @@
 
         onView(withText("Developer Options")).check(matches(isDisplayed()));
         onView(withId(R.id.filter_box)).check(matches(isDisplayed()));
+        onView(withContentDescription("Navigate up")).check(matches(isDisplayed()));
     }
 
     @Test
@@ -134,4 +137,16 @@
             assertThat(e.getMessage()).contains(fragmentClass);
         }
     }
+
+    @Test
+    public void testSettings_backButtonFinishesActivity() {
+        Bundle fragmentArgs = new Bundle();
+        fragmentArgs.putString(ARG_PREFERENCE_ROOT, "about_screen");
+        Intent intent = new Intent(mApplicationContext, SettingsActivity.class)
+                .putExtra(EXTRA_FRAGMENT_ARGS, fragmentArgs);
+        ActivityScenario<SettingsActivity> scenario = ActivityScenario.launch(intent);
+
+        onView(withContentDescription("Navigate up")).perform(click());
+        scenario.onActivity(activity -> assertThat(activity.isFinishing()).isTrue());
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index cdc09f1..e9245b0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -399,8 +399,10 @@
     public boolean shouldInsetWidgets() {
         Rect widgetPadding = inv.defaultWidgetPadding;
 
-        // Check all sides to ensure that the widget won't overlap into another cell.
-        return cellLayoutBorderSpacingPx > widgetPadding.left
+        // Check all sides to ensure that the widget won't overlap into another cell, or into
+        // status bar.
+        return workspaceTopPadding > widgetPadding.top
+                && cellLayoutBorderSpacingPx > widgetPadding.left
                 && cellLayoutBorderSpacingPx > widgetPadding.top
                 && cellLayoutBorderSpacingPx > widgetPadding.right
                 && cellLayoutBorderSpacingPx > widgetPadding.bottom;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8889e60..299c68f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -576,6 +576,14 @@
         mHotseat.getQsb().setAlpha(1f - visibility);
     }
 
+    /**
+     * Called when one handed mode activated and deactivated.
+     * @param activated true if one handed mode activated, false otherwise.
+     */
+    public void onOneHandedStateChanged(boolean activated) {
+        mDragLayer.onOneHandedModeStateChanged(activated);
+    }
+
     private void initDeviceProfile(InvariantDeviceProfile idp) {
         // Load configuration-specific DeviceProfile
         mDeviceProfile = idp.getDeviceProfile(this);
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 5dae5a6..b4288ce 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.views.AbstractSlideInView;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.AddItemWidgetsBottomSheet;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.NavigableAppWidgetHostView;
@@ -89,6 +90,7 @@
     private LauncherAppState mApp;
     private InvariantDeviceProfile mIdp;
     private BaseDragLayer<AddItemActivity> mDragLayer;
+    private AddItemWidgetsBottomSheet mSlideInView;
 
     private WidgetCell mWidgetCell;
 
@@ -124,8 +126,6 @@
         mDragLayer = findViewById(R.id.add_item_drag_layer);
         mDragLayer.recreateControllers();
         mDragLayer.setInsets(mDeviceProfile.getInsets());
-        AbstractSlideInView<AddItemActivity> slideInView = findViewById(R.id.add_item_bottom_sheet);
-        slideInView.addOnCloseListener(this);
         mWidgetCell = findViewById(R.id.widget_cell);
 
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -151,6 +151,9 @@
         TextView widgetAppName = findViewById(R.id.widget_appName);
         widgetAppName.setText(getApplicationInfo().labelRes);
 
+        mSlideInView = findViewById(R.id.add_item_bottom_sheet);
+        mSlideInView.addOnCloseListener(this);
+        mSlideInView.show();
         setupNavBarColor();
     }
 
@@ -279,7 +282,7 @@
      */
     public void onCancelClick(View v) {
         logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_CANCELLED);
-        finish();
+        mSlideInView.close(/* animate= */ true);
     }
 
     /**
@@ -290,7 +293,7 @@
             ItemInstallQueue.INSTANCE.get(this).queueItem(mRequest.getShortcutInfo());
             logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
             mRequest.accept();
-            finish();
+            mSlideInView.close(/* animate= */ true);
             return;
         }
 
@@ -313,7 +316,7 @@
         mWidgetOptions.putInt(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
         mRequest.accept(mWidgetOptions);
         logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_PLACED_AUTOMATICALLY);
-        finish();
+        mSlideInView.close(/* animate= */ true);
     }
 
     @Override
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index c2f609c..011325d 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -48,6 +48,7 @@
 import com.android.launcher3.graphics.Scrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
@@ -519,4 +520,14 @@
     public Scrim getWorkspaceDragScrim() {
         return mWorkspaceDragScrim;
     }
+
+    /**
+     * Called when one handed mode state changed.
+     * @param activated true if one handed mode activated, false otherwise.
+     */
+    public void onOneHandedModeStateChanged(boolean activated) {
+        for (TouchController controller : mControllers) {
+            controller.onOneHandedModeStateChanged(activated);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index e2a69ff..8fe42ac 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -152,6 +152,17 @@
                 filterPreferences(query, mPreferenceScreen);
             }
         });
+
+        View listView = getListView();
+        final int bottomPadding = listView.getPaddingBottom();
+        listView.setOnApplyWindowInsetsListener((v, insets) -> {
+            v.setPadding(
+                    v.getPaddingLeft(),
+                    v.getPaddingTop(),
+                    v.getPaddingRight(),
+                    bottomPadding + insets.getSystemWindowInsetBottom());
+            return insets.consumeSystemWindowInsets();
+        });
     }
 
     @Override
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 05927ef..915e140 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -24,9 +24,12 @@
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.text.TextUtils;
+import android.view.MenuItem;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.view.WindowCompat;
 import androidx.fragment.app.DialogFragment;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
@@ -82,9 +85,14 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.settings_activity);
         setActionBar(findViewById(R.id.action_bar));
+        WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
+
+        Intent intent = getIntent();
+        if (intent.hasExtra(EXTRA_FRAGMENT) || intent.hasExtra(EXTRA_FRAGMENT_ARGS)) {
+            getActionBar().setDisplayHomeAsUpEnabled(true);
+        }
 
         if (savedInstanceState == null) {
-            Intent intent = getIntent();
             Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
             if (args == null) {
                 args = new Bundle();
@@ -161,6 +169,15 @@
         return startPreference(getString(R.string.settings_fragment_name), args, pref.getKey());
     }
 
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == android.R.id.home) {
+            onBackPressed();
+            return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
     /**
      * This fragment shows the launcher preferences.
      */
@@ -199,6 +216,21 @@
         }
 
         @Override
+        public void onViewCreated(View view, Bundle savedInstanceState) {
+            super.onViewCreated(view, savedInstanceState);
+            View listView = getListView();
+            final int bottomPadding = listView.getPaddingBottom();
+            listView.setOnApplyWindowInsetsListener((v, insets) -> {
+                v.setPadding(
+                        v.getPaddingLeft(),
+                        v.getPaddingTop(),
+                        v.getPaddingRight(),
+                        bottomPadding + insets.getSystemWindowInsetBottom());
+                return insets.consumeSystemWindowInsets();
+            });
+        }
+
+        @Override
         public void onSaveInstanceState(Bundle outState) {
             super.onSaveInstanceState(outState);
             outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
diff --git a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
index 8c3c115..f751b7d 100644
--- a/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
+++ b/src/com/android/launcher3/touch/SingleAxisSwipeDetector.java
@@ -102,6 +102,8 @@
 
     private int mScrollDirections;
 
+    private float mTouchSlopMultiplier = 1f;
+
     public SingleAxisSwipeDetector(@NonNull Context context, @NonNull Listener l,
             @NonNull Direction dir) {
         this(ViewConfiguration.get(context), l, dir, Utilities.isRtl(context.getResources()));
@@ -115,6 +117,19 @@
         mDir = dir;
     }
 
+    /**
+     * Provides feasibility to adjust touch slop when visible window size changed. When visible
+     * bounds translate become smaller, multiply a larger multiplier could ensure the UX
+     * more consistent.
+     *
+     * @see #shouldScrollStart(PointF)
+     *
+     * @param touchSlopMultiplier the value to multiply original touch slop.
+     */
+    public void setTouchSlopMultiplier(float touchSlopMultiplier) {
+        mTouchSlopMultiplier = touchSlopMultiplier;
+    }
+
     public void setDetectableScrollConditions(int scrollDirectionFlags, boolean ignoreSlop) {
         mScrollDirections = scrollDirectionFlags;
         mIgnoreSlopWhenSettling = ignoreSlop;
@@ -133,7 +148,7 @@
     @Override
     protected boolean shouldScrollStart(PointF displacement) {
         // Reject cases where the angle or slop condition is not met.
-        float minDisplacement = Math.max(mTouchSlop,
+        float minDisplacement = Math.max(mTouchSlop * mTouchSlopMultiplier,
                 Math.abs(mDir.extractOrthogonalDirection(displacement)));
         if (Math.abs(mDir.extractDirection(displacement)) < minDisplacement) {
             return false;
diff --git a/src/com/android/launcher3/util/TouchController.java b/src/com/android/launcher3/util/TouchController.java
index fc1d819..9c397c0 100644
--- a/src/com/android/launcher3/util/TouchController.java
+++ b/src/com/android/launcher3/util/TouchController.java
@@ -32,5 +32,10 @@
      */
     boolean onControllerInterceptTouchEvent(MotionEvent ev);
 
+    /**
+     * Called when one handed mode state changed
+     */
+    default void onOneHandedModeStateChanged(boolean activated) { }
+
     default void dump(String prefix, PrintWriter writer) { }
 }
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
index e69cb5b..c6fa98a 100644
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -35,8 +35,6 @@
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
 
-    protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
-
     private Rect mInsets = new Rect();
     private View mEduView;
 
@@ -87,7 +85,7 @@
 
     @Override
     protected int getScrimColor(Context context) {
-        return FINAL_SCRIM_BG_COLOR;
+        return context.getResources().getColor(R.color.widgets_picker_scrim);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 9e08303..804973f 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -23,8 +23,11 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.view.ViewParent;
 
 import com.android.launcher3.Insettable;
+import com.android.launcher3.R;
 import com.android.launcher3.dragndrop.AddItemActivity;
 import com.android.launcher3.views.AbstractSlideInView;
 
@@ -48,6 +51,17 @@
         mContent = this;
         mInsets = new Rect();
         mCurrentConfiguration = new Configuration(getResources().getConfiguration());
+    }
+
+    /**
+     * Attaches to activity container and animates open the bottom sheet.
+     */
+    public void show() {
+        ViewParent parent = getParent();
+        if (parent instanceof ViewGroup) {
+            ((ViewGroup) parent).removeView(this);
+        }
+        attachToContainer();
         animateOpen();
     }
 
@@ -95,4 +109,9 @@
         }
         mCurrentConfiguration.updateFrom(newConfig);
     }
+
+    @Override
+    protected int getScrimColor(Context context) {
+        return context.getResources().getColor(R.color.widgets_picker_scrim);
+    }
 }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index e6791c3..edd42b4 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.widget;
 
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -62,8 +60,7 @@
     }
 
     protected int getScrimColor(Context context) {
-        int alpha = context.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
-        return setColorAlphaBound(context.getColor(R.color.wallpaper_popup_scrim), alpha);
+        return context.getResources().getColor(R.color.widgets_picker_scrim);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 7963431..3936ec8 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -25,6 +25,7 @@
 import android.view.ViewGroup;
 import android.widget.TableRow;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.Adapter;
@@ -48,8 +49,10 @@
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.OptionalInt;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 /**
  * Recycler view adapter for the widget tray.
@@ -87,6 +90,7 @@
                     || new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
                             .equals(mWidgetsContentVisiblePackageUserKey);
     @Nullable private Predicate<WidgetsListBaseEntry> mFilter = null;
+    @Nullable private RecyclerView mRecyclerView;
 
     public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
             WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
@@ -106,6 +110,16 @@
                         layoutInflater, /*onHeaderClickListener=*/ this, /* listAdapter= */ this));
     }
 
+    @Override
+    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+        mRecyclerView = recyclerView;
+    }
+
+    @Override
+    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
+        mRecyclerView = null;
+    }
+
     public void setFilter(Predicate<WidgetsListBaseEntry> filter) {
         mFilter = filter;
     }
@@ -168,12 +182,10 @@
         mAllEntries.forEach(entry -> {
             if (entry instanceof WidgetsListHeaderEntry) {
                 ((WidgetsListHeaderEntry) entry).setIsWidgetListShown(
-                        new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
-                                .equals(mWidgetsContentVisiblePackageUserKey));
+                        isHeaderForVisibleContent(entry));
             } else if (entry instanceof WidgetsListSearchHeaderEntry) {
                 ((WidgetsListSearchHeaderEntry) entry).setIsWidgetListShown(
-                        new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
-                                .equals(mWidgetsContentVisiblePackageUserKey));
+                        isHeaderForVisibleContent(entry));
             }
         });
         List<WidgetsListBaseEntry> newVisibleEntries = mAllEntries.stream()
@@ -183,6 +195,13 @@
         mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator);
     }
 
+    private boolean isHeaderForVisibleContent(WidgetsListBaseEntry entry) {
+        return (entry instanceof WidgetsListHeaderEntry
+                || entry instanceof WidgetsListSearchHeaderEntry)
+                && new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user)
+                .equals(mWidgetsContentVisiblePackageUserKey);
+    }
+
     /**
      * Resets any expanded widget header.
      */
@@ -247,12 +266,40 @@
         if (showWidgets) {
             mWidgetsContentVisiblePackageUserKey = packageUserKey;
             updateVisibleEntries();
+            // Scroll the layout manager to the header position to keep it anchored to the same
+            // position.
+            scrollToSelectedHeaderPosition();
         } else if (packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) {
             mWidgetsContentVisiblePackageUserKey = null;
             updateVisibleEntries();
         }
     }
 
+    private void scrollToSelectedHeaderPosition() {
+        OptionalInt selectedHeaderPosition =
+                IntStream.range(0, mVisibleEntries.size())
+                        .filter(index -> isHeaderForVisibleContent(mVisibleEntries.get(index)))
+                        .findFirst();
+        RecyclerView.LayoutManager layoutManager =
+                mRecyclerView == null ? null : mRecyclerView.getLayoutManager();
+        if (!selectedHeaderPosition.isPresent() || layoutManager == null) {
+            return;
+        }
+
+        // Scroll to the selected header position. LinearLayoutManager scrolls the minimum distance
+        // necessary, so this will keep the selected header in place during clicks, without
+        // interrupting the animation.
+        int position = selectedHeaderPosition.getAsInt();
+        if (position == mVisibleEntries.size() - 2) {
+            // If the selected header is in the last position (-1 for the content), then scroll to
+            // the final position so the last list of widgets will show.
+            layoutManager.scrollToPosition(mVisibleEntries.size() - 1);
+        } else {
+            // Otherwise, scroll to the position of the selected header.
+            layoutManager.scrollToPosition(position);
+        }
+    }
+
     /**
      * Sets the max horizontal spans that are allowed for grouping more than one widgets in a table
      * row.
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index e30e245..090362b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -154,8 +154,25 @@
             return -1;
         }
 
-        View child = getChildAt(0);
-        int rowIndex = getChildPosition(child);
+        int rowIndex = -1;
+        View child = null;
+
+        LayoutManager layoutManager = getLayoutManager();
+        if (layoutManager instanceof LinearLayoutManager) {
+            // Use the LayoutManager as the source of truth for visible positions. During
+            // animations, the view group child may not correspond to the visible views that appear
+            // at the top.
+            rowIndex = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
+            child = layoutManager.findViewByPosition(rowIndex);
+        }
+
+        if (child == null) {
+            // If the layout manager returns null for any reason, which can happen before layout
+            // has occurred for the position, then look at the child of this view as a ViewGroup.
+            child = getChildAt(0);
+            rowIndex = getChildPosition(child);
+        }
+
         for (int i = 0; i < getChildCount(); i++) {
             View view = getChildAt(i);
             if (view instanceof TableLayout) {