Merge "Initial commit of rotation contextual button." into sc-v2-dev
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index b36214b..e7da196 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -29,10 +29,6 @@
         android:orientation="horizontal">
 
         <Space
-            android:layout_width="@dimen/go_overview_button_width"
-            android:layout_height="1dp" />
-
-        <Space
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="1" />
@@ -50,9 +46,8 @@
         </LinearLayout>
 
         <Space
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1" />
+            android:layout_width="@dimen/go_overview_button_container_margin"
+            android:layout_height="1dp" />
 
         <LinearLayout
             style="@style/GoOverviewActionButtonContainer">
@@ -68,9 +63,8 @@
         </LinearLayout>
 
         <Space
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1" />
+            android:layout_width="@dimen/go_overview_button_container_margin"
+            android:layout_height="1dp" />
 
         <LinearLayout
             style="@style/GoOverviewActionButtonContainer">
@@ -90,10 +84,6 @@
             android:layout_height="1dp"
             android:layout_weight="1" />
 
-        <Space
-            android:layout_width="@dimen/go_overview_button_width"
-            android:layout_height="1dp" />
-
         <!-- Will be enabled in a future version. -->
         <LinearLayout
             style="@style/GoOverviewActionButtonContainer"
diff --git a/go/quickstep/res/layout/overview_panel.xml b/go/quickstep/res/layout/overview_panel.xml
new file mode 100644
index 0000000..241b63d
--- /dev/null
+++ b/go/quickstep/res/layout/overview_panel.xml
@@ -0,0 +1,39 @@
+<?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">
+
+    <com.android.quickstep.views.LauncherRecentsView
+        android:id="@+id/overview_panel"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:background="?attr/overviewBackgroundColor"
+        android:visibility="invisible" />
+
+    <com.android.quickstep.views.SplitPlaceholderView
+        android:id="@+id/split_placeholder"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/split_placeholder_size"
+        android:background="@android:color/darker_gray"
+        android:visibility="gone" />
+
+    <include
+        android:id="@+id/overview_actions_view"
+        layout="@layout/overview_actions_container" />
+
+</merge>
diff --git a/go/quickstep/res/values/attrs.xml b/go/quickstep/res/values/attrs.xml
new file mode 100644
index 0000000..3adf462
--- /dev/null
+++ b/go/quickstep/res/values/attrs.xml
@@ -0,0 +1,23 @@
+<?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>
+    <!-- Attributes used for Overview theming -->
+    <attr name="overviewBackgroundColor" format="color" />
+    <attr name="overviewButtonTextColor" format="color" />
+    <attr name="overviewButtonIconColor" format="color" />
+    <attr name="overviewButtonBackgroundColor" format="color" />
+</resources>
\ No newline at end of file
diff --git a/go/quickstep/res/values/colors.xml b/go/quickstep/res/values/colors.xml
index 9383770..f815f54 100644
--- a/go/quickstep/res/values/colors.xml
+++ b/go/quickstep/res/values/colors.xml
@@ -16,6 +16,10 @@
 -->
 <resources>
     <!-- Overview -->
-    <color name="go_overview_button_icon_color">#3C4043</color>
+    <color name="go_overview_background_color">#DADADA</color>
+    <color name="go_overview_background_color_dark">#000000</color>
+    <color name="go_overview_text_color">#3C4043</color>
+    <color name="go_overview_text_color_dark">#F8F9FA</color>
     <color name="go_overview_button_color">#70FFFFFF</color>
+    <color name="go_overview_button_color_dark">#303030</color>
 </resources>
diff --git a/go/quickstep/res/values/dimens.xml b/go/quickstep/res/values/dimens.xml
index da684fa..55cd138 100644
--- a/go/quickstep/res/values/dimens.xml
+++ b/go/quickstep/res/values/dimens.xml
@@ -22,6 +22,7 @@
     <dimen name="go_overview_button_width">60dp</dimen>
     <dimen name="go_overview_button_height">60dp</dimen>
     <dimen name="go_overview_button_container_width">80dp</dimen>
+    <dimen name="go_overview_button_container_margin">16dp</dimen>
     <dimen name="go_overview_button_caption_margin">8dp</dimen>
     <dimen name="overview_actions_height">96dp</dimen>
     <dimen name="overview_proactive_row_height">0dp</dimen>
diff --git a/go/quickstep/res/values/styles.xml b/go/quickstep/res/values/styles.xml
index 9b3fe67..59f7377 100644
--- a/go/quickstep/res/values/styles.xml
+++ b/go/quickstep/res/values/styles.xml
@@ -15,9 +15,25 @@
      limitations under the License.
 -->
 <resources>
+    <!-- App themes -->
+    <style name="AppTheme" parent="@style/LauncherTheme">
+        <item name="overviewBackgroundColor">@color/go_overview_background_color</item>
+        <item name="overviewButtonTextColor">@color/go_overview_text_color</item>
+        <item name="overviewButtonIconColor">@color/go_overview_text_color</item>
+        <item name="overviewButtonBackgroundColor">@color/go_overview_button_color</item>
+    </style>
+
+    <style name="AppTheme.Dark" parent="@style/LauncherTheme.Dark">
+        <item name="overviewBackgroundColor">@color/go_overview_background_color_dark</item>
+        <item name="overviewButtonTextColor">@color/go_overview_text_color_dark</item>
+        <item name="overviewButtonIconColor">@color/go_overview_text_color_dark</item>
+        <item name="overviewButtonBackgroundColor">@color/go_overview_button_color_dark</item>
+    </style>
+
+    <!-- Overview -->
     <style name="GoOverviewActionButton">
-        <item name="android:tint">@color/go_overview_button_icon_color</item>
-        <item name="android:backgroundTint">@color/go_overview_button_color</item>
+        <item name="android:tint">?attr/overviewButtonIconColor</item>
+        <item name="android:backgroundTint">?attr/overviewButtonBackgroundColor</item>
         <item name="android:background">@drawable/round_rect_button</item>
         <item name="android:layout_width">@dimen/go_overview_button_width</item>
         <item name="android:layout_height">@dimen/go_overview_button_height</item>
@@ -27,7 +43,7 @@
     <style name="GoOverviewActionButtonCaption">
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:textSize">14dp</item>
-        <item name="android:textColor">@color/go_overview_button_icon_color</item>
+        <item name="android:textColor">?attr/overviewButtonTextColor</item>
         <item name="android:lineHeight">20dp</item>
         <item name="android:textAlignment">center</item>
         <item name="android:importantForAccessibility">no</item>
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 96a94ba..763e45e 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -25,15 +25,15 @@
 
     <TextView
         android:id="@+id/task_name"
-        android:background="?android:attr/textColorPrimary"
-        android:textColor="?android:attr/textColorPrimaryInverse"
+        android:background="?android:attr/colorPrimary"
+        android:textColor="?android:attr/textColorPrimary"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:gravity="center"
         android:layout_marginBottom="2dp"
-        android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
-        android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
-        android:textSize="24sp"/>
+        android:paddingTop="@dimen/task_menu_vertical_padding"
+        android:paddingBottom="@dimen/task_menu_vertical_padding"
+        android:textSize="16sp"/>
 
     <LinearLayout
         android:id="@+id/menu_option_layout"
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 59c7263..19ca3e3 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -21,7 +21,7 @@
     android:orientation="vertical"
     android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
     android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
-    android:background="?android:attr/textColorPrimary"
+    android:background="?android:attr/colorPrimary"
     android:theme="@style/PopupItem" >
 
     <View
@@ -30,7 +30,7 @@
       android:layout_height="@dimen/system_shortcut_icon_size"
       android:layout_marginStart="@dimen/task_menu_option_start_margin"
       android:layout_gravity="center_horizontal"
-      android:backgroundTint="?android:attr/textColorPrimaryInverse"/>
+      android:backgroundTint="?android:attr/textColorPrimary"/>
 
     <TextView
         style="@style/BaseIcon"
@@ -39,7 +39,7 @@
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/task_menu_option_start_margin"
         android:textSize="14sp"
-        android:textColor="?android:attr/textColorPrimaryInverse"
+        android:textColor="?android:attr/textColorPrimary"
         android:focusable="false" />
 
 </LinearLayout>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index af4e19e..dd63cfa 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -64,7 +64,7 @@
     <dimen name="quickstep_fling_threshold_speed">0.5dp</dimen>
 
     <!-- Launcher app transition -->
-    <dimen name="content_trans_y">50dp</dimen>
+    <item name="content_scale" format="float" type="dimen">0.97</item>
     <dimen name="closing_window_trans_y">115dp</dimen>
 
     <dimen name="recents_empty_message_text_size">16sp</dimen>
