[automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: 46a7262d30

Blank merge reason: commit message contains skip directive

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

Change-Id: I4a712c0754e46b406cc23f6b31919c343e599121
diff --git a/Android.bp b/Android.bp
index 1b6ffe4..45d022f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,6 +112,7 @@
         "androidx.preference_preference",
         "androidx.slice_slice-view",
         "androidx.cardview_cardview",
+        "com.google.android.material_material",
         "iconloader_base",
     ],
     manifest: "AndroidManifest-common.xml",
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index d725a16..4eecf29 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -144,7 +144,7 @@
         <activity
             android:name="com.android.launcher3.settings.SettingsActivity"
             android:label="@string/settings_button_text"
-            android:theme="@style/HomeSettingsTheme"
+            android:theme="@style/HomeSettings.Theme"
             android:exported="true"
             android:autoRemoveFromRecents="true">
             <intent-filter>
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index b43d8d1..dc92731 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -22,11 +22,6 @@
      xmlns:tools="http://schemas.android.com/tools"
      package="com.android.launcher3">
 
-     <permission
-        android:name="${packageName}.permission.HOTSEAT_EDU"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signatureOrSystem" />
-
     <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
     <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
     <uses-permission android:name="android.permission.VIBRATE"/>
@@ -41,7 +36,6 @@
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
     <uses-permission android:name="android.permission.MONITOR_INPUT"/>
 
-    <uses-permission android:name="${packageName}.permission.HOTSEAT_EDU" />
     <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
 
     <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -133,20 +127,6 @@
             </intent-filter>
         </activity>
 
-        <activity
-            android:name=".hybridhotseat.HotseatEduActivity"
-            android:theme="@android:style/Theme.NoDisplay"
-            android:noHistory="true"
-            android:launchMode="singleTask"
-            android:clearTaskOnLaunch="true"
-            android:permission="${packageName}.permission.HOTSEAT_EDU"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="com.android.launcher3.action.SHOW_HYBRID_HOTSEAT_EDU"/>
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
     </application>
 
 </manifest>
diff --git a/quickstep/res/interpolator/app_open_x.xml b/quickstep/res/interpolator/app_open_x.xml
new file mode 100644
index 0000000..5fa0bcb
--- /dev/null
+++ b/quickstep/res/interpolator/app_open_x.xml
@@ -0,0 +1,21 @@
+<?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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0, 0 C 0.1217, 0.0462, 0.15, 0.4686, 0.1667, 0.66 C 0.1834, 0.8878, 0.1667, 1, 1, 1"/>
diff --git a/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml b/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml
new file mode 100644
index 0000000..70c4231
--- /dev/null
+++ b/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml
@@ -0,0 +1,21 @@
+<?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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index a44de79..de0416b 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -200,6 +200,17 @@
         }
     }
 
+    /**
+     * {@code LauncherOverlayCallbacks} scroll amount.
+     * Indicates transition progress to -1 screen.
+     * @param progress From 0 to 1.
+     */
+    @Override
+    public void onScrollChanged(float progress) {
+        super.onScrollChanged(progress);
+        mDepthController.onOverlayScrollChanged(progress);
+    }
+
     @Override
     public void startIntentSenderForResult(IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 5bb76d6..b557779 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -32,7 +32,6 @@
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
-import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
 import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
@@ -72,6 +71,7 @@
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
@@ -142,21 +142,11 @@
     private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
             "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
 
-    private static final long APP_LAUNCH_DURATION = 450;
-    // Use a shorter duration for x or y translation to create a curve effect
-    private static final long APP_LAUNCH_CURVED_DURATION = 250;
+    private static final long APP_LAUNCH_DURATION = 500;
+
     private static final long APP_LAUNCH_ALPHA_DURATION = 50;
     private static final long APP_LAUNCH_ALPHA_START_DELAY = 25;
 
-    // We scale the durations for the downward app launch animations (minus the scale animation).
-    private static final float APP_LAUNCH_DOWN_DUR_SCALE_FACTOR = 0.8f;
-    private static final long APP_LAUNCH_DOWN_DURATION =
-            (long) (APP_LAUNCH_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-    private static final long APP_LAUNCH_DOWN_CURVED_DURATION =
-            (long) (APP_LAUNCH_CURVED_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-    private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
-            (long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-
     public static final int ANIMATION_NAV_FADE_IN_DURATION = 266;
     public static final int ANIMATION_NAV_FADE_OUT_DURATION = 133;
     public static final long ANIMATION_DELAY_NAV_FADE_IN =
@@ -166,9 +156,6 @@
     public static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 1f, 1f);
 
-    private static final long CROP_DURATION = 375;
-    private static final long RADIUS_DURATION = 375;
-
     public static final int RECENTS_LAUNCH_DURATION = 336;
     private static final int LAUNCHER_RESUME_START_DELAY = 100;
     private static final int CLOSING_TRANSITION_DURATION_MS = 250;
@@ -222,6 +209,9 @@
     // Will never be larger than MAX_NUM_TASKS
     private LinkedHashMap<Integer, Pair<Integer, Integer>> mTaskStartParams;
 
+    private final Interpolator mOpeningXInterpolator;
+    private final Interpolator mOpeningInterpolator;
+
     public QuickstepTransitionManager(Context context) {
         mLauncher = Launcher.cast(Launcher.getLauncher(context));
         mDragLayer = mLauncher.getDragLayer();
@@ -248,6 +238,10 @@
             SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
                     mStartingWindowListener);
         }
+
+        mOpeningXInterpolator = AnimationUtils.loadInterpolator(context, R.interpolator.app_open_x);
+        mOpeningInterpolator = AnimationUtils.loadInterpolator(context,
+                R.interpolator.three_point_fast_out_extra_slow_in);
     }
 
     @Override
@@ -651,27 +645,29 @@
         final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
-            FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE);
+            FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
+                    mOpeningXInterpolator);
+            FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
+                    mOpeningInterpolator);
 
             FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
-                    prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
+                    prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
-                    APP_LAUNCH_ALPHA_START_DELAY, prop.alphaDuration, LINEAR);
+                    APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
 
             FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
-                    RADIUS_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
-                    APP_LAUNCH_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
 
             FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
-                    0, CROP_DURATION, EXAGGERATED_EASE);
+                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
-                    0, CROP_DURATION, EXAGGERATED_EASE);
+                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
-                    CROP_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
-                    CROP_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
 
             FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
                     NAV_FADE_OUT_INTERPOLATOR);
@@ -873,22 +869,23 @@
                     WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
                     WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
             final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
-                    0 /* start */, RADIUS_DURATION, LINEAR);
-            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, RADIUS_DURATION, LINEAR);
+                    0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator);
+            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION,
+                    mOpeningInterpolator);
 
             // Window & widget background positioning bounds
             final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
-                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_CURVED_DURATION,
-                    EXAGGERATED_EASE);
+                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION,
+                    mOpeningXInterpolator);
             final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
                     windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
             final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
                     windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
             final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
                     windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
 
             final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
                     NAV_FADE_OUT_INTERPOLATOR);
@@ -1424,10 +1421,6 @@
         public final float dX;
         public final float dY;
 
-        public final long xDuration;
-        public final long yDuration;
-        public final long alphaDuration;
-
         public final float initialAppIconScale;
         public final float finalAppIconScale;
 
@@ -1459,14 +1452,6 @@
             dX = centerX - launcherIconBounds.centerX();
             dY = centerY - launcherIconBounds.centerY();
 
-            boolean useUpwardAnimation = launcherIconBounds.top > centerY
-                    || Math.abs(dY) < dp.cellHeightPx;
-            xDuration = useUpwardAnimation ? APP_LAUNCH_CURVED_DURATION
-                    : APP_LAUNCH_DOWN_DURATION;
-            yDuration = useUpwardAnimation ? APP_LAUNCH_DURATION
-                    : APP_LAUNCH_DOWN_CURVED_DURATION;
-            alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
-                    : APP_LAUNCH_ALPHA_DOWN_DURATION;
             iconAlphaStart = hasSplashScreen && !hasDifferentAppIcon ? 0 : 1f;
 
             final int windowIconSize = ResourceUtils.getDimenByName("starting_surface_icon_size",
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
deleted file mode 100644
index 3a7d821..0000000
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.hybridhotseat;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ActivityTracker;
-
-/**
- * Proxy activity to return user to home screen and show halfsheet education
- */
-public class HotseatEduActivity extends Activity {
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(getPackageName())
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-        Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker());
-        startActivity(homeIntent);
-        finish();
-    }
-
-    static class HotseatActivityTracker<T extends QuickstepLauncher> implements
-            ActivityTracker.SchedulerCallback {
-
-        @Override
-        public boolean init(BaseActivity activity, boolean alreadyOnHome) {
-            QuickstepLauncher launcher = (QuickstepLauncher) activity;
-            if (launcher != null) {
-                launcher.getHotseatPredictionController().showEdu();
-            }
-            return false;
-        }
-
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 8c9ac12..bb58f45 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -125,6 +125,10 @@
     private WallpaperManagerCompat mWallpaperManager;
     private SurfaceControl mSurface;
     /**
+     * How visible the -1 overlay is, from 0 to 1.
+     */
+    private float mOverlayScrollProgress;
+    /**
      * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
      * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
      */
@@ -264,12 +268,24 @@
         }
     }
 