@@ -74,7 +74,8 @@
 
     <!-- Total space (start + end) between the task card and the edge of the screen
          in various configurations -->
-    <dimen name="task_card_menu_option_vertical_padding">8dp</dimen>
+    <dimen name="task_card_menu_option_vertical_padding">16dp</dimen>
+    <dimen name="task_menu_vertical_padding">8dp</dimen>
     <dimen name="task_card_margin">8dp</dimen>
     <dimen name="task_card_menu_shadow_height">3dp</dimen>
     <dimen name="task_menu_option_start_margin">12dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 8813891..34c08d6 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -23,11 +23,14 @@
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
 import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.Utilities.postAsyncCallback;
 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;
@@ -49,10 +52,12 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -60,12 +65,15 @@
 import android.os.SystemProperties;
 import android.util.Pair;
 import android.util.Size;
+import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.anim.AnimationSuccessListener;
@@ -74,10 +82,11 @@
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.util.ActivityOptionsWrapper;
-import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.FloatingIconView;
+import com.android.launcher3.views.ScrimView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.SystemUiProxy;
@@ -90,6 +99,7 @@
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.BlurUtils;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -159,7 +169,8 @@
     private static final int CLOSING_TRANSITION_DURATION_MS = 250;
 
     public static final int CONTENT_ALPHA_DURATION = 217;
-    protected static final int CONTENT_TRANSLATION_DURATION = 350;
+    protected static final int CONTENT_SCALE_DURATION = 350;
+    protected static final int CONTENT_SCRIM_DURATION = 350;
 
     private static final int MAX_NUM_TASKS = 5;
 
@@ -172,9 +183,8 @@
     private final AlphaProperty mDragLayerAlpha;
 
     final Handler mHandler;
-    private final boolean mIsRtl;
 
-    private final float mContentTransY;
+    private final float mContentScale;
     private final float mClosingWindowTransY;
     private final float mMaxShadowRadius;
 
@@ -211,11 +221,10 @@
         mDragLayer = mLauncher.getDragLayer();
         mDragLayerAlpha = mDragLayer.getAlphaProperty(ALPHA_INDEX_TRANSITIONS);
         mHandler = new Handler(Looper.getMainLooper());
-        mIsRtl = Utilities.isRtl(mLauncher.getResources());
         mDeviceProfile = mLauncher.getDeviceProfile();
 
         Resources res = mLauncher.getResources();
-        mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
+        mContentScale = res.getFloat(R.dimen.content_scale);
         mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
         mMaxShadowRadius = res.getDimensionPixelSize(R.dimen.max_shadow_radius);
 
@@ -334,8 +343,7 @@
                 windowTargetBounds, areAllTargetsTranslucent(appTargets), rotationChange));
         if (launcherClosing) {
             Pair<AnimatorSet, Runnable> launcherContentAnimator =
-                    getLauncherContentAnimator(true /* isAppOpening */,
-                            new float[] {0, -mContentTransY});
+                    getLauncherContentAnimator(true /* isAppOpening */);
             anim.play(launcherContentAnimator.first);
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
@@ -435,10 +443,8 @@
      *
      * @param isAppOpening True when this is called when an app is opening.
      *                     False when this is called when an app is closing.
-     * @param trans Array that contains the start and end translation values for the content.
      */
-    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening,
-            float[] trans) {
+    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening) {
         AnimatorSet launcherAnimator = new AnimatorSet();
         Runnable endListener;
 
@@ -446,13 +452,17 @@
                 ? new float[] {1, 0}
                 : new float[] {0, 1};
 
+        float[] scales = isAppOpening
+                ? new float[] {1, mContentScale}
+                : new float[] {mContentScale, 1};
+
         if (mLauncher.isInState(ALL_APPS)) {
             // All Apps in portrait mode is full screen, so we only animate AllAppsContainerView.
             final View appsView = mLauncher.getAppsView();
             final float startAlpha = appsView.getAlpha();
-            final float startY = appsView.getTranslationY();
+            final float startScale = SCALE_PROPERTY.get(appsView);
             appsView.setAlpha(alphas[0]);
-            appsView.setTranslationY(trans[0]);
+            SCALE_PROPERTY.set(appsView, scales[0]);
 
             ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas);
             alpha.setDuration(CONTENT_ALPHA_DURATION);
@@ -464,30 +474,22 @@
                     appsView.setLayerType(View.LAYER_TYPE_NONE, null);
                 }
             });
-            ObjectAnimator transY = ObjectAnimator.ofFloat(appsView, View.TRANSLATION_Y, trans);
-            transY.setInterpolator(AGGRESSIVE_EASE);
-            transY.setDuration(CONTENT_TRANSLATION_DURATION);
+            ObjectAnimator scale = ObjectAnimator.ofFloat(appsView, SCALE_PROPERTY, scales);
+            scale.setInterpolator(AGGRESSIVE_EASE);
+            scale.setDuration(CONTENT_SCALE_DURATION);
 
             launcherAnimator.play(alpha);
-            launcherAnimator.play(transY);
+            launcherAnimator.play(scale);
 
             endListener = () -> {
                 appsView.setAlpha(startAlpha);
-                appsView.setTranslationY(startY);
+                SCALE_PROPERTY.set(appsView, startScale);
                 appsView.setLayerType(View.LAYER_TYPE_NONE, null);
             };
         } else if (mLauncher.isInState(OVERVIEW)) {
-            endListener = composeViewContentAnimator(launcherAnimator, alphas, trans);
+            endListener = composeViewContentAnimator(launcherAnimator, alphas, scales);
         } else {
-            mDragLayerAlpha.setValue(alphas[0]);
-            ObjectAnimator alpha =
-                    ObjectAnimator.ofFloat(mDragLayerAlpha, MultiValueAlpha.VALUE, alphas);
-            alpha.setDuration(CONTENT_ALPHA_DURATION);
-            alpha.setInterpolator(LINEAR);
-            launcherAnimator.play(alpha);
-
             List<View> viewsToAnimate = new ArrayList<>();
-
             Workspace workspace = mLauncher.getWorkspace();
             workspace.forEachVisiblePage(
                     view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
@@ -498,18 +500,38 @@
 
             viewsToAnimate.forEach(view -> {
                 view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                launcherAnimator.play(ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, trans));
+
+                ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(view, SCALE_PROPERTY, scales)
+                        .setDuration(CONTENT_SCALE_DURATION);
+                scaleAnim.setInterpolator(DEACCEL_1_5);
+                launcherAnimator.play(scaleAnim);
             });
 
+            int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
+            int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0);
+            int[] colors = isAppOpening
+                    ? new int[] {scrimColorTrans, scrimColor}
+                    : new int[] {scrimColor, scrimColorTrans};
+            ScrimView scrimView = mLauncher.getScrimView();
+            if (scrimView.getBackground() instanceof ColorDrawable) {
+                scrimView.setBackgroundColor(colors[0]);
+
+                ObjectAnimator scrim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
+                        colors);
+                scrim.setDuration(CONTENT_SCRIM_DURATION);
+                scrim.setInterpolator(DEACCEL_1_5);
+                launcherAnimator.play(scrim);
+            }
+
             // Pause page indicator animations as they lead to layer trashing.
             mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
 
             endListener = () -> {
                 viewsToAnimate.forEach(view -> {
-                    view.setTranslationY(0);
+                    SCALE_PROPERTY.set(view, 1f);
                     view.setLayerType(View.LAYER_TYPE_NONE, null);
                 });
-                mDragLayerAlpha.setValue(1f);
+                scrimView.setBackgroundColor(Color.TRANSPARENT);
                 mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
             };
         }
@@ -521,11 +543,11 @@
      *
      * @param anim the animator set to add to
      * @param alphas the alphas to animate to over time
-     * @param trans the translation Y values to animator to over time
+     * @param scales the scale values to animator to over time
      * @return listener to run when the animation ends
      */
     protected Runnable composeViewContentAnimator(@NonNull AnimatorSet anim,
-            float[] alphas, float[] trans) {
+            float[] alphas, float[] scales) {
         RecentsView overview = mLauncher.getOverviewPanel();
         ObjectAnimator alpha = ObjectAnimator.ofFloat(overview,
                 RecentsView.CONTENT_ALPHA, alphas);
@@ -534,14 +556,14 @@
         anim.play(alpha);
         overview.setFreezeViewVisibility(true);
 
-        ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans);
-        transY.setInterpolator(AGGRESSIVE_EASE);
-        transY.setDuration(CONTENT_TRANSLATION_DURATION);
-        anim.play(transY);
+        ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(overview, SCALE_PROPERTY, scales);
+        scaleAnim.setInterpolator(AGGRESSIVE_EASE);
+        scaleAnim.setDuration(CONTENT_SCALE_DURATION);
+        anim.play(scaleAnim);
 
         return () -> {
             overview.setFreezeViewVisibility(false);
-            overview.setTranslationY(0);
+            SCALE_PROPERTY.set(overview, 1f);
             mLauncher.getStateManager().reapplyState();
         };
     }
@@ -901,12 +923,39 @@
                 BACKGROUND_APP.getDepth(mLauncher))
                 .setDuration(APP_LAUNCH_DURATION);
         if (allowBlurringLauncher) {
-            depthController.setSurfaceToApp(RemoteAnimationProvider.findLowestOpaqueLayerTarget(
-                    appTargets, MODE_OPENING));
+            final SurfaceControl dimLayer;
+            if (BlurUtils.supportsBlursOnWindows()) {
+                // Create a temporary effect layer, that lives on top of launcher, so we can apply
+                // the blur to it. The EffectLayer will be fullscreen, which will help with caching
+                // optimizations on the SurfaceFlinger side:
+                // - Results would be able to be cached as a texture
+                // - There won't be texture allocation overhead, because EffectLayers don't have
+                //   buffers
+                ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
+                SurfaceControl parent = viewRootImpl != null
+                        ? viewRootImpl.getSurfaceControl()
+                        : null;
+                dimLayer = new SurfaceControl.Builder()
+                        .setName("Blur layer")
+                        .setParent(parent)
+                        .setOpaque(false)
+                        .setHidden(false)
+                        .setEffectLayer()
+                        .build();
+            } else {
+                dimLayer = null;
+            }
+
+            depthController.setSurface(dimLayer);
             backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
-                    depthController.setSurfaceToApp(null);
+                    depthController.setSurface(null);
+                    if (dimLayer != null) {
+                        new SurfaceControl.Transaction()
+                                .remove(dimLayer)
+                                .apply();
+                    }
                 }
             });
         }
@@ -1230,8 +1279,7 @@
 
                     if (mLauncher.isInState(LauncherState.ALL_APPS)) {
                         Pair<AnimatorSet, Runnable> contentAnimator =
-                                getLauncherContentAnimator(false /* isAppOpening */,
-                                        new float[] {-mContentTransY, 0});
+                                getLauncherContentAnimator(false /* isAppOpening */);
                         contentAnimator.first.setStartDelay(LAUNCHER_RESUME_START_DELAY);
                         anim.play(contentAnimator.first);
                         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index e608885..46ef698 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -25,7 +25,9 @@
 import android.animation.ObjectAnimator;
 import android.os.IBinder;
 import android.util.FloatProperty;
+import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
 import com.android.launcher3.BaseActivity;
@@ -37,9 +39,6 @@
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.systemui.shared.system.BlurUtils;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.SurfaceControlCompat;
-import com.android.systemui.shared.system.TransactionCompat;
 import com.android.systemui.shared.system.WallpaperManagerCompat;
 
 /**
@@ -91,7 +90,8 @@
                 @Override
                 public void onDraw() {
                     View view = mLauncher.getDragLayer();
-                    setSurface(new SurfaceControlCompat(view));
+                    ViewRootImpl viewRootImpl = view.getViewRootImpl();
+                    setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null);
                     view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this));
                 }
             };
@@ -102,7 +102,7 @@
      */
     private int mMaxBlurRadius;
     private WallpaperManagerCompat mWallpaperManager;
-    private SurfaceControlCompat mSurface;
+    private SurfaceControl mSurface;
     /**
      * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
      * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
@@ -157,11 +157,7 @@
     /**
      * Sets the specified app target surface to apply the blur to.
      */
-    public void setSurfaceToApp(RemoteAnimationTargetCompat target) {
-        setSurface(target == null ? null : target.leash);
-    }
-
-    private void setSurface(SurfaceControlCompat surface) {
+    public void setSurface(SurfaceControl surface) {
         if (mSurface != surface) {
             mSurface = surface;
             if (surface != null) {
@@ -219,7 +215,7 @@
         if (supportsBlur) {
             boolean isOpaque = mLauncher.getScrimView().isFullyOpaque();
             int blur = isOpaque ? 0 : (int) (mDepth * mMaxBlurRadius);
-            new TransactionCompat()
+            new SurfaceControl.Transaction()
                     .setBackgroundBlurRadius(mSurface, blur)
                     .setOpaque(mSurface, isOpaque)
                     .apply();
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 92e8268..be927e0 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -103,10 +103,10 @@
 import com.android.quickstep.util.ProtoTracer;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TransformParams;
-import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -202,7 +202,7 @@
             STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
 
     public static final long MAX_SWIPE_DURATION = 350;
-    public static final long HOME_DURATION = WorkspaceRevealAnim.DURATION_MS;
+    public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
 
     public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
     private static final float SWIPE_DURATION_MULTIPLIER =
@@ -394,6 +394,9 @@
         if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
             return;
         }
+        // RecentsView never updates the display rotation until swipe-up, force update
+        // RecentsOrientedState before passing to TaskViewSimulator.
+        mRecentsView.updateRecentsRotation();
         mTaskViewSimulator.setOrientationState(mRecentsView.getPagedViewOrientedState());
 
         // If we've already ended the gesture and are going home, don't prepare recents UI,
@@ -1395,6 +1398,10 @@
             mLauncherTransitionController.getNormalController().getAnimationPlayer().end();
             mLauncherTransitionController = null;
         }
+
+        if (mRecentsView != null) {
+            mRecentsView.abortScrollerAnimation();
+        }
     }
 
     /**
@@ -1413,7 +1420,7 @@
 
     private void resetStateForAnimationCancel() {
         boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
-        mActivityInterface.onTransitionCancelled(wasVisible);
+        mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
 
         // Leave the pending invisible flag, as it may be used by wallpaper open animation.
         if (mActivity != null) {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index ebf422c..803f036 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -86,12 +86,22 @@
         mBackgroundState = backgroundState;
     }
 
-    public void onTransitionCancelled(boolean activityVisible) {
+    /**
+     * Called when the current gesture transition is cancelled.
+     * @param activityVisible Whether the user can see the changes we make here, so try to animate.
+     * @param endTarget If the gesture ended before we got cancelled, where we were headed.
+     */
+    public void onTransitionCancelled(boolean activityVisible,
+            @Nullable GestureState.GestureEndTarget endTarget) {
         ACTIVITY_TYPE activity = getCreatedActivity();
         if (activity == null) {
             return;
         }
         STATE_TYPE startState = activity.getStateManager().getRestState();
+        if (endTarget != null) {
+            // We were on our way to this state when we got canceled, end there instead.
+            startState = stateFromGestureEndTarget(endTarget);
+        }
         activity.getStateManager().goToState(startState, activityVisible);
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index badb41a..5cf4f0b 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -78,6 +78,10 @@
         }
 
         StateAnimationConfig config = new StateAnimationConfig();
+        if (playWorkspaceRevealAnim) {
+            // WorkspaceRevealAnim handles the depth, so don't interfere.
+            config.animFlags |= StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+        }
         config.duration = startState.getTransitionDuration(mLauncher);
         AnimatorSet stateAnim = stateManager.createAtomicAnimation(
                 startState, NORMAL, config);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4b0c08a..7cd8d60 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -75,7 +75,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.UserHandle;
-import android.os.VibrationEffect;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -132,7 +131,6 @@
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TranslateEdgeEffect;
-import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseActivityInterface;
@@ -344,17 +342,6 @@
     private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
     private static final float ANIMATION_DISMISS_PROGRESS_MIDPOINT = 0.5f;
 
-    private static final int SNAP_TO_PAGE_VIBRATION_PRIMITIVE =
-            Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
-    private static final float SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE = 0.4f;
-    private static final VibrationEffect SNAP_TO_PAGE_VIBRATION_FALLBACK =
-            VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
-    private static final int EDGE_IMPACT_VIBRATION_PRIMITIVE =
-            Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
-    private static final float EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE = 0.8f;
-    private static final VibrationEffect EDGE_IMPACT_VIBRATION_FALLBACK =
-            VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK);
-
     protected final RecentsOrientedState mOrientationState;
     protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
     protected RecentsAnimationController mRecentsAnimationController;
@@ -979,8 +966,6 @@
     @Override
     protected void onPageEndTransition() {
         super.onPageEndTransition();
-        VibratorWrapper.INSTANCE.get(mContext).vibrate(SNAP_TO_PAGE_VIBRATION_PRIMITIVE,
-                SNAP_TO_PAGE_VIBRATION_PRIMITIVE_SCALE, SNAP_TO_PAGE_VIBRATION_FALLBACK);
         if (isClearAllHidden()) {
             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
         }
@@ -1084,13 +1069,6 @@
     }
 
     @Override
-    protected void onEdgeAbsorbingScroll() {
-        super.onEdgeAbsorbingScroll();
-        VibratorWrapper.INSTANCE.get(mContext).vibrate(EDGE_IMPACT_VIBRATION_PRIMITIVE,
-                EDGE_IMPACT_VIBRATION_PRIMITIVE_SCALE, EDGE_IMPACT_VIBRATION_FALLBACK);
-    }
-
-    @Override
     protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
         // Enables swiping to the left or right only if the task overlay is not modal.
         if (!isModal()) {
@@ -2702,19 +2680,20 @@
         if (LIVE_TILE.get() && mEnableDrawingLiveTile && newConfig.orientation != mOrientation) {
             switchToScreenshot(
                     () -> finishRecentsAnimation(true /* toRecents */,
-                            this::onConfigurationChangedInternal));
+                            this::updateRecentsRotation));
             mEnableDrawingLiveTile = false;
         } else {
-            onConfigurationChangedInternal();
+            updateRecentsRotation();
         }
         mOrientation = newConfig.orientation;
     }
 