+    public void onOverlayScrollChanged(float progress) {
+        // Round out the progress to dedupe frequent, non-perceptable updates
+        int progressI = (int) (progress * 256);
+        float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f);
+        if (Float.compare(mOverlayScrollProgress, progressF) == 0) {
+            return;
+        }
+        mOverlayScrollProgress = progressF;
+        dispatchTransactionSurface(mDepth);
+    }
+
     private boolean dispatchTransactionSurface(float depth) {
         boolean supportsBlur = BlurUtils.supportsBlursOnWindows();
         if (supportsBlur && (mSurface == null || !mSurface.isValid())) {
             return false;
         }
         ensureDependencies();
+        depth = Math.max(depth, mOverlayScrollProgress);
         IBinder windowToken = mLauncher.getRootView().getWindowToken();
         if (windowToken != null) {
             mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index fd44e02..e2f198c 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -173,7 +173,9 @@
     @Override
     protected void notifyGestureAnimationStartToRecents() {
         if (mRunningOverHome) {
-            mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+            if (SysUINavigationMode.getMode(mContext).hasGestures) {
+                mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
+            }
         } else {
             super.notifyGestureAnimationStartToRecents();
         }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index db5c93c..0f5671c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -331,12 +331,14 @@
         mDeviceState = new RecentsAnimationDeviceState(this, true);
         mDisplayManager = getSystemService(DisplayManager.class);
         mTaskbarManager = new TaskbarManager(this);
-
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
-        mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
-        mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
+
+        // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
         mDeviceState.runOnUserUnlocked(this::onUserUnlocked);
         mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
+        mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
+        mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
+
         ProtoTracer.INSTANCE.get(this).add(this);
         sConnected = true;
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3887060..070714a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1729,10 +1729,10 @@
         int runningIndex = getCurrentPage();
         AnimatorSet as = new AnimatorSet();
         for (int i = 0; i < getTaskViewCount(); i++) {
-            if (runningIndex == i) {
+            View taskView = getTaskViewAt(i);
+            if (runningIndex == i && taskView.getAlpha() != 0) {
                 continue;
             }
-            View taskView = getTaskViewAt(i);
             as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
         }
         return as;
@@ -1768,8 +1768,6 @@
             // When switching to tasks in quick switch, ensures the snapped page's scroll maintain
             // invariant between quick switch and overview, to ensure a smooth animation transition.
             updateGridProperties();
-        } else if (endTarget == GestureState.GestureEndTarget.RECENTS) {
-            setEnableFreeScroll(true);
         }
     }
 
@@ -1779,7 +1777,7 @@
     public void onGestureAnimationEnd() {
         mGestureActive = false;
         if (mOrientationState.setGestureActive(false)) {
-            updateOrientationHandler();
+            updateOrientationHandler(/* forceRecreateDragLayerControllers = */ false);
         }
 
         setEnableFreeScroll(true);
@@ -2910,8 +2908,11 @@
         boolean isStartShift;
         if (midpointIndex > -1) {
             // When there is a midpoint reference task, adjacent tasks have less distance to travel
-            // to reach offscreen. Offset the task position to the task's starting point.
-            int midpointScroll = getScrollForPage(midpointIndex);
+            // 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);
+
             getPersistentChildPosition(midpointIndex, midpointScroll, taskPosition);
             float midpointStart = mOrientationHandler.getStart(taskPosition);
 
diff --git a/res/color-v31/home_settings_switch_thumb_color.xml b/res/color-v31/home_settings_switch_thumb_color.xml
new file mode 100644
index 0000000..91d3d9b
--- /dev/null
+++ b/res/color-v31/home_settings_switch_thumb_color.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 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">
+    <!-- Disabled status of thumb -->
+    <item android:state_enabled="false"
+        android:color="@color/home_settings_thumb_off_color" />
+    <!-- Toggle off status of thumb -->
+    <item android:state_checked="false"
+        android:color="@color/home_settings_thumb_off_color" />
+    <!-- Enabled or toggle on status of thumb -->
+    <item android:color="@color/home_settings_state_on_color" />
+</selector>
diff --git a/res/color-v31/home_settings_switch_track_color.xml b/res/color-v31/home_settings_switch_track_color.xml
new file mode 100644
index 0000000..50784f5
--- /dev/null
+++ b/res/color-v31/home_settings_switch_track_color.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 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">
+    <!-- Disabled status of thumb -->
+    <item android:state_enabled="false"
+        android:color="@color/home_settings_track_off_color"
+        android:alpha="?android:attr/disabledAlpha" />
+    <!-- Toggle off status of thumb -->
+    <item android:state_checked="false"
+        android:color="@color/home_settings_track_off_color" />
+    <!-- Enabled or toggle on status of thumb -->
+    <item android:color="@color/home_settings_track_on_color" />
+</selector>
diff --git a/res/drawable-v31/home_settings_switch_thumb.xml b/res/drawable-v31/home_settings_switch_thumb.xml
new file mode 100644
index 0000000..260d5ea
--- /dev/null
+++ b/res/drawable-v31/home_settings_switch_thumb.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 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.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:top="4dp"
+        android:left="4dp"
+        android:right="4dp"
+        android:bottom="4dp">
+        <shape android:shape="oval" >
+            <size android:height="20dp" android:width="20dp" />
+            <solid android:color="@color/home_settings_switch_thumb_color" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable-v31/home_settings_switch_track.xml b/res/drawable-v31/home_settings_switch_track.xml
new file mode 100644
index 0000000..502a300
--- /dev/null
+++ b/res/drawable-v31/home_settings_switch_track.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 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.
+-->
+
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle"
+    android:width="52dp"
+    android:height="28dp">
+
+    <solid android:color="@color/home_settings_switch_track_color" />
+    <corners android:radius="35dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/padded_rounded_action_button.xml b/res/drawable/padded_rounded_action_button.xml
index 6432efd..6863f92 100644
--- a/res/drawable/padded_rounded_action_button.xml
+++ b/res/drawable/padded_rounded_action_button.xml
@@ -14,18 +14,11 @@
   ~ limitations under the License.
   -->
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item
+        android:drawable="@drawable/rounded_action_button"
         android:left="@dimen/padded_rounded_button_padding"
         android:top="@dimen/padded_rounded_button_padding"
         android:right="@dimen/padded_rounded_button_padding"
-        android:bottom="@dimen/padded_rounded_button_padding">
-        <shape android:shape="rectangle">
-            <corners android:radius="@dimen/rounded_button_radius" />
-            <stroke android:width="1dp"
-                android:color="?androidprv:attr/colorAccentPrimaryVariant" />
-        </shape>
-    </item>
+        android:bottom="@dimen/padded_rounded_button_padding" />
 </layer-list>
-
diff --git a/res/drawable/rounded_action_button.xml b/res/drawable/rounded_action_button.xml
index f043893..b9942c0 100644
--- a/res/drawable/rounded_action_button.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -19,7 +19,9 @@
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle">
     <corners android:radius="@dimen/rounded_button_radius" />
-    <stroke android:width="1dp" android:color="@color/all_apps_tab_background_selected" />
+    <stroke
+        android:width="1dp"
+        android:color="?androidprv:attr/colorAccentPrimaryVariant" />
     <padding
         android:left="@dimen/rounded_button_padding"
         android:right="@dimen/rounded_button_padding" />
diff --git a/res/layout-v31/settings_activity.xml b/res/layout-v31/settings_activity.xml
new file mode 100644
index 0000000..59e14f2
--- /dev/null
+++ b/res/layout-v31/settings_activity.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 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.
+-->
+<androidx.coordinatorlayout.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/content_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+
+    <com.google.android.material.appbar.AppBarLayout
+        android:id="@+id/app_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorPrimary"
+        android:fitsSystemWindows="true"
+        android:outlineAmbientShadowColor="@android:color/transparent"
+        android:outlineSpotShadowColor="@android:color/transparent"
+        android:theme="@style/HomeSettings.CollapsingToolbar">
+
+        <com.google.android.material.appbar.CollapsingToolbarLayout
+            android:id="@+id/collapsing_toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="226dp"
+            android:clipToPadding="false"
+            app:collapsedTitleTextAppearance="@style/HomeSettings.CollapsedToolbarTitle"
+            app:contentScrim="@color/home_settings_header_collapsed"
+            app:expandedTitleMarginEnd="24dp"
+            app:expandedTitleMarginStart="24dp"
+            app:expandedTitleTextAppearance="@style/HomeSettings.ExpandedToolbarTitle"
+            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
+            app:maxLines="3"
+            app:scrimAnimationDuration="50"
+            app:scrimVisibleHeightTrigger="174dp"
+            app:statusBarScrim="@null"
+            app:titleCollapseMode="fade"
+            app:toolbarId="@id/action_bar">
+
+            <Toolbar
+                android:id="@+id/action_bar"
+                android:layout_width="match_parent"
+                android:layout_height="?attr/actionBarSize"
+                android:theme="?android:attr/actionBarTheme"
+                android:transitionName="shared_element_view"
+                app:layout_collapseMode="pin" />
+
+        </com.google.android.material.appbar.CollapsingToolbarLayout>
+    </com.google.android.material.appbar.AppBarLayout>
+
+    <FrameLayout
+        android:id="@+id/content_frame"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
+</androidx.coordinatorlayout.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml
index 9a6f8c3..88a92eb 100644
--- a/res/layout/arrow_toast.xml
+++ b/res/layout/arrow_toast.xml
@@ -27,15 +27,13 @@
         android:gravity="center"
         android:padding="16dp"
         android:background="@drawable/arrow_toast_rounded_background"
-        android:elevation="2dp"
-        android:outlineProvider="none"
+        android:elevation="@dimen/arrow_toast_elevation"
         android:textColor="@color/arrow_tip_view_content"
         android:textSize="14sp"/>
 
     <View
         android:id="@+id/arrow"
-        android:elevation="2dp"
-        android:outlineProvider="none"
+        android:elevation="@dimen/arrow_toast_elevation"
         android:layout_width="@dimen/arrow_toast_arrow_width"
         android:layout_height="10dp"/>
 </merge>
diff --git a/res/layout/notification_content.xml b/res/layout/notification_content.xml
index 84822a6..91897e9 100644
--- a/res/layout/notification_content.xml
+++ b/res/layout/notification_content.xml
@@ -14,10 +14,11 @@
      limitations under the License.
 -->
 
-<merge
+<com.android.launcher3.notification.NotificationMainView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
     <!-- header -->
     <FrameLayout
@@ -49,7 +50,7 @@
     </FrameLayout>
 
     <!-- Main view -->
-    <com.android.launcher3.notification.NotificationMainView
+    <FrameLayout
         android:id="@+id/main_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -59,7 +60,6 @@
             android:id="@+id/text_and_background"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:background="?attr/popupColorPrimary"
             android:gravity="center_vertical"
             android:orientation="vertical"
             android:paddingTop="@dimen/notification_padding"
@@ -95,5 +95,5 @@
             android:layout_marginTop="@dimen/notification_padding"
             android:layout_marginStart="@dimen/notification_icon_padding" />
 
-    </com.android.launcher3.notification.NotificationMainView>
-</merge>
\ No newline at end of file
+    </FrameLayout>
+</com.android.launcher3.notification.NotificationMainView>
\ No newline at end of file
diff --git a/res/layout/popup_container.xml b/res/layout/popup_container.xml
index 18014bb..9327287 100644
--- a/res/layout/popup_container.xml
+++ b/res/layout/popup_container.xml
@@ -31,12 +31,9 @@
         android:elevation="@dimen/deep_shortcuts_elevation"
         android:orientation="vertical"/>
 
-    <LinearLayout
+    <com.android.launcher3.notification.NotificationContainer
         android:id="@+id/notification_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:visibility="gone"
-        android:background="?attr/popupColorPrimary"
-        android:elevation="@dimen/deep_shortcuts_elevation"
-        android:orientation="vertical"/>
+        android:visibility="gone"/>
 </com.android.launcher3.popup.PopupContainerWithArrow>
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index de091c5..331d2be 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -18,7 +18,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="@dimen/bg_popup_item_width"
-    android:layout_height="@dimen/bg_popup_item_height"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/bg_popup_item_height"
     android:elevation="@dimen/deep_shortcuts_elevation"
     android:background="@drawable/middle_item_primary"
     android:theme="@style/PopupItem" >
diff --git a/res/layout/system_shortcut_content.xml b/res/layout/system_shortcut_content.xml
new file mode 100644
index 0000000..feab13d
--- /dev/null
+++ b/res/layout/system_shortcut_content.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto" >
+
+    <com.android.launcher3.BubbleTextView
+        style="@style/BaseIconUnBounded"
+        android:id="@+id/bubble_text"
+        android:background="?android:attr/selectableItemBackground"
+        android:gravity="start|center_vertical"
+        android:paddingTop="@dimen/bg_popup_item_vertical_padding"
+        android:paddingBottom="@dimen/bg_popup_item_vertical_padding"
+        android:minHeight="@dimen/bg_popup_item_height"
+        android:textAlignment="viewStart"
+        android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
+        android:paddingEnd="@dimen/popup_padding_end"
+        android:textSize="14sp"
+        android:minLines="1"
+        android:maxLines="2"
+        android:ellipsize="end"
+        android:textColor="?android:attr/textColorPrimary"
+        launcher:iconDisplay="shortcut_popup"
+        launcher:layoutHorizontal="true"
+        android:focusable="false" />
+
+    <View
+        android:id="@+id/icon"
+        android:layout_width="@dimen/system_shortcut_icon_size"
+        android:layout_height="@dimen/system_shortcut_icon_size"
+        android:layout_marginStart="@dimen/system_shortcut_margin_start"
+        android:layout_gravity="start|center_vertical"
+        android:backgroundTint="?android:attr/textColorPrimary"/>
+</merge>
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index ec34b47..79bce70 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -28,7 +28,7 @@
         android:layout_marginTop="40dp"
         android:text="@string/work_apps_paused_title"
         android:textAlignment="center"
-        android:textSize="22sp" />
+        android:textSize="18sp" />
 
     <TextView
         android:layout_width="wrap_content"
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ac77a2a..d82e92d 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -104,7 +104,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SIZE">%2$d</xliff:g> elementos)"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SIZE">%2$d</xliff:g> o más elementos)"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Fondo de pantalla y estilo"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Estilo y fondo de pantalla"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Ajustes de la pantalla de inicio"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitado por el administrador"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotación de la pantalla de inicio"</string>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
new file mode 100644
index 0000000..2c1bc90
--- /dev/null
+++ b/res/values-night-v31/colors.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+* Copyright (C) 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.
+*/
+-->
+
+<resources>
+    <color name="home_settings_header_accent">@android:color/system_accent1_100</color>
+    <color name="home_settings_header_collapsed">@android:color/system_neutral1_700</color>
+    <color name="home_settings_header_expanded">@android:color/system_neutral1_900</color>
+
+    <color name="home_settings_thumb_off_color">@android:color/system_neutral2_300</color>
+    <color name="home_settings_track_on_color">@android:color/system_accent2_700</color>
+    <color name="home_settings_track_off_color">@android:color/system_neutral1_700</color>
+</resources>
\ No newline at end of file
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index f42d214..22aa785 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -47,7 +47,7 @@
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"విడ్జెట్‌లు"</string>
     <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"సెర్చ్ చేయండి"</string>
-    <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"సెర్చ్ బాక్స్ నుండి టెక్స్ట్‌ను క్లియర్ చేయండి"</string>
+    <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"సెర్చ్ బాక్స్ నుండి టెక్స్ట్‌ను క్లియర్ చేయి"</string>
     <string name="no_widgets_available" msgid="4337693382501046170">"విడ్జెట్‌లు, షార్ట్‌కట్‌లు అందుబాటులో లేవు"</string>
     <string name="no_search_results" msgid="3787956167293097509">"విడ్జెట్‌లు లేదా షార్ట్‌కట్‌లు కనుగొనబడలేదు"</string>
     <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"వ్యక్తిగత గ్యాడ్జెట్స్"</string>
@@ -58,10 +58,10 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"విడ్జెట్ సెట్టింగ్‌లను మార్చడానికి ట్యాప్ చేయండి"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"అర్థమైంది"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"విడ్జెట్ సెట్టింగ్‌లను మార్చండి"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"యాప్‌ల కోసం సెర్చ్ చేయండి"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"అప్లికేషన్‌లను వెతకండి"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"అప్లికేషన్‌లను లోడ్ చేస్తోంది…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్‌లేవీ కనుగొనబడలేదు"</string>
-    <string name="all_apps_search_market_message" msgid="1366263386197059176">"మరిన్ని యాప్‌ల కోసం సెర్చ్ చేయండి"</string>
+    <string name="all_apps_search_market_message" msgid="1366263386197059176">"మరిన్ని యాప్‌ల కోసం వెతుకు"</string>
     <string name="label_application" msgid="8531721983832654978">"యాప్"</string>
     <string name="notifications_header" msgid="1404149926117359025">"నోటిఫికేషన్‌లు"</string>
     <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"షార్ట్‌కట్‌ను తరలించడానికి తాకి &amp; నొక్కి ఉంచు."</string>
@@ -122,7 +122,7 @@
     <string name="abandoned_clean_this" msgid="7610119707847920412">"తీసివేయి"</string>
     <string name="abandoned_search" msgid="891119232568284442">"సెర్చ్"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ఈ యాప్ ఇన్‌స్టాల్ చేయబడలేదు"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ఈ ఐకాన్‌కు చెందిన యాప్ ఇన్‌స్టాల్ చేయలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ యాప్ కోసం సెర్చ్ చేసి, దాన్ని మాన్యువల్‌గా ఇన్‌స్టాల్ చేయవచ్చు."</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ఈ చిహ్నం యొక్క యాప్ ఇన్‌స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ యాప్ కోసం శోధించి దాన్ని మాన్యువల్‌గా ఇన్‌స్టాల్ చేయవచ్చు."</string>
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>‌ను ఇన్‌స్టాల్ చేయడం, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్‌లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్‌స్టాల్ కావడానికి వేచి ఉంది"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index d73ee57..c2ebeff 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -42,6 +42,16 @@
 
     <color name="folder_dot_color">@android:color/system_accent2_50</color>
 
+    <color name="home_settings_header_accent">@android:color/system_accent1_600</color>
+    <color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
+    <color name="home_settings_header_expanded">@android:color/system_neutral1_50</color>
+
+    <color name="home_settings_state_on_color">@android:color/system_accent1_100</color>
+    <color name="home_settings_state_off_color">@android:color/system_accent2_100</color>
+    <color name="home_settings_thumb_off_color">@android:color/system_neutral2_100</color>
+    <color name="home_settings_track_on_color">@android:color/system_accent1_600</color>
+    <color name="home_settings_track_off_color">@android:color/system_neutral2_600</color>
+
     <color name="workspace_accent_color_light">@android:color/system_accent1_100</color>
     <color name="workspace_accent_color_dark">@android:color/system_accent2_600</color>
 </resources>
diff --git a/res/values-v31/config.xml b/res/values-v31/config.xml
new file mode 100644
index 0000000..afb9e6d
--- /dev/null
+++ b/res/values-v31/config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 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.
+  -->
+<resources>
+    <bool name="home_settings_icon_space_reserved">false</bool>
+    <bool name="home_settings_allow_divider">false</bool>
+</resources>
\ No newline at end of file
diff --git a/res/values-v31/styles.xml b/res/values-v31/styles.xml
new file mode 100644
index 0000000..0d2fce0
--- /dev/null
+++ b/res/values-v31/styles.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 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.
+*/
+-->
+
+<resources>
+
+    <style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
+        <item name="android:listPreferredItemPaddingEnd">16dp</item>
+        <item name="android:listPreferredItemPaddingStart">24dp</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:switchStyle">@style/HomeSettings.SwitchStyle</item>
+        <item name="android:textAppearanceListItem">@style/HomeSettings.PreferenceTitle</item>
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
+    </style>
+
+    <style name="HomeSettings.PreferenceTheme" parent="@style/PreferenceThemeOverlay">
+        <item name="preferenceCategoryStyle">@style/HomeSettings.CategoryStyle</item>
+        <item name="preferenceCategoryTitleTextAppearance">@style/HomeSettings.CategoryTitle</item>
+        <item name="preferenceFragmentCompatStyle">@style/HomeSettings.FragmentCompatStyle</item>
+        <item name="preferenceScreenStyle">@style/HomeSettings.PreferenceScreenStyle</item>
+        <item name="preferenceStyle">@style/HomeSettings.PreferenceStyle</item>
+        <item name="switchPreferenceStyle">@style/HomeSettings.SwitchPreferenceStyle</item>
+    </style>
+
+    <style name="HomeSettings.CategoryStyle" parent="@style/Preference.Category.Material">
+        <item name="allowDividerAbove">@bool/home_settings_allow_divider</item>
+        <item name="allowDividerBelow">@bool/home_settings_allow_divider</item>
+        <item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
+    </style>
+
+    <style name="HomeSettings.PreferenceStyle" parent="@style/Preference.Material">
+        <item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
+    </style>
+
+    <style name="HomeSettings.PreferenceScreenStyle"
+            parent="@style/Preference.PreferenceScreen.Material">
+        <item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
+    </style>
+
+    <style name="HomeSettings.SwitchPreferenceStyle"
+            parent="@style/Preference.SwitchPreference.Material">
+        <item name="iconSpaceReserved">@bool/home_settings_icon_space_reserved</item>
+    </style>
+
+    <style name="HomeSettings.SwitchStyle"
+            parent="@android:style/Widget.Material.CompoundButton.Switch">
+        <item name="android:switchMinWidth">52dp</item>
+        <item name="android:thumb">@drawable/home_settings_switch_thumb</item>
+        <item name="android:track">@drawable/home_settings_switch_track</item>
+    </style>
+
+    <style name="HomeSettings.PreferenceTitle"
+            parent="@android:style/TextAppearance.Material.Subhead">
+        <item name="android:fontFamily">google-sans</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="HomeSettings.CategoryTitle" parent="@android:style/TextAppearance.Material.Body2">
+        <item name="android:fontFamily">google-sans-text-medium</item>
+    </style>
+
+    <style name="HomeSettings.CollapsingToolbar" parent="@style/Theme.MaterialComponents.DayNight">
+        <item name="colorAccent">@color/home_settings_header_accent</item>
+        <item name="colorPrimary">@color/home_settings_header_expanded</item>
+        <item name="elevationOverlayColor">?attr/colorPrimary</item>
+        <item name="elevationOverlayEnabled">true</item>
+    </style>
+
+    <style name="HomeSettings.CollapsedToolbarTitle"
+            parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+        <item name="android:fontFamily">google-sans</item>
+    </style>
+
+    <style name="HomeSettings.ExpandedToolbarTitle" parent="HomeSettings.CollapsedToolbarTitle">
+        <item name="android:textSize">36sp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index 04c359e..72959b2 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -34,6 +34,9 @@
     <!-- View tag key used to determine if we should fade in the child views.. -->
     <string name="popup_container_iterate_children" translatable="false">popup_container_iterate_children</string>
 
+    <!-- config used to determine if header protection is supported in AllApps -->
+    <bool name="config_header_protection_supported">false</bool>
+
     <!-- Workspace -->
     <!-- The duration (in ms) of the fade animation on the object outlines, used when
          we are dragging objects around on the home screen. -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f434644..a1e4cd9 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -109,6 +109,7 @@
     <dimen name="all_apps_tip_bottom_margin">8dp</dimen>
     <!-- The size of corner radius of the arrow in the arrow toast. -->
     <dimen name="arrow_toast_corner_radius">2dp</dimen>
+    <dimen name="arrow_toast_elevation">2dp</dimen>
     <dimen name="arrow_toast_arrow_width">10dp</dimen>
 
 <!-- Search bar in All Apps -->
@@ -196,6 +197,7 @@
     <dimen name="drop_target_text_size">16sp</dimen>
     <dimen name="drop_target_shadow_elevation">2dp</dimen>
     <dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
+    <dimen name="drop_target_button_drawable_padding">8dp</dimen>
 
     <!-- the distance an icon must be dragged before button drop targets accept it -->
     <dimen name="drag_distanceThreshold">30dp</dimen>
@@ -241,6 +243,7 @@
     <dimen name="bg_popup_padding">2dp</dimen>
     <dimen name="bg_popup_item_width">216dp</dimen>
     <dimen name="bg_popup_item_height">56dp</dimen>
+    <dimen name="bg_popup_item_vertical_padding">12dp</dimen>
     <dimen name="pre_drag_view_scale">6dp</dimen>
     <!-- an icon with shortcuts must be dragged this far before the container is removed. -->
     <dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
@@ -271,6 +274,8 @@
 
 <!-- Notifications -->
     <dimen name="bg_round_rect_radius">8dp</dimen>
+    <dimen name="notification_max_trans">8dp</dimen>
+    <dimen name="notification_space">8dp</dimen>
     <dimen name="notification_padding">16dp</dimen>
     <dimen name="notification_padding_top">18dp</dimen>
     <dimen name="notification_header_text_size">14sp</dimen>
@@ -331,4 +336,5 @@
     <dimen name="search_row_icon_size">48dp</dimen>
     <dimen name="search_row_small_icon_size">32dp</dimen>
     <dimen name="padded_rounded_button_padding">8dp</dimen>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d30b80c..b7661b9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -147,18 +147,18 @@
     <style name="AppTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark.DarkMainColor" />
     <style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
 
-    <style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
+    <style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:navigationBarColor">?android:colorPrimaryDark</item>
         <item name="android:windowActionBar">false</item>
         <item name="android:windowNoTitle">true</item>
-        <item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
+        <item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
     </style>
 
-    <style name="HomeSettingsPreferenceTheme" parent="@style/PreferenceThemeOverlay.v14.Material">
-        <item name="preferenceFragmentCompatStyle">@style/HomeSettingsFragmentCompatStyle</item>
+    <style name="HomeSettings.PreferenceTheme" parent="@style/PreferenceThemeOverlay.v14.Material">
+        <item name="preferenceFragmentCompatStyle">@style/HomeSettings.FragmentCompatStyle</item>
     </style>
 
-    <style name="HomeSettingsFragmentCompatStyle" parent="@style/PreferenceFragment.Material">
+    <style name="HomeSettings.FragmentCompatStyle" parent="@style/PreferenceFragment.Material">
         <item name="android:layout">@layout/home_settings</item>
     </style>
 
@@ -259,7 +259,7 @@
 
     <!-- Drop targets -->
     <style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
-        <item name="android:drawablePadding">8dp</item>
+        <item name="android:drawablePadding">@dimen/drop_target_button_drawable_padding</item>
         <item name="android:padding">14dp</item>
         <item name="android:textColor">@color/drop_target_text</item>
         <item name="android:textSize">@dimen/drop_target_text_size</item>
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 61b5564..bc4c982 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -66,6 +66,8 @@
     private final int mDragDistanceThreshold;
     /** The size of the drawable shown in the drop target. */
     private final int mDrawableSize;
+    /** The padding, in pixels, between the text and drawable. */
+    private final int mDrawablePadding;
 
     protected CharSequence mText;
     protected Drawable mDrawable;
@@ -85,6 +87,8 @@
         Resources resources = getResources();
         mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
         mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_text_size);
+        mDrawablePadding = resources.getDimensionPixelSize(
+                R.dimen.drop_target_button_drawable_padding);
     }
 
     @Override
@@ -303,6 +307,8 @@
             mTextVisible = isVisible;
             setText(newText);
             setCompoundDrawablesRelative(mDrawable, null, null, null);
+            int drawablePadding = mTextVisible ? mDrawablePadding : 0;
+            setCompoundDrawablePadding(drawablePadding);
         }
     }
 
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index a4e1af6..21bc479 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -99,8 +99,18 @@
         }
     }
 