-    private void onConfigurationChangedInternal() {
+    /**
+     * Updates {@link RecentsOrientedState}'s cached RecentsView rotation.
+     */
+    public void updateRecentsRotation() {
         final int rotation = mActivity.getDisplay().getRotation();
-        if (mOrientationState.setRecentsRotation(rotation)) {
-            updateOrientationHandler();
-        }
+        mOrientationState.setRecentsRotation(rotation);
     }
 
     public void setLayoutRotation(int touchRotation, int displayRotation) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index d5816b5..c97225e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -234,7 +234,7 @@
         Rect insets = mActivity.getDragLayer().getInsets();
         BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
         int padding = getResources()
-                .getDimensionPixelSize(R.dimen.task_card_menu_option_vertical_padding);
+                .getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
         params.width = orientationHandler.getTaskMenuWidth(taskView.getThumbnail()) - (2 * padding);
         // Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
         params.gravity = Gravity.LEFT;
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 1bfd430..df195d7 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -336,12 +336,20 @@
         if (mOverlayEnabled != overlayEnabled) {
             mOverlayEnabled = overlayEnabled;
 
-            if (mOverlayEnabled) {
-                getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
-                        mPreviewPositionHelper.mIsOrientationChanged);
-            } else {
-                getTaskOverlay().reset();
-            }
+            refreshOverlay();
+        }
+    }
+
+    /**
+     * Potentially re-init the task overlay. Be cautious when calling this as the overlay may
+     * do processing on initialization.
+     */
+    private void refreshOverlay() {
+        if (mOverlayEnabled) {
+            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
+                    mPreviewPositionHelper.mIsOrientationChanged);
+        } else {
+            getTaskOverlay().reset();
         }
     }
 
@@ -382,6 +390,8 @@
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
         updateThumbnailMatrix();
+
+        refreshOverlay();
     }
 
     private ColorFilter getColorFilter(float dimAmount) {
diff --git a/res/color-night-v31/widgets_picker_surface.xml b/res/color-night-v31/surface.xml
similarity index 100%
rename from res/color-night-v31/widgets_picker_surface.xml
rename to res/color-night-v31/surface.xml
diff --git a/res/color-v31/widgets_picker_surface.xml b/res/color-v31/surface.xml
similarity index 100%
rename from res/color-v31/widgets_picker_surface.xml
rename to res/color-v31/surface.xml
diff --git a/res/color/arrow_tip_view_content.xml b/res/color/arrow_tip_view_content.xml
index 87c733e..7d7f98b 100644
--- a/res/color/arrow_tip_view_content.xml
+++ b/res/color/arrow_tip_view_content.xml
@@ -19,5 +19,5 @@
 -->
 <selector
     xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/white" />
+    <item android:color="?android:attr/textColorPrimaryInverse" />
 </selector>
diff --git a/res/color/button_bg.xml b/res/color/button_bg.xml
new file mode 100644
index 0000000..91eed50
--- /dev/null
+++ b/res/color/button_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/colorAccent" />
+</selector>
diff --git a/res/color/button_text.xml b/res/color/button_text.xml
new file mode 100644
index 0000000..7d7f98b
--- /dev/null
+++ b/res/color/button_text.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2021, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="?android:attr/textColorPrimaryInverse" />
+</selector>
diff --git a/res/color/widgets_picker_surface.xml b/res/color/surface.xml
similarity index 100%
rename from res/color/widgets_picker_surface.xml
rename to res/color/surface.xml
diff --git a/res/drawable-v28/widgets_bottom_sheet_background.xml b/res/drawable-v28/widgets_bottom_sheet_background.xml
index c3009c3..7fb8681 100644
--- a/res/drawable-v28/widgets_bottom_sheet_background.xml
+++ b/res/drawable-v28/widgets_bottom_sheet_background.xml
@@ -16,7 +16,7 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="@color/widgets_picker_surface" />
+    <solid android:color="@color/surface" />
     <corners
         android:topLeftRadius="?android:attr/dialogCornerRadius"
         android:topRightRadius="?android:attr/dialogCornerRadius"
diff --git a/res/drawable/add_item_dialog_background.xml b/res/drawable/add_item_dialog_background.xml
index 16a0767..c3a8269 100644
--- a/res/drawable/add_item_dialog_background.xml
+++ b/res/drawable/add_item_dialog_background.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
-    <solid android:color="@color/widgets_picker_surface" />
+    <solid android:color="@color/surface" />
     <corners
         android:topLeftRadius="?android:attr/dialogCornerRadius"
         android:topRightRadius="?android:attr/dialogCornerRadius" />
diff --git a/res/drawable/add_item_dialog_button_background.xml b/res/drawable/add_item_dialog_button_background.xml
deleted file mode 100644
index 1b4591f..0000000
--- a/res/drawable/add_item_dialog_button_background.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<inset
-    android:insetLeft="@dimen/pin_widget_button_inset_horizontal"
-    android:insetRight="@dimen/pin_widget_button_inset_horizontal"
-    android:insetTop="@dimen/pin_widget_button_inset_vertical"
-    android:insetBottom="@dimen/pin_widget_button_inset_vertical"
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <ripple
-        android:color="?android:attr/colorControlHighlight">
-        <item>
-            <shape android:tint="?android:attr/colorAccent" android:shape="rectangle">
-                <corners android:radius="18dp" />
-                <solid android:color="#FFFFFF"  />
-                <padding
-                    android:left="@dimen/pin_widget_button_padding_horizontal"
-                    android:top="@dimen/pin_widget_button_padding_vertical"
-                    android:right="@dimen/pin_widget_button_padding_horizontal"
-                    android:bottom="@dimen/pin_widget_button_padding_vertical" />
-            </shape>
-        </item>
-    </ripple>
-</inset>
\ No newline at end of file
diff --git a/res/drawable/arrow_toast_rounded_background.xml b/res/drawable/arrow_toast_rounded_background.xml
index f3f2158..1206ddd 100644
--- a/res/drawable/arrow_toast_rounded_background.xml
+++ b/res/drawable/arrow_toast_rounded_background.xml
@@ -15,5 +15,5 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
     <solid android:color="@color/arrow_tip_view_bg" />
-    <corners android:radius="8dp" />
+    <corners android:radius="@dimen/dialogCornerRadius" />
 </shape>
diff --git a/res/drawable/bg_rounded_corner_bottom_sheet.xml b/res/drawable/bg_rounded_corner_bottom_sheet.xml
new file mode 100644
index 0000000..aa49bce
--- /dev/null
+++ b/res/drawable/bg_rounded_corner_bottom_sheet.xml
@@ -0,0 +1,23 @@
+<?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" >
+    <solid android:color="@color/surface" />
+    <corners
+        android:topLeftRadius="@dimen/dialogCornerRadius"
+        android:topRightRadius="@dimen/dialogCornerRadius" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_searchbox.xml b/res/drawable/bg_widgets_searchbox.xml
index 3230ac8..dc6d868 100644
--- a/res/drawable/bg_widgets_searchbox.xml
+++ b/res/drawable/bg_widgets_searchbox.xml
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
-    <solid android:color="@color/widgets_picker_surface" />
+    <solid android:color="@color/surface" />
     <corners android:radius="24dp" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/button_bottom_rounded_colored_ripple.xml b/res/drawable/button_bottom_rounded_colored_ripple.xml
new file mode 100644
index 0000000..95f5234
--- /dev/null
+++ b/res/drawable/button_bottom_rounded_colored_ripple.xml
@@ -0,0 +1,32 @@
+<?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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners
+                    android:topLeftRadius="4dp"
+                    android:topRightRadius="4dp"
+                    android:bottomLeftRadius="12dp"
+                    android:bottomRightRadius="12dp"  />
+                <solid android:color="@color/button_bg"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/button_rounded_colored_ripple.xml b/res/drawable/button_rounded_colored_ripple.xml
new file mode 100644
index 0000000..f6d689f
--- /dev/null
+++ b/res/drawable/button_rounded_colored_ripple.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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners android:radius="12dp"/>
+                <solid android:color="@color/button_bg"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/button_top_rounded_bordered_ripple.xml b/res/drawable/button_top_rounded_bordered_ripple.xml
new file mode 100644
index 0000000..f15a4a0
--- /dev/null
+++ b/res/drawable/button_top_rounded_bordered_ripple.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners
+                    android:topLeftRadius="12dp"
+                    android:topRightRadius="12dp"
+                    android:bottomLeftRadius="4dp"
+                    android:bottomRightRadius="4dp"  />
+                <solid android:color="@color/surface"/>
+                <stroke
+                    android:width="2dp"
+                    android:color="@color/button_bg"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/full_rounded_colored_ripple.xml b/res/drawable/full_rounded_colored_ripple.xml
new file mode 100644
index 0000000..d89537c
--- /dev/null
+++ b/res/drawable/full_rounded_colored_ripple.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.
+-->
+
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <solid android:color="@color/button_bg"/>
+                <corners android:radius="28dp"/>
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/widgets_bottom_sheet_background.xml b/res/drawable/widgets_bottom_sheet_background.xml
index 2460767..b877546 100644
--- a/res/drawable/widgets_bottom_sheet_background.xml
+++ b/res/drawable/widgets_bottom_sheet_background.xml
@@ -16,7 +16,7 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="@color/widgets_picker_surface" />
+    <solid android:color="@color/surface" />
     <corners
         android:topLeftRadius="@dimen/default_dialog_corner_radius"
         android:topRightRadius="@dimen/default_dialog_corner_radius"
diff --git a/res/drawable/widgets_list_bottom_ripple.xml b/res/drawable/widgets_list_bottom_ripple.xml
index 971d6f3..c2debb1 100644
--- a/res/drawable/widgets_list_bottom_ripple.xml
+++ b/res/drawable/widgets_list_bottom_ripple.xml
@@ -21,7 +21,7 @@
     android:color="?android:attr/colorControlHighlight">
     <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_content_corner_radius"
                 android:topRightRadius="@dimen/widget_list_content_corner_radius"
@@ -31,7 +31,7 @@
     </item>
     <item android:id="@android:id/background">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_content_corner_radius"
                 android:topRightRadius="@dimen/widget_list_content_corner_radius"
diff --git a/res/drawable/widgets_list_middle_ripple.xml b/res/drawable/widgets_list_middle_ripple.xml
index 2b77d4d..83f96a0 100644
--- a/res/drawable/widgets_list_middle_ripple.xml
+++ b/res/drawable/widgets_list_middle_ripple.xml
@@ -21,7 +21,7 @@
     android:color="?android:attr/colorControlHighlight">
     <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_content_corner_radius"
                 android:topRightRadius="@dimen/widget_list_content_corner_radius"
@@ -32,7 +32,7 @@
 
     <item android:id="@android:id/background">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_content_corner_radius"
                 android:topRightRadius="@dimen/widget_list_content_corner_radius"
diff --git a/res/drawable/widgets_list_single_item_ripple.xml b/res/drawable/widgets_list_single_item_ripple.xml
index c09944d..a4223a8 100644
--- a/res/drawable/widgets_list_single_item_ripple.xml
+++ b/res/drawable/widgets_list_single_item_ripple.xml
@@ -21,7 +21,7 @@
     android:color="?android:attr/colorControlHighlight">
     <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
                 android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
@@ -31,7 +31,7 @@
     </item>
     <item android:id="@android:id/background">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
                 android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
diff --git a/res/drawable/widgets_list_top_ripple.xml b/res/drawable/widgets_list_top_ripple.xml
index f79ab72..bc0876e 100644
--- a/res/drawable/widgets_list_top_ripple.xml
+++ b/res/drawable/widgets_list_top_ripple.xml
@@ -21,7 +21,7 @@
     android:color="?android:attr/colorControlHighlight">
     <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
                 android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
@@ -32,7 +32,7 @@
 
     <item android:id="@android:id/background">
         <shape android:shape="rectangle">
-            <solid android:color="@color/widgets_picker_surface" />
+            <solid android:color="@color/surface" />
             <corners
                 android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
                 android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
diff --git a/res/drawable/widgets_recommendation_background.xml b/res/drawable/widgets_recommendation_background.xml
index b59de27..0550a34 100644
--- a/res/drawable/widgets_recommendation_background.xml
+++ b/res/drawable/widgets_recommendation_background.xml
@@ -19,6 +19,6 @@
 -->
 <shape android:shape="rectangle"
     xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/widgets_picker_surface" />
+    <solid android:color="@color/surface" />
     <corners android:radius="@dimen/widget_list_top_bottom_corner_radius"/>
 </shape>
\ No newline at end of file
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 0a3fbbc..ddc9815 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -53,7 +53,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="center_horizontal"
-            android:paddingVertical="8dp"
+            android:paddingTop="8dp"
             android:text="@string/add_item_request_drag_hint"
             android:textSize="14sp"
             android:textColor="?android:attr/textColorSecondary"
@@ -70,28 +70,33 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:gravity="end"
-            android:padding="8dp"
+            android:gravity="center_vertical|end"
+            android:paddingHorizontal="24dp"
+            android:paddingVertical="8dp"
             android:orientation="horizontal">
             <Button
-                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                style="@style/Button.FullRounded.Colored"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="36dp"
                 android:paddingHorizontal="16dp"
-                android:onClick="onCancelClick"
-                android:text="@android:string/cancel" />
+                android:textSize="14sp"
+                android:textColor="@color/button_text"
+                android:text="@android:string/cancel"
+                android:onClick="onCancelClick"/>
 
             <Space
-                android:layout_width="4dp"
+                android:layout_width="8dp"
                 android:layout_height="wrap_content" />
 
             <Button
-                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                style="@style/Button.FullRounded.Colored"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
+                android:layout_height="36dp"
                 android:paddingHorizontal="16dp"
-                android:onClick="onPlaceAutomaticallyClick"
-                android:text="@string/add_to_home_screen"/>
+                android:textSize="14sp"
+                android:textColor="@color/button_text"
+                android:text="@string/add_to_home_screen"
+                android:onClick="onPlaceAutomaticallyClick"/>
         </LinearLayout>
     </com.android.launcher3.widget.AddItemWidgetsBottomSheet>
 
diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml
index c071bec..aee00a9 100644
--- a/res/layout/arrow_toast.xml
+++ b/res/layout/arrow_toast.xml
@@ -14,46 +14,22 @@
      limitations under the License.
 -->
 
-<merge xmlns:android="http://schemas.android.com/apk/res/android"
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
     android:layout_width="wrap_content">
 
-    <LinearLayout
+    <TextView
+        android:id="@+id/text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:paddingStart="24dp"
-        android:paddingEnd="4dp"
-        android:background="@drawable/arrow_toast_rounded_background"
         android:layout_gravity="center_horizontal"
+        android:gravity="center"
+        android:padding="16dp"
+        android:background="@drawable/arrow_toast_rounded_background"
         android:elevation="2dp"
-        android:orientation="horizontal">
-
-        <TextView
-            android:id="@+id/text"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:paddingTop="5dp"
-            android:paddingBottom="5dp"
-            android:gravity="center"
-            android:layout_gravity="center_vertical"
-            android:textColor="@color/arrow_tip_view_content"
-            android:textSize="16sp" />
-
-        <ImageView
-            android:id="@+id/dismiss"
-            android:layout_width="40dp"
-            android:layout_height="40dp"
-            android:layout_gravity="center_vertical"
-            android:padding="10dp"
-            android:layout_marginStart="2dp"
-            android:layout_marginEnd="2dp"
-            android:alpha="0.7"
-            android:src="@drawable/ic_remove_no_shadow"
-            android:tint="@color/arrow_tip_view_content"
-            android:background="?android:attr/selectableItemBackgroundBorderless"
-            android:contentDescription="@string/accessibility_close" />
-    </LinearLayout>
+        android:textColor="@color/arrow_tip_view_content"
+        android:textSize="14sp"/>
 
     <View
         android:id="@+id/arrow"
diff --git a/res/layout/settings_activity.xml b/res/layout/settings_activity.xml
new file mode 100644
index 0000000..c70d5bf
--- /dev/null
+++ b/res/layout/settings_activity.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <Toolbar
+        android:id="@+id/action_bar"
+        style="?android:attr/actionBarStyle"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:theme="?android:attr/actionBarTheme" />
+
+    <FrameLayout
+        android:id="@+id/content_frame"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/widgets_edu.xml b/res/layout/widgets_edu.xml
new file mode 100644
index 0000000..280c095
--- /dev/null
+++ b/res/layout/widgets_edu.xml
@@ -0,0 +1,66 @@
+<?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.
+-->
+
+<com.android.launcher3.views.WidgetsEduView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom"
+    android:gravity="bottom"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/edu_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/bg_rounded_corner_bottom_sheet"
+        android:gravity="center_horizontal"
+        android:orientation="vertical"
+        android:paddingHorizontal="@dimen/bottom_sheet_edu_padding"
+        android:paddingTop="@dimen/bottom_sheet_edu_padding">
+
+        <TextView
+            style="@style/TextHeadline"
+            android:id="@+id/edu_header"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:text="@string/widget_education_header"
+            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="24sp"
+            android:layout_marginBottom="16dp"/>
+
+        <TextView
+            android:id="@+id/edu_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:text="@string/widget_education_content"
+            android:textSize="14sp"
+            android:textColor="?android:attr/textColorSecondary"
+            android:layout_marginBottom="24dp"/>
+
+        <Button
+            android:id="@+id/edu_close_button"
+            style="@style/Button.Rounded.Colored"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:text="@string/widget_education_close_button"
+            android:textSize="16sp"
+            android:textColor="@color/button_text"
+            android:layout_marginBottom="8dp"/>
+    </LinearLayout>
+</com.android.launcher3.views.WidgetsEduView>
\ No newline at end of file
diff --git a/res/values-v28/dimens.xml b/res/values-v28/dimens.xml
new file mode 100644
index 0000000..ffa8cc4
--- /dev/null
+++ b/res/values-v28/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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>
+    <dimen name="dialogCornerRadius">?android:attr/dialogCornerRadius</dimen>
+</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 6158e94..d6a6f43 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -149,7 +149,7 @@
     <dimen name="widget_row_padding">8dp</dimen>
     <dimen name="widget_row_divider">2dp</dimen>
 
-    <dimen name="widget_picker_education_tip_width">120dp</dimen>
+    <dimen name="widget_picker_education_tip_max_width">308dp</dimen>
     <dimen name="widget_picker_education_tip_min_margin">4dp</dimen>
 
     <dimen name="widget_picker_view_pager_top_padding">10dp</dimen>
@@ -288,6 +288,7 @@
 
 <!-- Theming related -->
     <dimen name="default_dialog_corner_radius">8dp</dimen>
+    <dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
 
     <!-- Onboarding bottomsheet related -->
     <dimen name="bottom_sheet_edu_padding">24dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eae32b7..c851cf8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -99,6 +99,15 @@
     <!-- A widget category label for grouping widgets related to conversations. [CHAR_LIMIT=30] -->
     <string name="widget_category_conversations">Conversations</string>
 
+    <!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
+         [CHAR_LIMIT=NONE] -->
+    <string name="widget_education_header">Useful info at your fingertips</string>
+    <!-- Dialog text. This dialog lets a user know how they can use widgets on their phone.
+         [CHAR_LIMIT=NONE] -->
+    <string name="widget_education_content">To get info without opening apps, you can add widgets to your Home screen</string>
+    <!-- Text on the button that closes the education dialog about widgets. [CHAR_LIMIT=50] -->
+    <string name="widget_education_close_button">Got it</string>
+
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
     <string name="all_apps_search_bar_hint">Search apps</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index df617ea..92824ad 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -48,7 +48,7 @@
         <item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="folderDotColor">?android:attr/colorPrimary</item>
-        <item name="folderFillColor">?android:attr/colorBackground</item>
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
         <item name="folderTextColor">?android:attr/textColorPrimary</item>
         <item name="isFolderDarkText">true</item>
@@ -71,7 +71,7 @@
     </style>
 
     <style name="LauncherTheme.DarkMainColor" parent="@style/LauncherTheme">
-        <item name="folderFillColor">#FF3C4043</item> <!-- 100% GM2 800 -->
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderTextColor">?attr/workspaceTextColor</item>
         <item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
         <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
@@ -87,7 +87,7 @@
         <item name="isWorkspaceDarkText">true</item>
         <item name="workspaceStatusBarScrim">@null</item>
         <item name="folderDotColor">#FF464646</item>
-        <item name="folderFillColor">#CDFFFFFF</item>
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderIconBorderColor">#FF80868B</item>
         <item name="folderTextColor">?attr/workspaceTextColor</item>
         <item name="isFolderDarkText">true</item>
@@ -109,7 +109,7 @@
         <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
         <item name="folderDotColor">?android:attr/colorPrimary</item>
-        <item name="folderFillColor">?android:attr/colorBackground</item>
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
         <item name="folderTextColor">?android:attr/textColorPrimary</item>
         <item name="isFolderDarkText">false</item>
@@ -123,7 +123,7 @@
     </style>
 
     <style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
-        <item name="folderFillColor">#FF3C4043</item> <!-- 100% GM2 800 -->
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderTextColor">@android:color/white</item>
         <item name="isFolderDarkText">false</item>
         <item name="folderHintColor">@color/folder_hint_text_color_light</item>
@@ -132,7 +132,7 @@
 
     <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
         <item name="android:colorControlHighlight">#19212121</item>
-        <item name="folderFillColor">#CDFFFFFF</item>
+        <item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
         <item name="folderTextColor">?attr/workspaceTextColor</item>
         <item name="isFolderDarkText">?attr/isWorkspaceDarkText</item>
         <item name="folderHintColor">@color/folder_hint_text_color_dark</item>
@@ -156,6 +156,8 @@
 
     <style name="HomeSettingsTheme" 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>
     </style>
 
@@ -240,7 +242,7 @@
 
 
     <!-- Icon displayed on the workspace -->
-    <style name="BaseIcon.Workspace" >
+    <style name="BaseIcon.Workspace.Shadows" parent="BaseIcon">
         <item name="android:shadowRadius">2.0</item>
         <item name="android:shadowColor">?attr/workspaceShadowColor</item>
         <item name="ambientShadowColor">?attr/workspaceAmbientShadowColor</item>
@@ -251,6 +253,10 @@
         <item name="keyShadowOffsetY">.5dp</item>
     </style>
 
+    <!-- Intentionally empty so we can override -->
+    <style name="BaseIcon.Workspace" parent="BaseIcon.Workspace.Shadows">
+    </style>
+
     <!-- Theme for the popup container -->
     <style name="PopupItem">
         <item name="android:colorControlHighlight">?attr/popupColorTertiary</item>
@@ -287,8 +293,24 @@
         <item name="android:colorForeground">@color/all_apps_bg_hand_fill_dark</item>
     </style>
 
-    <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">
-        <item name="android:background">@drawable/add_item_dialog_button_background</item>
+    <style name="Button.TopRounded.Bordered" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/button_top_rounded_bordered_ripple</item>
+        <item name="android:stateListAnimator">@null</item>
+    </style>
+
+    <style name="Button.BottomRounded.Colored" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/button_bottom_rounded_colored_ripple</item>
+        <item name="android:stateListAnimator">@null</item>
+    </style>
+
+    <style name="Button.Rounded.Colored" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/button_rounded_colored_ripple</item>
+        <item name="android:stateListAnimator">@null</item>
+    </style>
+
+    <style name="Button.FullRounded.Colored" parent="@android:style/Widget.Material.Button">
+        <item name="android:background">@drawable/full_rounded_colored_ripple</item>
+        <item name="android:stateListAnimator">@null</item>
     </style>
 
     <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
diff --git a/res/xml/size_limits_80x104.xml b/res/xml/size_limits_80x104.xml
index f375549..f5ca757 100644
--- a/res/xml/size_limits_80x104.xml
+++ b/res/xml/size_limits_80x104.xml
@@ -62,10 +62,10 @@
     <device-padding
         launcher:maxEmptySpace="9999dp">
         <workspaceTopPadding
-            launcher:a="0.38"
+            launcher:a="0.40"
             launcher:c="36dp"/>
         <workspaceBottomPadding
-            launcher:a="0.62"
+            launcher:a="0.60"
             launcher:c="36dp"/>
         <hotseatBottomPadding
             launcher:a="0"
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 9100947..4979b40 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -63,7 +63,8 @@
             TYPE_TASK_MENU,
             TYPE_OPTIONS_POPUP,
             TYPE_ICON_SURFACE,
-            TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
+            TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP,
+            TYPE_WIDGETS_EDUCATION_DIALOG
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FloatingViewType {}
@@ -85,17 +86,19 @@
     public static final int TYPE_ICON_SURFACE = 1 << 13;
 
     public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 14;
+    public static final int TYPE_WIDGETS_EDUCATION_DIALOG = 1 << 15;
 
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
             | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
             | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
-            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP;
+            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
+            | TYPE_WIDGETS_EDUCATION_DIALOG;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
-            | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE;
+            | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG;
 
     // Usually we show the back button when a floating view is open. Instead, hide for these types.
     public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index d977620..97a44c1 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -253,6 +253,15 @@
         forceFinishScroller(true);
     }
 