-    // inherited class can override to change the appearance of the edit text.
-    public void show() {}
+    /**
+     * Sets whether EditText background should be visible
+     * @param maxAlpha defines the maximum alpha the background should animates to
+     */
+    public void setBackgroundVisibility(boolean visible, float maxAlpha) {}
+
+    /**
+     * Returns whether a visible background is set on EditText
+     */
+    public boolean getBackgroundVisibility() {
+        return getBackground() != null;
+    }
 
     public void showKeyboard() {
         mShowImeAfterFirstLayout = !showSoftInput();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 099f256..5fb862e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -218,7 +218,8 @@
  * Default launcher application.
  */
 public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
-        Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
+        Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin>,
+        LauncherOverlayCallbacks {
     public static final String TAG = "Launcher";
 
     public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
@@ -619,7 +620,7 @@
     @Override
     public void setLauncherOverlay(LauncherOverlay overlay) {
         if (overlay != null) {
-            overlay.setOverlayCallbacks(new LauncherOverlayCallbacksImpl());
+            overlay.setOverlayCallbacks(this);
         }
         mWorkspace.setLauncherOverlay(overlay);
     }
@@ -1123,12 +1124,15 @@
         mAppWidgetHost.setActivityResumed(false);
     }
 
-    class LauncherOverlayCallbacksImpl implements LauncherOverlayCallbacks {
-
-        public void onScrollChanged(float progress) {
-            if (mWorkspace != null) {
-                mWorkspace.onOverlayScrollChanged(progress);
-            }
+    /**
+     * {@code LauncherOverlayCallbacks} scroll amount.
+     * Indicates transition progress to -1 screen.
+     * @param progress From 0 to 1.
+     */
+    @Override
+    public void onScrollChanged(float progress) {
+        if (mWorkspace != null) {
+            mWorkspace.onOverlayScrollChanged(progress);
         }
     }
 
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 519b63d..bebbf4f 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -31,7 +31,7 @@
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
 
 public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.FolderIconParent {
     static final String TAG = "ShortcutAndWidgetContainer";
@@ -104,9 +104,9 @@
 
     public void setupLp(View child) {
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-        if (child instanceof LauncherAppWidgetHostView) {
+        if (child instanceof NavigableAppWidgetHostView) {
             DeviceProfile profile = mActivity.getDeviceProfile();
-            ((LauncherAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
+            ((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
                     profile.appWidgetScale.x, profile.appWidgetScale.y, mBorderSpacing, mTempRect);
         } else {
@@ -129,8 +129,8 @@
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
         final DeviceProfile dp = mActivity.getDeviceProfile();
 
-        if (child instanceof LauncherAppWidgetHostView) {
-            ((LauncherAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
+        if (child instanceof NavigableAppWidgetHostView) {
+            ((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
             lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
                     dp.appWidgetScale.x, dp.appWidgetScale.y, mBorderSpacing, mTempRect);
         } else {
@@ -178,16 +178,16 @@
      */
     public void layoutChild(View child) {
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-        if (child instanceof LauncherAppWidgetHostView) {
-            LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
+        if (child instanceof NavigableAppWidgetHostView) {
+            NavigableAppWidgetHostView nahv = (NavigableAppWidgetHostView) child;
 
             // Scale and center the widget to fit within its cells.
             DeviceProfile profile = mActivity.getDeviceProfile();
             float scaleX = profile.appWidgetScale.x;
             float scaleY = profile.appWidgetScale.y;
 
-            lahv.setScaleToFit(Math.min(scaleX, scaleY));
-            lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
+            nahv.setScaleToFit(Math.min(scaleX, scaleY));
+            nahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
                     -(lp.height - (lp.height * scaleY)) / 2.0f);
         }
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 5bdc402..2bb4e5c 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -687,8 +687,9 @@
         CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);
 
         // If the final screen is empty, convert it to the extra empty screen
-        if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&
-                !finalScreen.isDropPending()) {
+        if (finalScreen != null
+                && finalScreen.getShortcutsAndWidgets().getChildCount() == 0
+                && !finalScreen.isDropPending()) {
             mWorkspaceScreens.remove(finalScreenId);
             mScreenOrder.removeValue(finalScreenId);
 
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index f420ec2..57a3e1c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
@@ -118,7 +119,7 @@
     private SpannableStringBuilder mSearchQueryBuilder = null;
 
     protected boolean mUsingTabs;
-    private boolean mSearchModeWhileUsingTabs = false;
+    private boolean mIsSearching;
 
     protected RecyclerViewFastScroller mTouchHandler;
     protected final Point mFastScrollerOffset = new Point();
@@ -132,6 +133,7 @@
     private final float mHeaderThreshold;
     private ScrimView mScrimView;
     private int mHeaderColor;
+    private int mTabsProtectionAlpha;
 
     public AllAppsContainerView(Context context) {
         this(context, null);
@@ -454,7 +456,6 @@
         mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
 
         if (mUsingTabs) {
-            setupWorkToggle();
             mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
             mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
             mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
@@ -485,6 +486,7 @@
     }
 
     private void setupWorkToggle() {
+        removeWorkToggle();
         if (Utilities.ATLEAST_P) {
             mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
                     R.layout.work_mode_fab, this, false);
@@ -497,6 +499,14 @@
         }
     }
 
+    private void removeWorkToggle() {
+        if (mWorkModeSwitch == null) return;
+        if (mWorkModeSwitch.getParent() == this) {
+            this.removeView(mWorkModeSwitch);
+        }
+        mWorkModeSwitch = null;
+    }
+
     private void replaceRVContainer(boolean showTabs) {
         for (int i = 0; i < mAH.length; i++) {
             AllAppsRecyclerView rv = mAH[i].recyclerView;
@@ -519,8 +529,10 @@
             mViewPager = (AllAppsPagedView) newView;
             mViewPager.initParentViews(this);
             mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
+            setupWorkToggle();
         } else {
             mViewPager = null;
+            removeWorkToggle();
         }
     }
 
@@ -539,14 +551,6 @@
             mWorkModeSwitch.setWorkTabVisible(currentActivePage == AdapterHolder.WORK
                     && mAllAppsStore.hasModelFlag(
                     FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION));
-
-            if (currentActivePage == AdapterHolder.WORK) {
-                if (mWorkModeSwitch.getParent() == null) {
-                    addView(mWorkModeSwitch);
-                }
-            } else {
-                removeView(mWorkModeSwitch);
-            }
         }
     }
 
@@ -623,18 +627,19 @@
         for (int i = 0; i < mAH.length; i++) {
             mAH[i].adapter.setLastSearchQuery(query);
         }
+        mIsSearching = true;
         if (mUsingTabs) {
-            mSearchModeWhileUsingTabs = true;
             rebindAdapters(false); // hide tabs
         }
         mHeader.setCollapsed(true);
     }
 
     public void onClearSearchResult() {
-        if (mSearchModeWhileUsingTabs) {
+        if (mUsingTabs) {
             rebindAdapters(true); // show tabs
-            mSearchModeWhileUsingTabs = false;
         }
+        mIsSearching = false;
+        getActiveRecyclerView().scrollToTop();
     }
 
     public void onSearchResultsChanged() {
@@ -708,13 +713,12 @@
         mHeaderPaint.setColor(mHeaderColor);
         mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor)));
         if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) {
-            int bottom = mUsingTabs && mHeader.mHeaderCollapsed ? mHeader.getVisibleBottomBound()
-                    : mSearchContainer.getBottom();
-            canvas.drawRect(0, 0, canvas.getWidth(), bottom + getTranslationY(),
-                    mHeaderPaint);
-
-            if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && getTranslationY() == 0) {
-                mSearchUiManager.getEditText().setBackground(null);
+            int bottom = (int) (mSearchContainer.getBottom() + getTranslationY());
+            canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint);
+            int tabsHeight = getFloatingHeaderView().getPeripheralProtectionHeight();
+            if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
+                mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha));
+                canvas.drawRect(0, bottom, canvas.getWidth(), bottom + tabsHeight, mHeaderPaint);
             }
         }
     }
@@ -794,18 +798,29 @@
 
 
     protected void updateHeaderScroll(int scrolledOffset) {
-        float prog = Math.max(0, Math.min(1, (float) scrolledOffset / mHeaderThreshold));
+
+        float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
         int viewBG = ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, prog);
         int headerColor = ColorUtils.setAlphaComponent(viewBG,
                 (int) (getSearchView().getAlpha() * 255));
-        if (headerColor != mHeaderColor) {
+        int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
+                : (int) (Utilities.boundToRange(
+                        (scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
+                        * 255);
+        if (headerColor != mHeaderColor || mTabsProtectionAlpha != tabsAlpha) {
             mHeaderColor = headerColor;
-            getSearchView().setBackgroundColor(viewBG);
-            getFloatingHeaderView().setHeaderColor(viewBG);
+            mTabsProtectionAlpha = tabsAlpha;
             invalidateHeader();
-            if (scrolledOffset == 0 && mSearchUiManager.getEditText() != null) {
-                mSearchUiManager.getEditText().show();
+        }
+        if (mSearchUiManager.getEditText() != null) {
+            ExtendedEditText editText = mSearchUiManager.getEditText();
+            boolean bgVisible = editText.getBackgroundVisibility();
+            if (scrolledOffset == 0 && !mIsSearching) {
+                bgVisible = true;
+            } else if (scrolledOffset > mHeaderThreshold) {
+                bgVisible = false;
             }
+            editText.setBackgroundVisibility(bgVisible, 1 - prog);
         }
     }
 
@@ -813,7 +828,7 @@
      * redraws header protection
      */
     public void invalidateHeader() {
-        if (mScrimView != null && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+        if (mScrimView != null && mHeader.isHeaderProtectionSupported()) {
             mScrimView.invalidate();
         }
     }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 8ea83d5..debb5b2 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -17,9 +17,6 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.ArrayMap;
@@ -50,11 +47,10 @@
         ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
         OnHeightUpdatedListener {
 
-    private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
+    private final Rect mRVClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
+    private final Rect mHeaderClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
     private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
-    private final ValueAnimator mHeaderAnimator = ValueAnimator.ofInt(0, 1).setDuration(100);
     private final Point mTempOffset = new Point();
-    private final Paint mBGPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final RecyclerView.OnScrollListener mOnScrollListener =
             new RecyclerView.OnScrollListener() {
                 @Override
@@ -82,19 +78,19 @@
                 }
             };
 
-    private final int mHeaderTopPadding;
-
     protected final Map<AllAppsRow, PluginHeaderRow> mPluginRows = new ArrayMap<>();
 
+    private final int mHeaderTopPadding;
+    private final boolean mHeaderProtectionSupported;
+
     protected ViewGroup mTabLayout;
     private AllAppsRecyclerView mMainRV;
     private AllAppsRecyclerView mWorkRV;
     private AllAppsRecyclerView mCurrentRV;
     private ViewGroup mParent;
     public boolean mHeaderCollapsed;
-    private int mSnappedScrolledY;
+    protected int mSnappedScrolledY;
     private int mTranslationY;
-    private int mHeaderColor;
 
     private boolean mForwardToRecyclerView;
 
@@ -120,6 +116,8 @@
         super(context, attrs);
         mHeaderTopPadding = context.getResources()
                 .getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
+        mHeaderProtectionSupported = context.getResources().getBoolean(
+                R.bool.config_header_protection_supported);
     }
 
     @Override
@@ -138,7 +136,6 @@
         }
         mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]);
         mAllRows = mFixedRows;
-        mHeaderAnimator.addUpdateListener(valueAnimator -> invalidate());
     }
 
     @Override
@@ -285,7 +282,7 @@
                 mHeaderCollapsed = false;
             }
             mTranslationY = currentScrollY;
-        } else if (!mHeaderCollapsed) {
+        } else {
             mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
 
             // update state vars
@@ -295,31 +292,10 @@
             } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
                 mHeaderCollapsed = true;
                 mSnappedScrolledY = -mMaxTranslation;
-                mHeaderAnimator.setCurrentFraction(0);
-                mHeaderAnimator.start();
             }
         }
     }
 