+    /**
+     *  Immediately finishes any overscroll effect and jumps to the end of the scroller animation.
+     */
+    public void abortScrollerAnimation() {
+        mEdgeGlowLeft.finish();
+        mEdgeGlowRight.finish();
+        abortScrollerAnimation(true);
+    }
+
     private void abortScrollerAnimation(boolean resetNextPage) {
         mScroller.abortAnimation();
         // We need to clean up the next page here to avoid computeScrollHelper from
@@ -506,11 +515,9 @@
                 if (newPos < mMinScroll && oldPos >= mMinScroll) {
                     mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
                     mScroller.abortAnimation();
-                    onEdgeAbsorbingScroll();
                 } else if (newPos > mMaxScroll && oldPos <= mMaxScroll) {
                     mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
                     mScroller.abortAnimation();
-                    onEdgeAbsorbingScroll();
                 }
             }
 
@@ -1361,13 +1368,6 @@
 
     protected void onNotSnappingToPageInFreeScroll() { }
 
-    /**
-     * Called when the view edges absorb part of the scroll. Subclasses can override this
-     * to provide custom behavior during animation.
-     */
-    protected void onEdgeAbsorbingScroll() {
-    }
-
     protected boolean shouldFlingForVelocity(int velocity) {
         float threshold = mAllowEasyFling ? mEasyFlingThresholdVelocity : mFlingThresholdVelocity;
         return Math.abs(velocity) > threshold;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 78e8048..9a8f3dd 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -106,6 +106,7 @@
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.OverlayEdgeEffect;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
@@ -429,10 +430,9 @@
         // When a accessible drag is started by the folder, we only allow rearranging withing the
         // folder.
         boolean addNewPage = !(options.isAccessibleDrag && dragObject.dragSource != this);
-
         if (addNewPage) {
             mDeferRemoveExtraEmptyScreen = false;
-            addExtraEmptyScreenOnDrag();
+            addExtraEmptyScreenOnDrag(dragObject);
 
             if (dragObject.dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
                     && dragObject.dragSource != this) {
@@ -640,12 +640,19 @@
         return newScreen;
     }
 
-    public void addExtraEmptyScreenOnDrag() {
+    private void addExtraEmptyScreenOnDrag(DragObject dragObject) {
         boolean lastChildOnScreen = false;
         boolean childOnFinalScreen = false;
 
         if (mDragSourceInternal != null) {
-            if (mDragSourceInternal.getChildCount() == 1) {
+            // When the drag view content is a LauncherAppWidgetHostView, we should increment the
+            // drag source child count by 1 because the widget in drag has been detached from its
+            // original parent, ShortcutAndWidgetContainer, and reattached to the DragView.
+            int dragSourceChildCount =
+                    dragObject.dragView.getContentView() instanceof LauncherAppWidgetHostView
+                            ? mDragSourceInternal.getChildCount() + 1
+                            : mDragSourceInternal.getChildCount();
+            if (dragSourceChildCount == 1) {
                 lastChildOnScreen = true;
             }
             CellLayout cl = (CellLayout) mDragSourceInternal.getParent();
@@ -1925,10 +1932,16 @@
                 if (droppedOnOriginalCellDuringTransition) {
                     // Animate the item to its original position, while simultaneously exiting
                     // spring-loaded mode so the page meets the icon where it was picked up.
+                    final RunnableList callbackList = new RunnableList();
+                    final Runnable onCompleteCallback = onCompleteRunnable;
                     mLauncher.getDragController().animateDragViewToOriginalPosition(
-                            onCompleteRunnable, cell,
+                            /* onComplete= */ callbackList::executeAllAndDestroy, cell,
                             SPRING_LOADED.getTransitionDuration(mLauncher));
-                    mLauncher.getStateManager().goToState(NORMAL);
+                    mLauncher.getStateManager().goToState(NORMAL, /* delay= */ 0,
+                            onCompleteCallback == null
+                                    ? null
+                                    : forSuccessCallback(
+                                            () -> callbackList.add(onCompleteCallback)));
                     mLauncher.getDropTargetBar().onDragEnd();
                     parent.onDropChild(cell);
                     return;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 0336c50..cebdc1f 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -238,7 +238,7 @@
             "Sends a notification whenever launcher encounters an uncaught exception.");
 
     public static final BooleanFlag PROTOTYPE_APP_CLOSE = getDebugFlag(
-            "PROTOTYPE_APP_CLOSE", true, "Enables new app close");
+            "PROTOTYPE_APP_CLOSE", false, "Enables new app close");
 
     public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(
             "ENABLE_WALLPAPER_SCRIM", false,
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 5ddf84f..4eab63e 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -89,8 +89,8 @@
     private static final float ACCEPT_COLOR_MULTIPLIER = 1.5f;
 
     // Expressed on a scale from 0 to 255.
-    private static final int BG_OPACITY = 160;
-    private static final int MAX_BG_OPACITY = 225;
+    private static final int BG_OPACITY = 255;
+    private static final int MAX_BG_OPACITY = 255;
     private static final int SHADOW_OPACITY = 40;
 
     private ValueAnimator mScaleAnimator;
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 8ca157b..e4f5539 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -1,6 +1,7 @@
 package com.android.launcher3.graphics;
 
 import static com.android.launcher3.Utilities.getPrefs;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
 import static com.android.launcher3.util.Themes.isThemedIconEnabled;
 
@@ -18,7 +19,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.util.ArrayMap;
@@ -217,7 +217,8 @@
             Bundle result = new Bundle();
             result.putParcelable(KEY_SURFACE_PACKAGE, renderer.getSurfacePackage());
 
-            Messenger messenger = new Messenger(new Handler(Looper.getMainLooper(), observer));
+            Messenger messenger =
+                    new Messenger(new Handler(UI_HELPER_EXECUTOR.getLooper(), observer));
             Message msg = Message.obtain();
             msg.replyTo = messenger;
             result.putParcelable(KEY_CALLBACK, msg);
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 85c2492..05927ef 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -80,6 +80,8 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setContentView(R.layout.settings_activity);
+        setActionBar(findViewById(R.id.action_bar));
 
         if (savedInstanceState == null) {
             Intent intent = getIntent();
@@ -98,7 +100,7 @@
                     getPreferenceFragment());
             f.setArguments(args);
             // Display the fragment as the main content.
-            fm.beginTransaction().replace(android.R.id.content, f).commit();
+            fm.beginTransaction().replace(R.id.content_frame, f).commit();
         }
         Utilities.getPrefs(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
     }
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 14bf6c2..b0defd4 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -21,19 +21,15 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
-import android.media.AudioAttributes;
 import android.os.Build;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
 
-import com.android.launcher3.Utilities;
-
 /**
  * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
  */
@@ -43,11 +39,6 @@
     public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
             new MainThreadInitializedObject<>(VibratorWrapper::new);
 
-    public static final AudioAttributes VIBRATION_ATTRS = new AudioAttributes.Builder()
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .build();
-
     public static final VibrationEffect EFFECT_CLICK =
             createPredefined(VibrationEffect.EFFECT_CLICK);
 
@@ -90,24 +81,4 @@
             UI_HELPER_EXECUTOR.execute(() -> mVibrator.vibrate(vibrationEffect));
         }
     }
-
-    /**
-     * Vibrates with a single primitive, if supported, or use a fallback effect instead. This only
-     * vibrates if haptic feedback is available and enabled.
-     */
-    @SuppressLint("NewApi")
-    public void vibrate(int primitiveId, float primitiveScale, VibrationEffect fallbackEffect) {
-        if (mHasVibrator && mIsHapticFeedbackEnabled) {
-            UI_HELPER_EXECUTOR.execute(() -> {
-                if (Utilities.ATLEAST_R && primitiveId >= 0
-                        && mVibrator.areAllPrimitivesSupported(primitiveId)) {
-                    mVibrator.vibrate(VibrationEffect.startComposition()
-                            .addPrimitive(primitiveId, primitiveScale)
-                            .compose(), VIBRATION_ATTRS);
-                } else {
-                    mVibrator.vibrate(fallbackEffect, VIBRATION_ATTRS);
-                }
-            });
-        }
-    }
 }
diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
index ef3df5f..07d3776 100644
--- a/src/com/android/launcher3/views/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -105,10 +105,6 @@
     private void init(Context context) {
         inflate(context, R.layout.arrow_toast, this);
         setOrientation(LinearLayout.VERTICAL);
-        View dismissButton = findViewById(R.id.dismiss);
-        dismissButton.setOnClickListener(view -> {
-            handleClose(true);
-        });
 
         View arrowView = findViewById(R.id.arrow);
         ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams();
@@ -194,18 +190,18 @@
     public ArrowTipView showAtLocation(String text, int arrowXCoord, int yCoord) {
         ViewGroup parent = mActivity.getDragLayer();
         @Px int parentViewWidth = parent.getWidth();
-        @Px int textViewWidth = getContext().getResources()
-                .getDimensionPixelSize(R.dimen.widget_picker_education_tip_width);
+        @Px int maxTextViewWidth = getContext().getResources()
+                .getDimensionPixelSize(R.dimen.widget_picker_education_tip_max_width);
         @Px int minViewMargin = getContext().getResources()
                 .getDimensionPixelSize(R.dimen.widget_picker_education_tip_min_margin);
-        if (parentViewWidth < textViewWidth + 2 * minViewMargin) {
+        if (parentViewWidth < maxTextViewWidth + 2 * minViewMargin) {
             Log.w(TAG, "Cannot display tip on a small screen of size: " + parentViewWidth);
             return null;
         }
 
         TextView textView = findViewById(R.id.text);
         textView.setText(text);
-        textView.setWidth(textViewWidth);
+        textView.setMaxWidth(maxTextViewWidth);
         parent.addView(this);
         requestLayout();
 
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
new file mode 100644
index 0000000..e69cb5b
--- /dev/null
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -0,0 +1,118 @@
+/*
+ * 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.views;
+
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+/**
+ * Education view about widgets.
+ */
+public class WidgetsEduView extends AbstractSlideInView<Launcher> implements Insettable {
+
+    private static final int DEFAULT_CLOSE_DURATION = 200;
+
+    protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
+
+    private Rect mInsets = new Rect();
+    private View mEduView;
+
+
+    public WidgetsEduView(Context context, AttributeSet attr) {
+        this(context, attr, 0);
+    }
+
+    public WidgetsEduView(Context context, AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContent = this;
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        handleClose(true, DEFAULT_CLOSE_DURATION);
+    }
+
+    @Override
+    protected boolean isOfType(int type) {
+        return (type & TYPE_WIDGETS_EDUCATION_DIALOG) != 0;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mEduView = findViewById(R.id.edu_view);
+        findViewById(R.id.edu_close_button)
+                .setOnClickListener(v -> close(/* animate= */ true));
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        int leftInset = insets.left - mInsets.left;
+        int rightInset = insets.right - mInsets.right;
+        int bottomInset = insets.bottom - mInsets.bottom;
+        mInsets.set(insets);
+        setPadding(leftInset, getPaddingTop(), rightInset, 0);
+        mEduView.setPaddingRelative(mEduView.getPaddingStart(),
+                mEduView.getPaddingTop(), mEduView.getPaddingEnd(), bottomInset);
+    }
+
+    private void show() {
+        attachToContainer();
+        animateOpen();
+    }
+
+    @Override
+    protected int getScrimColor(Context context) {
+        return FINAL_SCRIM_BG_COLOR;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        setTranslationShift(mTranslationShift);
+    }
+
+    private void animateOpen() {
+        if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+            return;
+        }
+        mIsOpen = true;
+        mOpenCloseAnimator.setValues(
+                PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+        mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        mOpenCloseAnimator.start();
+    }
+
+    /** Shows widget education dialog. */
+    public static WidgetsEduView showEducationDialog(Launcher launcher) {
+        LayoutInflater layoutInflater = LayoutInflater.from(launcher);
+        WidgetsEduView v = (WidgetsEduView) layoutInflater.inflate(
+                R.layout.widgets_edu, launcher.getDragLayer(), false);
+        v.show();
+        return v;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 62af283..92f84da 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -49,11 +49,14 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.views.ArrowTipView;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.TopRoundedCornerView;
+import com.android.launcher3.views.WidgetsEduView;
 import com.android.launcher3.widget.BaseWidgetSheet;
 import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -79,12 +82,16 @@
     private static final long DEFAULT_OPEN_DURATION = 267;
     private static final long FADE_IN_DURATION = 150;
     private static final long EDUCATION_TIP_DELAY_MS = 200;
+    private static final long EDUCATION_DIALOG_DELAY_MS = 500;
     private static final float VERTICAL_START_POSITION = 0.3f;
     // The widget recommendation table can easily take over the entire screen on devices with small
     // resolution or landscape on phone. This ratio defines the max percentage of content area that
     // the table can display.
     private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
 
+    private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
+            "launcher.widgets_education_dialog_seen";
+
     private final Rect mInsets = new Rect();
     private final boolean mHasWorkProfile;
     private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
@@ -93,6 +100,7 @@
             entry -> mCurrentUser.equals(entry.mPkgItem.user);
     private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
             mPrimaryWidgetsFilter.negate();
+    @Nullable private ArrowTipView mLatestEducationalTip;
     private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
             new OnLayoutChangeListener() {
                 @Override
@@ -116,11 +124,12 @@
             removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
             return;
         }
-        View viewForTip = getViewToShowEducationTip();
-        if (showEducationTipOnViewIfPossible(viewForTip) != null) {
+        mLatestEducationalTip = showEducationTipOnViewIfPossible(getViewToShowEducationTip());
+        if (mLatestEducationalTip != null) {
             removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
         }
     };
+
     private final int mTabsHeight;
     private final int mViewPagerTopPadding;
     private final int mSearchAndRecommendationContainerBottomMargin;
@@ -221,9 +230,7 @@
         mSearchAndRecommendationViewHolder.mSearchBar.initialize(
                 mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
 
-        if (!hasSeenEducationTip()) {
-            addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
-        }
+        setUpEducationViewsIfNeeded();
     }
 
     @Override
@@ -608,6 +615,10 @@
     @Override
     protected void onCloseComplete() {
         super.onCloseComplete();
+        removeCallbacks(mShowEducationTipTask);
+        if (mLatestEducationalTip != null) {
+            mLatestEducationalTip.close(false);
+        }
         AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
     }
 
@@ -680,6 +691,38 @@
         return null;
     }
 
+    /** Shows education dialog for widgets. */
+    private WidgetsEduView showEducationDialog() {
+        mActivityContext.getSharedPrefs().edit()
+                .putBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, true).apply();
+        return WidgetsEduView.showEducationDialog(mActivityContext);
+    }
+
+    /** Returns {@code true} if education dialog has previously been shown. */
+    protected boolean hasSeenEducationDialog() {
+        return mActivityContext.getSharedPrefs()
+                .getBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, false)
+                || Utilities.IS_RUNNING_IN_TEST_HARNESS;
+    }
+
+    private void setUpEducationViewsIfNeeded() {
+        if (!hasSeenEducationDialog()) {
+            postDelayed(() -> {
+                WidgetsEduView eduDialog = showEducationDialog();
+                eduDialog.addOnCloseListener(() -> {
+                    if (!hasSeenEducationTip()) {
+                        addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
+                        // Call #requestLayout() to trigger layout change listener in order to show
+                        // arrow tip immediately if there is a widget to show it on.
+                        requestLayout();
+                    }
+                });
+            }, EDUCATION_DIALOG_DELAY_MS);
+        } else if (!hasSeenEducationTip()) {
+            addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
+        }
+    }
+
     /** A holder class for holding adapters & their corresponding recycler view. */
     private final class AdapterHolder {
         static final int PRIMARY = 0;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 4cf52f0..c99a81f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -105,7 +105,7 @@
     static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
     static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
     private final String mLauncherPackage;
-    private final boolean mIsLauncher3;
+    private Boolean mIsLauncher3;
     private long mTestStartTime = -1;
 
     // Types for launcher containers that the user is interacting with. "Background" is a
@@ -206,7 +206,6 @@
     public LauncherInstrumentation(Instrumentation instrumentation) {
         mInstrumentation = instrumentation;
         mDevice = UiDevice.getInstance(instrumentation);
-        mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
 
         // Launcher should run in test harness so that custom accessibility protocol between
         // Launcher and TAPL is enabled. In-process tests enable this protocol with a direct call
@@ -1422,6 +1421,9 @@
     }
 
     boolean isLauncher3() {
+        if (mIsLauncher3 == null) {
+            mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
+        }
         return mIsLauncher3;
     }