-    /**
-     * Set current header protection background color
-     */
-    public void setHeaderColor(int color) {
-        mHeaderColor = color;
-        invalidate();
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (mHeaderCollapsed && !mCollapsed && mTabLayout.getVisibility() == VISIBLE
-                && mHeaderColor != Color.TRANSPARENT && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-            mBGPaint.setColor(mHeaderColor);
-            mBGPaint.setAlpha((int) (255 * mHeaderAnimator.getAnimatedFraction()));
-            canvas.drawRect(0, 0, getWidth(), getHeight() + mTranslationY, mBGPaint);
-        }
-        super.dispatchDraw(canvas);
-    }
-
     protected void applyVerticalMove() {
         int uncappedTranslationY = mTranslationY;
         mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
@@ -336,11 +312,15 @@
         }
 
         mTabLayout.setTranslationY(mTranslationY);
-        mClip.top = mMaxTranslation + mTranslationY;
+
+        int clipHeight = mHeaderTopPadding - getPaddingBottom();
+        mRVClip.top = mTabsHidden ? clipHeight : 0;
+        mHeaderClip.top = clipHeight;
         // clipping on a draw might cause additional redraw
-        mMainRV.setClipBounds(mClip);
+        setClipBounds(mHeaderClip);
+        mMainRV.setClipBounds(mRVClip);
         if (mWorkRV != null) {
-            mWorkRV.setClipBounds(mClip);
+            mWorkRV.setClipBounds(mRVClip);
         }
     }
 
@@ -421,6 +401,10 @@
         return false;
     }
 
+    public boolean isHeaderProtectionSupported() {
+        return mHeaderProtectionSupported;
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
         return false;
@@ -444,10 +428,19 @@
     }
 
     /**
-     * Returns visible height of FloatingHeaderView contents
+     * Returns visible height of FloatingHeaderView contents requiring header protection
      */
-    public int getVisibleBottomBound() {
-        return getBottom() + mTranslationY;
+    public int getPeripheralProtectionHeight() {
+        if (!mHeaderProtectionSupported) {
+            return 0;
+        }
+
+        // we only want to show protection when work tab is available and header is either
+        // collapsed or animating to/from collapsed state
+        if (mTabsHidden || !mHeaderCollapsed) {
+            return 0;
+        }
+        return Math.max(getHeight() - getPaddingTop() + mTranslationY, 0);
     }
 }
 
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index a800d34..5d3af08 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -51,6 +51,7 @@
 
     @Nullable
     private KeyboardInsetAnimationCallback mKeyboardInsetAnimationCallback;
+    private boolean mWorkTabVisible;
 
     public WorkModeSwitch(Context context) {
         this(context, null, 0);
@@ -91,11 +92,10 @@
      */
     public void setWorkTabVisible(boolean workTabVisible) {
         clearAnimation();
-        if (workTabVisible) {
+        mWorkTabVisible = workTabVisible;
+        if (workTabVisible && mWorkEnabled) {
             setEnabled(true);
-            if (mWorkEnabled) {
-                setVisibility(VISIBLE);
-            }
+            setVisibility(VISIBLE);
             setAlpha(0);
             animate().alpha(1).start();
         } else {
@@ -105,7 +105,7 @@
 
     @Override
     public void onClick(View view) {
-        if (Utilities.ATLEAST_P) {
+        if (Utilities.ATLEAST_P && mWorkTabVisible) {
             setEnabled(false);
             Launcher.fromContext(getContext()).getStatsLogManager().logger().log(
                     LAUNCHER_TURN_OFF_WORK_APPS_TAP);
@@ -137,7 +137,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        if (Utilities.ATLEAST_R) {
+        if (Utilities.ATLEAST_R && mWorkTabVisible) {
             setTranslationY(0);
             if (insets.isVisible(WindowInsets.Type.ime())) {
                 Insets keyboardInsets = insets.getInsets(WindowInsets.Type.ime());
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 79718fb..0137e2a 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -18,8 +18,10 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_FOCUSED_ITEM_SELECTED_WITH_IME;
 
 import android.text.Editable;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.text.style.SuggestionSpan;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
@@ -47,6 +49,7 @@
     protected SearchCallback<AdapterItem> mCallback;
     protected ExtendedEditText mInput;
     protected String mQuery;
+    private String[] mTextConversions;
 
     protected SearchAlgorithm<AdapterItem> mSearchAlgorithm;
 
@@ -78,7 +81,20 @@
 
     @Override
     public void onTextChanged(CharSequence s, int start, int before, int count) {
-        // Do nothing
+        mTextConversions = extractTextConversions(s);
+    }
+
+    private static String[] extractTextConversions(CharSequence text) {
+        if (text instanceof SpannableStringBuilder) {
+            SpannableStringBuilder spanned = (SpannableStringBuilder) text;
+            SuggestionSpan[] suggestionSpans =
+                spanned.getSpans(0, text.length(), SuggestionSpan.class);
+            if (suggestionSpans != null && suggestionSpans.length > 0) {
+                spanned.removeSpan(suggestionSpans[0]);
+                return suggestionSpans[0].getSuggestions();
+            }
+        }
+        return null;
     }
 
     @Override
@@ -89,7 +105,7 @@
             mCallback.clearSearchResult();
         } else {
             mSearchAlgorithm.cancel(false);
-            mSearchAlgorithm.doSearch(mQuery, mCallback);
+            mSearchAlgorithm.doSearch(mQuery, mTextConversions, mCallback);
         }
     }
 
@@ -154,4 +170,4 @@
     public boolean isSearchFieldFocused() {
         return mInput.isFocused();
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index f066dc1..e0769db 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -181,7 +181,7 @@
                     + "Ignored if ENABLE_SMARTSPACE_UNIVERSAL is enabled.");
 
     public static final BooleanFlag ENABLE_SMARTSPACE_FEEDBACK = getDebugFlag(
-            "ENABLE_SMARTSPACE_FEEDBACK", true,
+            "ENABLE_SMARTSPACE_FEEDBACK", false,
             "Adds a menu option to send feedback for Enhanced Smartspace.");
 
     public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(
@@ -254,6 +254,10 @@
             "ENABLE_WALLPAPER_SCRIM", false,
             "Enables scrim over wallpaper for text protection.");
 
+    public static final BooleanFlag WIDGETS_IN_LAUNCHER_PREVIEW = getDebugFlag(
+            "WIDGETS_IN_LAUNCHER_PREVIEW", true,
+            "Enables widgets in Launcher preview for the Wallpaper app.");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 7a31ea0..fb25954 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -29,6 +29,7 @@
 import android.app.Fragment;
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
+import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
@@ -87,8 +88,11 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.LocalColorExtractor;
+import com.android.launcher3.widget.NavigableAppWidgetHostView;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.util.ArrayList;
@@ -207,6 +211,7 @@
     private final Hotseat mHotseat;
     private final CellLayout mWorkspace;
     private final SparseIntArray mWallpaperColorResources;
+    private final AppWidgetHost mAppWidgetHost;
 
     public LauncherPreviewRenderer(Context context,
             InvariantDeviceProfile idp,
@@ -273,6 +278,9 @@
         } else {
             mWallpaperColorResources = null;
         }
+        mAppWidgetHost = FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()
+                ? new LauncherPreviewAppWidgetHost(context)
+                : null;
     }
 
     /** Populate preview and render it. */
@@ -372,9 +380,20 @@
 
     private void inflateAndAddWidgets(
             LauncherAppWidgetInfo info, LauncherAppWidgetProviderInfo providerInfo) {
-        AppWidgetHostView view = new AppWidgetHostView(mContext);
-        view.setAppWidget(-1, providerInfo);
-        view.updateAppWidget(null);
+        AppWidgetHostView view;
+        if (FeatureFlags.WIDGETS_IN_LAUNCHER_PREVIEW.get()) {
+            view = mAppWidgetHost.createView(mContext, info.appWidgetId, providerInfo);
+        } else {
+            view = new NavigableAppWidgetHostView(this) {
+                @Override
+                protected boolean shouldAllowDirectClick() {
+                    return false;
+                }
+            };
+            view.setAppWidget(-1, providerInfo);
+            view.updateAppWidget(null);
+        }
+
         view.setTag(info);
 
         if (mWallpaperColorResources != null) {
@@ -504,4 +523,31 @@
             return true;
         }
     }
+
+    private class LauncherPreviewAppWidgetHost extends AppWidgetHost {
+
+        private LauncherPreviewAppWidgetHost(Context context) {
+            super(context, LauncherAppWidgetHost.APPWIDGET_HOST_ID);
+        }
+
+        @Override
+        protected AppWidgetHostView onCreateView(
+                Context context,
+                int appWidgetId,
+                AppWidgetProviderInfo appWidget) {
+            return new LauncherPreviewAppWidgetHostView(LauncherPreviewRenderer.this);
+        }
+    }
+
+    private static class LauncherPreviewAppWidgetHostView extends BaseLauncherAppWidgetHostView {
+
+        private LauncherPreviewAppWidgetHostView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected boolean shouldAllowDirectClick() {
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 9889a80..b74d0fc 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -21,7 +21,6 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.InstantAppResolver;
@@ -73,13 +72,7 @@
             dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
                 if (si.hasPromiseIconUi()
                         && mInstallInfo.packageName.equals(si.getTargetPackage())) {
-                    int installProgress = mInstallInfo.progress;
-
-                    si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
-                    if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
-                        // Mark this info as broken.
-                        si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                    }
+                    si.setProgressLevel(mInstallInfo);
                     updates.add(si);
                 }
             });
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 6813b97..a74c02f 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -24,6 +24,7 @@
 
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.util.PackageManagerHelper;
 
@@ -179,6 +180,12 @@
      */
     public void setProgressLevel(PackageInstallInfo installInfo) {
         setProgressLevel(installInfo.progress, installInfo.state);
+
+        if (installInfo.state == PackageInstallInfo.STATUS_FAILED) {
+            FileLog.d(TAG,
+                    "Icon info: " + this + " marked broken with install info: " + installInfo,
+                    new Exception());
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/notification/NotificationContainer.java b/src/com/android/launcher3/notification/NotificationContainer.java
new file mode 100644
index 0000000..9eb05cd
--- /dev/null
+++ b/src/com/android/launcher3/notification/NotificationContainer.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 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.
+ */
+package com.android.launcher3.notification;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.touch.BaseSwipeDetector;
+import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Class to manage the notification UI in a {@link PopupContainerWithArrow}.
+ *
+ * - Has two {@link NotificationMainView} that represent the top two notifications
+ * - Handles dismissing a notification
+ */
+public class NotificationContainer extends FrameLayout implements SingleAxisSwipeDetector.Listener {
+
+    private static final FloatProperty<NotificationContainer> DRAG_TRANSLATION_X =
+            new FloatProperty<NotificationContainer>("notificationProgress") {
+                @Override
+                public void setValue(NotificationContainer view, float transX) {
+                    view.setDragTranslationX(transX);
+                }
+
+                @Override
+                public Float get(NotificationContainer view) {
+                    return view.mDragTranslationX;
+                }
+            };
+
+    private static final Rect sTempRect = new Rect();
+
+    private final SingleAxisSwipeDetector mSwipeDetector;
+    private final List<NotificationInfo> mNotificationInfos = new ArrayList<>();
+    private boolean mIgnoreTouch = false;
+
+    private final ObjectAnimator mContentTranslateAnimator;
+    private float mDragTranslationX = 0;
+
+    private final NotificationMainView mPrimaryView;
+    private final NotificationMainView mSecondaryView;
+    private PopupContainerWithArrow mPopupContainer;
+
+    public NotificationContainer(Context context) {
+        this(context, null, 0);
+    }
+
+    public NotificationContainer(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mSwipeDetector = new SingleAxisSwipeDetector(getContext(), this, HORIZONTAL);
+        mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_BOTH, false);
+        mContentTranslateAnimator = ObjectAnimator.ofFloat(this, DRAG_TRANSLATION_X, 0);
+
+        mPrimaryView = (NotificationMainView) View.inflate(getContext(),
+                R.layout.notification_content, null);
+        mSecondaryView = (NotificationMainView) View.inflate(getContext(),
+                R.layout.notification_content, null);
+        mSecondaryView.setAlpha(0);
+
+        addView(mSecondaryView);
+        addView(mPrimaryView);
+
+    }
+
+    public void setPopupView(PopupContainerWithArrow popupView) {
+        mPopupContainer = popupView;
+    }
+
+    /**
+     * Returns true if we should intercept the swipe.
+     */
+    public boolean onInterceptSwipeEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            sTempRect.set(getLeft(), getTop(), getRight(), getBottom());
+            mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
+            if (!mIgnoreTouch) {
+                mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true);
+            }
+        }
+        if (mIgnoreTouch) {
+            return false;
+        }
+        if (mPrimaryView.getNotificationInfo() == null) {
+            // The notification hasn't been populated yet.
+            return false;
+        }
+
+        mSwipeDetector.onTouchEvent(ev);
+        return mSwipeDetector.isDraggingOrSettling();
+    }
+
+    /**
+     * Returns true when we should handle the swipe.
+     */
+    public boolean onSwipeEvent(MotionEvent ev) {
+        if (mIgnoreTouch) {
+            return false;
+        }
+        if (mPrimaryView.getNotificationInfo() == null) {
+            // The notification hasn't been populated yet.
+            return false;
+        }
+        return mSwipeDetector.onTouchEvent(ev);
+    }
+
+    /**
+     * Applies the list of @param notificationInfos to this container.
+     */
+    public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
+        mNotificationInfos.clear();
+        if (notificationInfos.isEmpty()) {
+            mPrimaryView.applyNotificationInfo(null);
+            mSecondaryView.applyNotificationInfo(null);
+            return;
+        }
+        mNotificationInfos.addAll(notificationInfos);
+
+        NotificationInfo mainNotification = notificationInfos.get(0);
+        mPrimaryView.applyNotificationInfo(mainNotification);
+        mSecondaryView.applyNotificationInfo(notificationInfos.size() > 1
+                ? notificationInfos.get(1)
+                : null);
+    }
+
+    /**
+     * Trims the notifications.
+     * @param notificationKeys List of all valid notification keys.
+     */
+    public void trimNotifications(final List<String> notificationKeys) {
+        Iterator<NotificationInfo> iterator = mNotificationInfos.iterator();
+        while (iterator.hasNext()) {
+            if (!notificationKeys.contains(iterator.next().notificationKey)) {
+                iterator.remove();
+            }
+        }
+
+        NotificationInfo primaryInfo = mNotificationInfos.size() > 0
+                ? mNotificationInfos.get(0)
+                : null;
+        NotificationInfo secondaryInfo = mNotificationInfos.size() > 1
+                ? mNotificationInfos.get(1)
+                : null;
+
+        mPrimaryView.applyNotificationInfo(primaryInfo);
+        mSecondaryView.applyNotificationInfo(secondaryInfo);
+
+        mPrimaryView.onPrimaryDrag(0);
+        mSecondaryView.onSecondaryDrag(0);
+    }
+
+    private void setDragTranslationX(float translationX) {
+        mDragTranslationX = translationX;
+
+        float progress = translationX / getWidth();
+        mPrimaryView.onPrimaryDrag(progress);
+        if (mSecondaryView.getNotificationInfo() == null) {
+            mSecondaryView.setAlpha(0f);
+        } else {
+            mSecondaryView.onSecondaryDrag(progress);
+        }
+    }
+
+    // SingleAxisSwipeDetector.Listener's
+    @Override
+    public void onDragStart(boolean start, float startDisplacement) {
+        mPopupContainer.showArrow(false);
+    }
+
+    @Override
+    public boolean onDrag(float displacement) {
+        if (!mPrimaryView.canChildBeDismissed()) {
+            displacement = OverScroll.dampedScroll(displacement, getWidth());
+        }
+
+        float progress = displacement / getWidth();
+        mPrimaryView.onPrimaryDrag(progress);
+        if (mSecondaryView.getNotificationInfo() == null) {
+            mSecondaryView.setAlpha(0f);
+        } else {
+            mSecondaryView.onSecondaryDrag(progress);
+        }
+        mContentTranslateAnimator.cancel();
+        return true;
+    }
+
+    @Override
+    public void onDragEnd(float velocity) {
+        final boolean willExit;
+        final float endTranslation;
+        final float startTranslation = mPrimaryView.getTranslationX();
+        final float width = getWidth();
+
+        if (!mPrimaryView.canChildBeDismissed()) {
+            willExit = false;
+            endTranslation = 0;
+        } else if (mSwipeDetector.isFling(velocity)) {
+            willExit = true;
+            endTranslation = velocity < 0 ? -width : width;
+        } else if (Math.abs(startTranslation) > width / 2f) {
+            willExit = true;
+            endTranslation = (startTranslation < 0 ? -width : width);
+        } else {
+            willExit = false;
+            endTranslation = 0;
+        }
+
+        long duration = BaseSwipeDetector.calculateDuration(velocity,
+                (endTranslation - startTranslation) / width);
+
+        mContentTranslateAnimator.removeAllListeners();
+        mContentTranslateAnimator.setDuration(duration)
+                .setInterpolator(scrollInterpolatorForVelocity(velocity));
+        mContentTranslateAnimator.setFloatValues(startTranslation, endTranslation);
+
+        NotificationMainView current = mPrimaryView;
+        mContentTranslateAnimator.addListener(new AnimationSuccessListener() {
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                mSwipeDetector.finishedScrolling();
+                if (willExit) {
+                    current.onChildDismissed();
+                }
+                mPopupContainer.showArrow(true);
+            }
+        });
+        mContentTranslateAnimator.start();
+    }
+
+    /**
+     * Animates the background color to a new color.
+     * @param color The color to change to.
+     * @param animatorSetOut The AnimatorSet where we add the color animator to.
+     */
+    public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
+        mPrimaryView.updateBackgroundColor(color, animatorSetOut);
+        mSecondaryView.updateBackgroundColor(color, animatorSetOut);
+    }
+
+    /**
+     * Updates the header with a new @param notificationCount.
+     */
+    public void updateHeader(int notificationCount) {
+        mPrimaryView.updateHeader(notificationCount);
+        mSecondaryView.updateHeader(notificationCount - 1);
+    }
+}
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
deleted file mode 100644
index af943a6..0000000
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2017 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.notification;
-
-import android.animation.AnimatorSet;
-import android.content.Context;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.ViewOutlineProvider;
-import android.widget.TextView;
-
-import com.android.launcher3.R;
-import com.android.launcher3.popup.PopupContainerWithArrow;
-import com.android.launcher3.util.Themes;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Utility class to manage notification UI
- */
-public class NotificationItemView {
-
-    private static final Rect sTempRect = new Rect();
-
-    private final Context mContext;
-    private final PopupContainerWithArrow mPopupContainer;
-    private final ViewGroup mRootView;
-
-    private final TextView mHeaderCount;
-    private final NotificationMainView mMainView;
-
-    private final View mHeader;
-
-    private View mGutter;
-
-    private boolean mIgnoreTouch = false;
-    private List<NotificationInfo> mNotificationInfos = new ArrayList<>();
-
-    public NotificationItemView(PopupContainerWithArrow container, ViewGroup rootView) {
-        mPopupContainer = container;
-        mRootView = rootView;
-        mContext = container.getContext();
-
-        mHeaderCount = container.findViewById(R.id.notification_count);
-        mMainView = container.findViewById(R.id.main_view);
-
-        mHeader = container.findViewById(R.id.header);
-
-        float radius = Themes.getDialogCornerRadius(mContext);
-        rootView.setClipToOutline(true);
-        rootView.setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), radius);
-            }
-        });
-    }
-
-    /**
-     * Animates the background color to a new color.
-     * @param color The color to change to.
-     * @param animatorSetOut The AnimatorSet where we add the color animator to.
-     */
-    public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
-        mMainView.updateBackgroundColor(color, animatorSetOut);
-    }
-
-    public void addGutter() {
-        if (mGutter == null) {
-            mGutter = mPopupContainer.inflateAndAdd(R.layout.notification_gutter, mRootView);
-        }
-    }
-
-    public void inverseGutterMargin() {
-        MarginLayoutParams lp = (MarginLayoutParams) mGutter.getLayoutParams();
-        int top = lp.topMargin;
-        lp.topMargin = lp.bottomMargin;
-        lp.bottomMargin = top;
-    }
-
-    public void removeAllViews() {
-        mRootView.removeView(mMainView);
-        mRootView.removeView(mHeader);
-        if (mGutter != null) {
-            mRootView.removeView(mGutter);
-        }
-    }
-
-    /**
-     * Updates the header text.
-     * @param notificationCount The number of notifications.
-     */
-    public void updateHeader(int notificationCount) {
-        final String text;
-        final int visibility;
-        if (notificationCount <= 1) {
-            text = "";
-            visibility = View.INVISIBLE;
-        } else {
-            text = String.valueOf(notificationCount);
-            visibility = View.VISIBLE;
-
-        }
-        mHeaderCount.setText(text);
-        mHeaderCount.setVisibility(visibility);
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            sTempRect.set(mRootView.getLeft(), mRootView.getTop(),
-                    mRootView.getRight(), mRootView.getBottom());
-            mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
-            if (!mIgnoreTouch) {
-                mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true);
-            }
-        }
-        if (mIgnoreTouch) {
-            return false;
-        }
-        if (mMainView.getNotificationInfo() == null) {
-            // The notification hasn't been populated yet.
-            return false;
-        }
-
-        return false;
-    }
-
-    public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
-        mNotificationInfos.clear();
-        if (notificationInfos.isEmpty()) {
-            return;
-        }
-        mNotificationInfos.addAll(notificationInfos);
-
-        NotificationInfo mainNotification = notificationInfos.get(0);
-        mMainView.applyNotificationInfo(mainNotification, false);
-    }
-
-    public void trimNotifications(final List<String> notificationKeys) {
-        NotificationInfo currentMainNotificationInfo = mMainView.getNotificationInfo();
-        boolean shouldUpdateMainNotification = !notificationKeys.contains(
-                currentMainNotificationInfo.notificationKey);
-
-        if (shouldUpdateMainNotification) {
-            int size = notificationKeys.size();
-            NotificationInfo nextNotification = null;
-            // We get the latest notification by finding the notification after the one that was
-            // just dismissed.
-            for (int i = 0; i < size; ++i) {
-                if (currentMainNotificationInfo == mNotificationInfos.get(i) && i + 1 < size) {
-                    nextNotification = mNotificationInfos.get(i + 1);
-                    break;
-                }
-            }
-            if (nextNotification != null) {
-                mMainView.applyNotificationInfo(nextNotification, true);
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index b8aa824..f9ff8a6 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -16,62 +16,70 @@
 
 package com.android.launcher3.notification;
 
+import static com.android.launcher3.Utilities.mapToRange;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED;
 
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.graphics.drawable.GradientDrawable;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.util.FloatProperty;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.FrameLayout;
+import android.view.ViewOutlineProvider;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.util.Themes;
 
 /**
  * A {@link android.widget.FrameLayout} that contains a single notification,
  * e.g. icon + title + text.
  */
 @TargetApi(Build.VERSION_CODES.N)
-public class NotificationMainView extends FrameLayout {
-
-    private static final FloatProperty<NotificationMainView> CONTENT_TRANSLATION =
-            new FloatProperty<NotificationMainView>("contentTranslation") {
-        @Override
-        public void setValue(NotificationMainView view, float v) {
-            view.setContentTranslation(v);
-        }
-
-        @Override
-        public Float get(NotificationMainView view) {
-            return view.mTextAndBackground.getTranslationX();
-        }
-    };
+public class NotificationMainView extends LinearLayout {
 
     // This is used only to track the notification view, so that it can be properly logged.
     public static final ItemInfo NOTIFICATION_ITEM_INFO = new ItemInfo();
 
+    // Value when the primary notification main view will be gone (zero alpha).
+    private static final float PRIMARY_GONE_PROGRESS = 0.7f;
+    private static final float PRIMARY_MIN_PROGRESS = 0.40f;
+    private static final float PRIMARY_MAX_PROGRESS = 0.60f;
+    private static final float SECONDARY_MIN_PROGRESS = 0.30f;
+    private static final float SECONDARY_MAX_PROGRESS = 0.50f;
+    private static final float SECONDARY_CONTENT_MAX_PROGRESS = 0.6f;
+
     private NotificationInfo mNotificationInfo;
-    private ViewGroup mTextAndBackground;
     private int mBackgroundColor;
     private TextView mTitleView;
     private TextView mTextView;
     private View mIconView;
 
-    private SingleAxisSwipeDetector mSwipeDetector;
+    private View mHeader;
+    private View mMainView;
 
-    private final ColorDrawable mColorDrawable;
+    private TextView mHeaderCount;
+    private final Rect mOutline = new Rect();
+
+    // Space between notifications during swipe
+    private final int mNotificationSpace;
+    private final int mMaxTransX;
+    private final int mMaxElevation;
+
+    private final GradientDrawable mBackground;
 
     public NotificationMainView(Context context) {
         this(context, null, 0);
@@ -82,28 +90,77 @@
     }
 
     public NotificationMainView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
+        this(context, attrs, defStyle, 0);
+    }
 
-        mColorDrawable = new ColorDrawable(Color.TRANSPARENT);
+    public NotificationMainView(Context context, AttributeSet attrs, int defStyle, int defStylRes) {
+        super(context, attrs, defStyle, defStylRes);
+
+        float outlineRadius = Themes.getDialogCornerRadius(context);
+
+        mBackground = new GradientDrawable();
+        mBackground.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary));
+        mBackground.setCornerRadius(outlineRadius);
+        setBackground(mBackground);
+
+        mMaxElevation = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_elevation);
+        setElevation(mMaxElevation);
+
+        mMaxTransX = getResources().getDimensionPixelSize(R.dimen.notification_max_trans);
+        mNotificationSpace = getResources().getDimensionPixelSize(R.dimen.notification_space);
+
+        setClipToOutline(true);
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(mOutline, outlineRadius);
+            }
+        });
+    }
+
+    /**
+     * Updates the header text.
+     * @param notificationCount The number of notifications.
+     */
+    public void updateHeader(int notificationCount) {
+        final String text;
+        final int visibility;
+        if (notificationCount <= 1) {
+            text = "";
+            visibility = View.INVISIBLE;
+        } else {
+            text = String.valueOf(notificationCount);
+            visibility = View.VISIBLE;
+
+        }
+        mHeaderCount.setText(text);
+        mHeaderCount.setVisibility(visibility);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mTextAndBackground = findViewById(R.id.text_and_background);
-        mTitleView = mTextAndBackground.findViewById(R.id.title);
-        mTextView = mTextAndBackground.findViewById(R.id.text);
+        ViewGroup textAndBackground = findViewById(R.id.text_and_background);
+        mTitleView = textAndBackground.findViewById(R.id.title);
+        mTextView = textAndBackground.findViewById(R.id.text);
         mIconView = findViewById(R.id.popup_item_icon);
+        mHeaderCount = findViewById(R.id.notification_count);
 
-        ColorDrawable colorBackground = (ColorDrawable) mTextAndBackground.getBackground();
-        updateBackgroundColor(colorBackground.getColor());
+        mHeader = findViewById(R.id.header);
+        mMainView = findViewById(R.id.main_view);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mOutline.set(0, 0, getWidth(), getHeight());
+        invalidateOutline();
     }
 
     private void updateBackgroundColor(int color) {
         mBackgroundColor = color;
-        mColorDrawable.setColor(color);
-        mTextAndBackground.setBackground(mColorDrawable);
+        mBackground.setColor(color);
         if (mNotificationInfo != null) {
             mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
                     mBackgroundColor));
@@ -128,8 +185,11 @@
     /**
      * Sets the content of this view, animating it after a new icon shifts up if necessary.
      */
-    public void applyNotificationInfo(NotificationInfo mainNotification, boolean animate) {
-        mNotificationInfo = mainNotification;
+    public void applyNotificationInfo(NotificationInfo notificationInfo) {
+        mNotificationInfo = notificationInfo;
+        if (notificationInfo == null) {
+            return;
+        }
         NotificationListener listener = NotificationListener.getInstanceIfConnected();
         if (listener != null) {
             listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey});
@@ -149,25 +209,112 @@
         if (mNotificationInfo.intent != null) {
             setOnClickListener(mNotificationInfo);
         }
-        setContentTranslation(0);
+
         // Add a stub ItemInfo so that logging populates the correct container and item types
         // instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively.
         setTag(NOTIFICATION_ITEM_INFO);
-        if (animate) {
-            ObjectAnimator.ofFloat(mTextAndBackground, ALPHA, 0, 1).setDuration(150).start();
+    }
+
+    /**
+     * Sets the alpha of only the child views.
+     */
+    public void setContentAlpha(float alpha) {
+        mHeader.setAlpha(alpha);
+        mMainView.setAlpha(alpha);
+    }
+
+    /**
+     * Sets the translation of only the child views.
+     */
+    public void setContentTranslationX(float transX) {
+        mHeader.setTranslationX(transX);
+        mMainView.setTranslationX(transX);
+    }
+
+    /**
+     * Updates the alpha, content alpha, and elevation of this view.
+     *
+     * @param progress Range from [0, 1] or [-1, 0]
+     *                 When 0: Full alpha
+     *                 When 1/-1: zero alpha
+     */
+    public void onPrimaryDrag(float progress) {
+        float absProgress = Math.abs(progress);
+        final int width = getWidth();
+
+        float min = PRIMARY_MIN_PROGRESS;
+        float max = PRIMARY_MAX_PROGRESS;
+
+        if (absProgress < min) {
+            setAlpha(1f);
+            setContentAlpha(1);
+            setElevation(mMaxElevation);
+        } else if (absProgress < max) {
+            setAlpha(1f);
+            setContentAlpha(mapToRange(absProgress, min, max, 1f, 0f, LINEAR));
+            setElevation(Utilities.mapToRange(absProgress, min, max, mMaxElevation, 0, LINEAR));
+        } else {
+            setAlpha(mapToRange(absProgress, max, PRIMARY_GONE_PROGRESS, 1f, 0f, LINEAR));
+            setContentAlpha(0f);
+            setElevation(0f);
         }
+
+        setTranslationX(width * progress);
     }
 
-    public void setContentTranslation(float translation) {
-        mTextAndBackground.setTranslationX(translation);
-        mIconView.setTranslationX(translation);
+    /**
+     * Updates the alpha, content alpha, elevation, and clipping of this view.
+     * @param progress Range from [0, 1] or [-1, 0]
+      *                 When 0: Smallest clipping, zero alpha
+      *                 When 1/-1: Full clip, full alpha
+     */
+    public void onSecondaryDrag(float progress) {
+        final float absProgress = Math.abs(progress);
+
+        float min = SECONDARY_MIN_PROGRESS;
+        float max = SECONDARY_MAX_PROGRESS;
+        float contentMax = SECONDARY_CONTENT_MAX_PROGRESS;
+
+        if (absProgress < min) {
+            setAlpha(0f);
+            setContentAlpha(0);
+            setElevation(0f);
+        } else if (absProgress < max) {
+            setAlpha(mapToRange(absProgress, min, max, 0, 1f, LINEAR));
+            setContentAlpha(0f);
+            setElevation(0f);
+        } else {
+            setAlpha(1f);
+            setContentAlpha(absProgress > contentMax
+                    ? 1f
+                    : mapToRange(absProgress, max, contentMax, 0, 1f, LINEAR));
+            setElevation(Utilities.mapToRange(absProgress, max, 1, 0, mMaxElevation, LINEAR));
+        }
+
+        final int width = getWidth();
+        int crop = (int) (width * absProgress);
+        int space = (int) (absProgress > PRIMARY_GONE_PROGRESS
+                ? mapToRange(absProgress, PRIMARY_GONE_PROGRESS, 1f, mNotificationSpace, 0, LINEAR)
+                : mNotificationSpace);
+        if (progress < 0) {
+            mOutline.left = Math.max(0, getWidth() - crop + space);
+            mOutline.right = getWidth();
+        } else {
+            mOutline.right = Math.min(getWidth(), crop - space);
+            mOutline.left = 0;
+        }
+
+        float contentTransX = mMaxTransX * (1f - absProgress);
+        setContentTranslationX(progress < 0
+                ? contentTransX
+                : -contentTransX);
+        invalidateOutline();
     }
 
-    public NotificationInfo getNotificationInfo() {
+    public @Nullable NotificationInfo getNotificationInfo() {
         return mNotificationInfo;
     }
 
-
     public boolean canChildBeDismissed() {
         return mNotificationInfo != null && mNotificationInfo.dismissable;
     }
diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java
index fad904f..1797c1f 100644
--- a/src/com/android/launcher3/pm/PackageInstallInfo.java
+++ b/src/com/android/launcher3/pm/PackageInstallInfo.java
@@ -57,4 +57,28 @@
     public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) {
         return new PackageInstallInfo(packageName, state, 0 /* progress */, user);
     }
+
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "(" + dumpProperties() + ")";
+    }
+
+    private String dumpProperties() {
+        return "componentName=" + componentName
+                + "packageName=" + packageName
+                + " state=" + stateToString()
+                + " progress=" + progress
+                + " user=" + user;
+    }
+
+    private String stateToString() {
+        switch (state) {
+            case STATUS_INSTALLED : return "STATUS_INSTALLED";
+            case STATUS_INSTALLING : return "STATUS_INSTALLING";
+            case STATUS_INSTALLED_DOWNLOADING : return "STATUS_INSTALLED_DOWNLOADING";
+            case STATUS_FAILED : return "STATUS_FAILED";
+            default : return "INVALID STATE";
+        }
+    }
 }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index a534ee3..5d3ba75 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -487,6 +487,13 @@
         return getMeasuredWidth() - mArrowOffsetHorizontal - mArrowWidth;
     }
 
+    /**
+     * @param show If true, shows arrow (when applicable), otherwise hides arrow.
+     */
+    public void showArrow(boolean show) {
+        mArrow.setVisibility(show && shouldAddArrow() ? VISIBLE : INVISIBLE);
+    }
+
     private void addArrow() {
         getPopupContainer().addView(mArrow);
         mArrow.setX(getX() + getArrowLeft());
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 18f263a..bc3419a 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -58,8 +58,8 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.notification.NotificationContainer;
 import com.android.launcher3.notification.NotificationInfo;
-import com.android.launcher3.notification.NotificationItemView;
 import com.android.launcher3.notification.NotificationKeyData;
 import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener;
 import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -92,9 +92,8 @@
     private final int mStartDragThreshold;
 
     private BubbleTextView mOriginalIcon;
-    private NotificationItemView mNotificationItemView;
     private int mNumNotifications;
-    private ViewGroup mNotificationContainer;
+    private NotificationContainer mNotificationContainer;
 
     private ViewGroup mWidgetContainer;
 
@@ -128,8 +127,8 @@
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mInterceptTouchDown.set(ev.getX(), ev.getY());
         }
-        if (mNotificationItemView != null
-                && mNotificationItemView.onInterceptTouchEvent(ev)) {
+        if (mNotificationContainer != null
+                && mNotificationContainer.onInterceptSwipeEvent(ev)) {
             return true;
         }
         // Stop sending touch events to deep shortcut views if user moved beyond touch slop.
@@ -138,6 +137,14 @@
     }
 
     @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mNotificationContainer != null) {
+            return mNotificationContainer.onSwipeEvent(ev) || super.onTouchEvent(ev);
+        }
+        return super.onTouchEvent(ev);
+    }
+
+    @Override
     protected boolean isOfType(int type) {
         return (type & TYPE_ACTION_POPUP) != 0;
     }
@@ -172,8 +179,8 @@
     @Override
     protected void setChildColor(View view, int color, AnimatorSet animatorSetOut) {
         super.setChildColor(view, color, animatorSetOut);
-        if (view.getId() == R.id.notification_container && mNotificationItemView != null) {
-            mNotificationItemView.updateBackgroundColor(color, animatorSetOut);
+        if (view.getId() == R.id.notification_container && mNotificationContainer != null) {
+            mNotificationContainer.updateBackgroundColor(color, animatorSetOut);
         }
     }
 
@@ -232,13 +239,6 @@
                 mNotificationContainer);
     }
 
-    @Override
-    protected void onInflationComplete(boolean isReversed) {
-        if (isReversed && mNotificationItemView != null) {
-            mNotificationItemView.inverseGutterMargin();
-        }
-    }
-
     @TargetApi(Build.VERSION_CODES.P)
     public void populateAndShow(final BubbleTextView originalIcon, int shortcutCount,
             final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
@@ -261,9 +261,10 @@
             if (mNotificationContainer == null) {
                 mNotificationContainer = findViewById(R.id.notification_container);
                 mNotificationContainer.setVisibility(VISIBLE);
+                mNotificationContainer.setPopupView(this);
+            } else {
+                mNotificationContainer.setVisibility(GONE);
             }
-            View.inflate(getContext(), R.layout.notification_content, mNotificationContainer);
-            mNotificationItemView = new NotificationItemView(this, mNotificationContainer);
             updateNotificationHeader();
         }
         int viewsToFlip = getChildCount();
@@ -274,10 +275,6 @@
         if (hasDeepShortcuts) {
             mDeepShortcutContainer.setVisibility(View.VISIBLE);
 
-            if (mNotificationItemView != null) {
-                mNotificationItemView.addGutter();
-            }
-
             for (int i = shortcutCount; i > 0; i--) {
                 DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
                 v.getLayoutParams().width = containerWidth;
@@ -309,10 +306,6 @@
         } else {
             mDeepShortcutContainer.setVisibility(View.GONE);
             if (!systemShortcuts.isEmpty()) {
-                if (mNotificationItemView != null) {
-                    mNotificationItemView.addGutter();
-                }
-
                 for (SystemShortcut shortcut : systemShortcuts) {
                     initializeSystemShortcut(R.layout.system_shortcut, this, shortcut);
                 }
@@ -355,13 +348,13 @@
     }
 
     public void applyNotificationInfos(List<NotificationInfo> notificationInfos) {
-        if (mNotificationItemView != null) {
-            mNotificationItemView.applyNotificationInfos(notificationInfos);
+        if (mNotificationContainer != null) {
+            mNotificationContainer.applyNotificationInfos(notificationInfos);
         }
     }
 
     private void updateHiddenShortcuts() {
-        int allowedCount = mNotificationItemView != null
+        int allowedCount = mNotificationContainer != null
                 ? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
 
         int total = mShortcuts.size();
@@ -447,8 +440,8 @@
     private void updateNotificationHeader() {
         ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
         DotInfo dotInfo = mLauncher.getDotInfoForItem(itemInfo);
-        if (mNotificationItemView != null && dotInfo != null) {
-            mNotificationItemView.updateHeader(dotInfo.getNotificationCount());
+        if (mNotificationContainer != null && dotInfo != null) {
+            mNotificationContainer.updateHeader(dotInfo.getNotificationCount());
         }
     }
 
@@ -590,20 +583,18 @@
 
         @Override
         public void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
-            if (mNotificationItemView == null) {
+            if (mNotificationContainer == null) {
                 return;
             }
             ItemInfo originalInfo = (ItemInfo) mOriginalIcon.getTag();
             DotInfo dotInfo = updatedDots.get(PackageUserKey.fromItemInfo(originalInfo));
             if (dotInfo == null || dotInfo.getNotificationKeys().size() == 0) {
                 // No more notifications, remove the notification views and expand all shortcuts.
-                mNotificationItemView.removeAllViews();
-                mNotificationItemView = null;
                 mNotificationContainer.setVisibility(GONE);
                 updateHiddenShortcuts();
                 assignMarginsAndBackgrounds(PopupContainerWithArrow.this);
             } else {
-                mNotificationItemView.trimNotifications(
+                mNotificationContainer.trimNotifications(
                         NotificationKeyData.extractKeysOnly(dotInfo.getNotificationKeys()));
             }
         }
diff --git a/src/com/android/launcher3/search/SearchAlgorithm.java b/src/com/android/launcher3/search/SearchAlgorithm.java
index a1720c7..96a15f4 100644
--- a/src/com/android/launcher3/search/SearchAlgorithm.java
+++ b/src/com/android/launcher3/search/SearchAlgorithm.java
@@ -28,6 +28,13 @@
     void doSearch(String query, SearchCallback<T> callback);
 
     /**
+     * Performs search with {@code query} and the {@code suggestedQueries}/
+     */
+    default void doSearch(String query, String[] suggestedQueries, SearchCallback<T> callback) {
+        doSearch(query, callback);
+    }
+
+    /**
      * Cancels any active request.
      */
     void cancel(boolean interruptActiveRequests);
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 915e140..f348a33 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -62,8 +62,9 @@
         SharedPreferences.OnSharedPreferenceChangeListener{
 
     /** List of fragments that can be hosted by this activity. */
-    private static final List<String> VALID_PREFERENCE_FRAGMENTS = Collections.singletonList(
-            DeveloperOptionsFragment.class.getName());
+    private static final List<String> VALID_PREFERENCE_FRAGMENTS =
+            !Utilities.IS_DEBUG_DEVICE ? Collections.emptyList()
+                    : Collections.singletonList(DeveloperOptionsFragment.class.getName());
 
     private static final String DEVELOPER_OPTIONS_KEY = "pref_developer_options";
     private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
diff --git a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
new file mode 100644
index 0000000..2742882
--- /dev/null
+++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.RemoteViews;
+
+import androidx.annotation.UiThread;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Executors;
+
+/**
+ * Launcher AppWidgetHostView with support for rounded corners and a fallback View.
+ */
+public abstract class BaseLauncherAppWidgetHostView extends NavigableAppWidgetHostView {
+
+    protected final LayoutInflater mInflater;
+
+    private final Rect mEnforcedRectangle = new Rect();
+    private final float mEnforcedCornerRadius;
+    private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
+        @Override
+        public void getOutline(View view, Outline outline) {
+            if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
+                outline.setEmpty();
+            } else {
+                outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
+            }
+        }
+    };
+
+    public BaseLauncherAppWidgetHostView(Context context) {
+        super(context);
+
+        setExecutor(Executors.THREAD_POOL_EXECUTOR);
+
+        mInflater = LayoutInflater.from(context);
+        mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
+    }
+
+    @Override
+    protected View getErrorView() {
+        return mInflater.inflate(R.layout.appwidget_error, this, false);
+    }
+
+    /**
+     * Fall back to error layout instead of showing widget.
+     */
+    public void switchToErrorView() {
+        // Update the widget with 0 Layout id, to reset the view to error view.
+        updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        try {
+            super.onLayout(changed, left, top, right, bottom);
+        } catch (final RuntimeException e) {
+            post(this::switchToErrorView);
+        }
+
+        enforceRoundedCorners();
+    }
+
+    @UiThread
+    private void resetRoundedCorners() {
+        setOutlineProvider(ViewOutlineProvider.BACKGROUND);
+        setClipToOutline(false);
+    }
+
+    @UiThread
+    private void enforceRoundedCorners() {
+        if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
+            resetRoundedCorners();
+            return;
+        }
+        View background = RoundedCornerEnforcement.findBackground(this);
+        if (background == null
+                || RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
+            resetRoundedCorners();
+            return;
+        }
+        RoundedCornerEnforcement.computeRoundedRectangle(this,
+                background,
+                mEnforcedRectangle);
+        setOutlineProvider(mCornerRadiusEnforcementOutline);
+        setClipToOutline(true);
+    }
+
+    /** Returns the corner radius currently enforced, in pixels. */
+    public float getEnforcedCornerRadius() {
+        return mEnforcedCornerRadius;
+    }
+
+    /** Returns true if the corner radius are enforced for this App Widget. */
+    public boolean hasEnforcedCornerRadius() {
+        return getClipToOutline();
+    }
+}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 63bc416..fb6de9f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -20,19 +20,16 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
-import android.graphics.Outline;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
-import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.AdapterView;
 import android.widget.Advanceable;
@@ -40,7 +37,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
 
 import com.android.launcher3.CheckLongPressHelper;
 import com.android.launcher3.Launcher;
@@ -51,7 +47,6 @@
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
 import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
@@ -61,7 +56,7 @@
 /**
  * {@inheritDoc}
  */
-public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
+public class LauncherAppWidgetHostView extends BaseLauncherAppWidgetHostView
         implements TouchCompleteListener, View.OnLongClickListener,
         LocalColorExtractor.Listener {
 
@@ -76,8 +71,6 @@
     // Maximum duration for which updates can be deferred.
     private static final long UPDATE_LOCK_TIMEOUT_MILLIS = 1000;
 
-    protected final LayoutInflater mInflater;
-
     private final CheckLongPressHelper mLongPressHelper;
     protected final Launcher mLauncher;
     private final Workspace mWorkspace;
@@ -101,18 +94,6 @@
     private final Rect mWidgetSizeAtDrag = new Rect();
 
     private final RectF mTempRectF = new RectF();
-    private final Rect mEnforcedRectangle = new Rect();
-    private final float mEnforcedCornerRadius;
-    private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            if (mEnforcedRectangle.isEmpty() || mEnforcedCornerRadius <= 0) {
-                outline.setEmpty();
-            } else {
-                outline.setRoundRect(mEnforcedRectangle, mEnforcedCornerRadius);
-            }
-        }
-    };
     private final Object mUpdateLock = new Object();
     private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
     private long mDeferUpdatesUntilMillis = 0;
@@ -126,18 +107,15 @@
         mLauncher = Launcher.getLauncher(context);
         mWorkspace = mLauncher.getWorkspace();
         mLongPressHelper = new CheckLongPressHelper(this, this);
-        mInflater = LayoutInflater.from(context);
         setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
 
-        setExecutor(Executors.THREAD_POOL_EXECUTOR);
         if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
             setOnLightBackground(true);
         }
         mColorExtractor = LocalColorExtractor.newInstance(getContext());
         mColorExtractor.setListener(this);
 
-        mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
         mDragLayerRelativeCoordinateHelper = new ViewGroupFocusHelper(mLauncher.getDragLayer());
     }
 
@@ -169,11 +147,6 @@
     }
 
     @Override
-    protected View getErrorView() {
-        return mInflater.inflate(R.layout.appwidget_error, this, false);
-    }
-
-    @Override
     public void updateAppWidget(RemoteViews remoteViews) {
         synchronized (mUpdateLock) {
             if (isDeferringUpdates()) {
@@ -329,28 +302,12 @@
         }
     }
 
-    public void switchToErrorView() {
-        // Update the widget with 0 Layout id, to reset the view to error view.
-        updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
-    }
-
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        try {
-            super.onLayout(changed, left, top, right, bottom);
-        } catch (final RuntimeException e) {
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    switchToErrorView();
-                }
-            });
-        }
+        super.onLayout(changed, left, top, right, bottom);
 
         mIsScrollable = checkScrollableRecursively(this);
         updateColorExtraction();
-
-        enforceRoundedCorners();
     }
 
     /** Starts the drag mode. */
@@ -564,40 +521,4 @@
         }
         return false;
     }
-
-    @UiThread
-    private void resetRoundedCorners() {
-        setOutlineProvider(ViewOutlineProvider.BACKGROUND);
-        setClipToOutline(false);
-    }
-
-    @UiThread
-    private void enforceRoundedCorners() {
-        if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
-            resetRoundedCorners();
-            return;
-        }
-        View background = RoundedCornerEnforcement.findBackground(this);
-        if (background == null
-                || RoundedCornerEnforcement.hasAppWidgetOptedOut(this, background)) {
-            resetRoundedCorners();
-            return;
-        }
-        RoundedCornerEnforcement.computeRoundedRectangle(this,
-                background,
-                mEnforcedRectangle);
-        setOutlineProvider(mCornerRadiusEnforcementOutline);
-        setClipToOutline(true);
-    }
-
-    /** Returns the corner radius currently enforced, in pixels. */
-    public float getEnforcedCornerRadius() {
-        return mEnforcedCornerRadius;
-    }
-
-    /** Returns true if the corner radius are enforced for this App Widget. */
-    public boolean hasEnforcedCornerRadius() {
-        return getClipToOutline();
-    }
-
 }
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index 6163b51..d12fe74 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -26,7 +26,6 @@
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Reorderable;
 import com.android.launcher3.dragndrop.DraggableView;
@@ -59,7 +58,7 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mChildrenFocused;
 
-    protected final BaseActivity mActivity;
+    protected final ActivityContext mActivity;
 
     public NavigableAppWidgetHostView(Context context) {
         super(context);