Merge "Measure WidgetsFullSheet before estimating the recommended table size" into sc-dev
diff --git a/lint-baseline-launcher3.xml b/lint-baseline-launcher3.xml
index 469ad94..9a68405 100644
--- a/lint-baseline-launcher3.xml
+++ b/lint-baseline-launcher3.xml
@@ -573,4 +573,26 @@
             column="42"/>
     </issue>
 
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#setColorResources`"
+        errorLine1="            view.setColorResources(mWallpaperColorResources);"
+        errorLine2="                 ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
+            line="381"
+            column="18"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 27 (current min is 26): `android.app.WallpaperManager#getWallpaperColors`"
+        errorLine1="                    : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);"
+        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
+            line="270"
+            column="61"/>
+    </issue>
+
 </issues>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 86f9017..23ffad3 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -46,7 +46,7 @@
     <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सुझाए गए ऐप्लिकेशन की सुविधा बंद है"</string>
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"सुझाया गया ऐप्लिकेशन: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिल्कुल किनारे से स्वाइप कर रहे हों."</string>
-    <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"पक्का करें कि आप स्क्रीन के दाएं या बाएं किनारे से, स्क्रीन के बीच तक स्वाइप करें और फिर अपनी उंगली उठा लें."</string>
+    <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"स्क्रीन के दाएं या बाएं किनारे से स्क्रीन के बीच तक स्वाइप करें और अपनी उंगली उठा लें."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"आपने पेज पर पीछे ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"देखे लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों."</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 3ee1b99..9c2adef 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -48,16 +48,16 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"右端または左端からスワイプしてください。"</string>
     <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"画面の右端または左端から中央に向かってスワイプし、指を離してください。"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"</string>
-    <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"「戻る」操作を完了しました。"</string>
+    <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"「戻る」操作を学習しました。"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"スワイプする際は画面の下部に近づきすぎないようにしましょう。"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"「戻る」操作の感度を変更するには [設定] に移動します"</string>
-    <string name="back_gesture_intro_title" msgid="19551256430224428">"スワイプで戻りましょう"</string>
+    <string name="back_gesture_intro_title" msgid="19551256430224428">"スワイプで戻る"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"直前の画面に戻るには、画面の左端または右端から中央に向かってスワイプします。"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"画面の下端から上にスワイプしてください。"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"指を離す前にいったん止めないでください。"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"まっすぐ上にスワイプしてください。"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"「ホームに戻る」操作を完了しました。次は、前の画面に戻る方法を覚えましょう。"</string>
-    <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"「ホームに戻る」操作を完了しました。"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"「ホームに戻る」操作を学習しました。次は、前の画面に戻る方法を覚えましょう。"</string>
+    <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"「ホームに戻る」操作を学習しました。"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"スワイプでホームに戻る"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"画面の下端から上にスワイプしてください。"</string>
@@ -65,7 +65,7 @@
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"まっすぐ上にスワイプしてから、いったん指を止めてください。"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"主な操作方法を覚えました。操作を OFF にするには、設定に移動してください。"</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"「アプリを切り替える」操作を完了しました。"</string>
-    <string name="overview_gesture_intro_title" msgid="2902054412868489378">"スワイプでアプリを切り替え"</string>
+    <string name="overview_gesture_intro_title" msgid="2902054412868489378">"スワイプでアプリを切り替える"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"アプリを切り替えるには、画面を下から上にスワイプして長押しし、指を離します。"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"設定完了"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"完了"</string>
@@ -81,7 +81,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string>
-    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"これは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
+    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"チュートリアルは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"キャンセル"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string>
 </resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index dfa98e7..79fbca6 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -47,7 +47,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Таамаглаж буй апп: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Та баруун зах эсвэл зүүн захын булангаас шударна уу."</string>
     <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Та баруун эсвэл зүүн булангаас дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу."</string>
-    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа Дараа нь аппыг хэрхэн сэлгэхийг мэдэж аваарай."</string>
+    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Та буцах зангааг гүйцэтгэлээ."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 4428cec..d873795 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -23,7 +23,7 @@
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
-    <string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका एपहरू"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
     <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; १ मिनेट"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 96e9060..52b2878 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -81,7 +81,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ข้ามบทแนะนำการนำทางไหม"</string>
-    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ยกเลิก"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ข้าม"</string>
 </resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 6c192b2..7bd0c70 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -47,11 +47,11 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Ứng dụng dự đoán: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Hãy vuốt từ mép ngoài cùng bên phải hoặc ngoài cùng bên trái."</string>
     <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi thả tay ra."</string>
-    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã tìm hiểu cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
+    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Bạn đã thực hiện xong cử chỉ quay lại."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Hãy nhớ không được vuốt quá gần phần cuối màn hình."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"</string>
-    <string name="back_gesture_intro_title" msgid="19551256430224428">"Hãy vuốt để quay lại"</string>
+    <string name="back_gesture_intro_title" msgid="19551256430224428">"Vuốt để quay lại"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Để quay lại màn hình gần đây nhất, hãy vuốt từ mép trái hoặc mép phải tới chính giữa màn hình."</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Hãy vuốt lên từ mép dưới cùng của màn hình."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Hãy nhớ không được tạm dừng trước khi nhấc ngón tay."</string>
@@ -75,7 +75,7 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Hướng dẫn <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Đã hoàn tất!"</string>
     <string name="allset_hint" msgid="2384632994739392447">"Vuốt lên để chuyển đến Màn hình chính"</string>
-    <string name="allset_description" msgid="6350320429953234580">"Hiện giờ, bạn đã có thể sử dụng điện thoại"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Vậy là bạn đã sẵn sàng sử dụng điện thoại của mình"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Chế độ cài đặt di chuyển trên hệ thống"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 82582ee..370fb8e 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -100,9 +100,12 @@
                 }
             };
 
-    private final Consumer<Boolean> mCrossWindowBlurListener = (enabled) -> {
-        mCrossWindowBlursEnabled = enabled;
-        dispatchTransactionSurface();
+    private final Consumer<Boolean> mCrossWindowBlurListener = new Consumer<Boolean>() {
+        @Override
+        public void accept(Boolean enabled) {
+            mCrossWindowBlursEnabled = enabled;
+            dispatchTransactionSurface(mDepth);
+        }
     };
 
     private final Launcher mLauncher;
@@ -189,14 +192,14 @@
         if (mSurface != surface) {
             mSurface = surface;
             if (surface != null) {
-                dispatchTransactionSurface();
+                dispatchTransactionSurface(mDepth);
             }
         }
     }
 
     @Override
     public void setState(LauncherState toState) {
-        if (mIgnoreStateChangesDuringMultiWindowAnimation) {
+        if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) {
             return;
         }
 
@@ -204,7 +207,7 @@
         if (Float.compare(mDepth, toDepth) != 0) {
             setDepth(toDepth);
         } else if (toState == LauncherState.OVERVIEW) {
-            dispatchTransactionSurface();
+            dispatchTransactionSurface(mDepth);
         }
     }
 
@@ -243,31 +246,36 @@
         if (Float.compare(mDepth, depthF) == 0) {
             return;
         }
-        mDepth = depthF;
-        dispatchTransactionSurface();
+        if (dispatchTransactionSurface(depthF)) {
+            mDepth = depthF;
+        }
     }
 
-    private void dispatchTransactionSurface() {
+    private boolean dispatchTransactionSurface(float depth) {
         boolean supportsBlur = BlurUtils.supportsBlursOnWindows();
+        if (supportsBlur && (mSurface == null || !mSurface.isValid())) {
+            return false;
+        }
         ensureDependencies();
         IBinder windowToken = mLauncher.getRootView().getWindowToken();
         if (windowToken != null) {
-            mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
+            mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
         }
 
-        if (supportsBlur && (mSurface != null && mSurface.isValid())) {
+        if (supportsBlur) {
             // We cannot mark the window as opaque in overview because there will be an app window
             // below the launcher layer, and we need to draw it -- without blurs.
             boolean isOverview = mLauncher.isInState(LauncherState.OVERVIEW);
             boolean opaque = mLauncher.getScrimView().isFullyOpaque() && !isOverview;
 
             int blur = opaque || isOverview || !mCrossWindowBlursEnabled
-                    || mBlurDisabledForAppLaunch ? 0 : (int) (mDepth * mMaxBlurRadius);
+                    || mBlurDisabledForAppLaunch ? 0 : (int) (depth * mMaxBlurRadius);
             new SurfaceControl.Transaction()
                     .setBackgroundBlurRadius(mSurface, blur)
                     .setOpaque(mSurface, opaque)
                     .apply();
         }
+        return true;
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 069ed11..b6dc833 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -564,8 +564,7 @@
                 } else {
                     mUncheckedConsumer = InputConsumer.NO_OP;
                 }
-            } else if (mDeviceState.canTriggerOneHandedAction(event)
-                    && !mDeviceState.isOneHandedModeActive()) {
+            } else if (mDeviceState.canTriggerOneHandedAction(event)) {
                 // Consume gesture event for triggering one handed feature.
                 mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
                         InputConsumer.NO_OP, mInputMonitorCompat);
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index f67940a..04a7baa 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -17,13 +17,10 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -35,7 +32,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.ViewGroup;
+import android.view.View;
 
 import androidx.core.graphics.ColorUtils;
 
@@ -44,25 +41,21 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
 import com.android.launcher3.util.Themes;
 import com.android.quickstep.util.MultiValueUpdateListener;
 
 /**
  * View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
- * Consumes all touches until after the animation is completed and the view is removed.
+ * If the user drags on the view, the animation is overridden so the user can swipe to All Apps or
+ * Home.
  */
 public class AllAppsEduView extends AbstractFloatingView {
 
-    private static final float HINT_PROG_SCRIM_THRESHOLD = 0.06f;
-    private static final float HINT_PROG_CONTENT_THRESHOLD = 0.08f;
-
     private Launcher mLauncher;
+    private AllAppsEduTouchController mTouchController;
 
     private AnimatorSet mAnimation;
 
@@ -124,7 +117,34 @@
     }
 
     @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        mTouchController.onControllerTouchEvent(ev);
+        if (mAnimation != null) {
+            updateAnimationOnTouchEvent(ev);
+        }
+        return super.onControllerTouchEvent(ev);
+    }
+
+    private void updateAnimationOnTouchEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mAnimation.pause();
+                return;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mAnimation.resume();
+                return;
+        }
+
+        if (mTouchController.isDraggingOrSettling()) {
+            mAnimation = null;
+            handleClose(false);
+        }
+    }
+
+    @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        mTouchController.onControllerInterceptTouchEvent(ev);
         return true;
     }
 
@@ -145,23 +165,9 @@
         int secondPart = 1200;
         int introDuration = firstPart + secondPart;
 
-        StateAnimationConfig config = new StateAnimationConfig();
-        config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
-                HINT_PROG_SCRIM_THRESHOLD, HINT_PROG_CONTENT_THRESHOLD));
-        config.setInterpolator(ANIM_SCRIM_FADE,
-                Interpolators.clampToProgress(ACCEL, 0, HINT_PROG_CONTENT_THRESHOLD));
-        config.duration = secondPart;
-        config.userControlled = false;
         AnimatorPlaybackController stateAnimationController =
-                mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
-        float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f;
-
-        AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-        PendingAnimation allAppsAlpha = new PendingAnimation(config.duration);
-        allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha);
-        mLauncher.getWorkspace().getStateTransitionAnimation().setScrim(allAppsAlpha, ALL_APPS,
-                config);
-        mAnimation.play(allAppsAlpha.buildAnim());
+                mTouchController.initAllAppsAnimation();
+        float maxAllAppsProgress = 0.75f;
 
         ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
         intro.setInterpolator(LINEAR);
@@ -198,6 +204,7 @@
                 mGradient.setAlpha(0);
             }
         });
+        mLauncher.getAppsView().setVisibility(View.VISIBLE);
         mAnimation.play(intro);
 
         ValueAnimator closeAllApps = ValueAnimator.ofFloat(maxAllAppsProgress, 0f);
@@ -223,6 +230,7 @@
 
     private void init(Launcher launcher) {
         mLauncher = launcher;
+        mTouchController = new AllAppsEduTouchController(mLauncher);
 
         int accentColor = Themes.getColorAccent(launcher);
         mGradient = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
@@ -250,9 +258,8 @@
      */
     public static void show(Launcher launcher) {
         final DragLayer dragLayer = launcher.getDragLayer();
-        ViewGroup parent = (ViewGroup) dragLayer.getParent();
-        AllAppsEduView view = launcher.getViewCache().getView(R.layout.all_apps_edu_view,
-                launcher, parent);
+        AllAppsEduView view = (AllAppsEduView) launcher.getLayoutInflater().inflate(
+                R.layout.all_apps_edu_view, dragLayer, false);
         view.init(launcher);
         launcher.getDragLayer().addView(view);
         launcher.getStatsLogManager().logger().log(LAUNCHER_ALL_APPS_EDU_SHOWN);
@@ -260,4 +267,27 @@
         view.requestLayout();
         view.playAnimation();
     }
+
+    private static class AllAppsEduTouchController extends PortraitStatesTouchController {
+
+        private AllAppsEduTouchController(Launcher l) {
+            super(l);
+        }
+
+        @Override
+        protected boolean canInterceptTouch(MotionEvent ev) {
+            return true;
+        }
+
+        private AnimatorPlaybackController initAllAppsAnimation() {
+            mFromState = NORMAL;
+            mToState = ALL_APPS;
+            mProgressMultiplier = initCurrentAnimation();
+            return mCurrentAnimation;
+        }
+
+        private boolean isDraggingOrSettling() {
+            return mDetector.isDraggingOrSettling();
+        }
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 88e8171..5a3e7dd 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.ResourceUtils.pxFromDp;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.Utilities.pxFromSp;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
 import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
 
 import android.annotation.SuppressLint;
@@ -394,7 +395,8 @@
     }
 
     private void updateHotseatIconSize(int hotseatIconSizePx) {
-        hotseatCellHeightPx = hotseatIconSizePx;
+        // Ensure there is enough space for folder icons, which have a slightly larger radius.
+        hotseatCellHeightPx = (int) Math.ceil(hotseatIconSizePx * ICON_OVERLAP_FACTOR);
         if (isVerticalBarLayout()) {
             hotseatBarSizePx = hotseatIconSizePx + hotseatBarSidePaddingStartPx
                     + hotseatBarSidePaddingEndPx;
@@ -473,7 +475,7 @@
         if (workspaceCellPaddingY < iconTextHeight) {
             iconTextSizePx = 0;
             iconDrawablePaddingPx = 0;
-            cellHeightPx = iconSizePx;
+            cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR);
             autoResizeAllAppsCells();
         }
     }
@@ -560,7 +562,8 @@
             desiredWorkspaceLeftRightMarginPx = (int) (desiredWorkspaceLeftRightOriginalPx * scale);
         } else {
             cellWidthPx = iconSizePx + iconDrawablePaddingPx;
-            cellHeightPx = iconSizePx + iconDrawablePaddingPx
+            cellHeightPx = (int) Math.ceil(iconSizePx * ICON_OVERLAP_FACTOR)
+                    + iconDrawablePaddingPx
                     + Utilities.calculateTextHeight(iconTextSizePx);
             int cellPaddingY = (getCellSize().y - cellHeightPx) / 2;
             if (iconDrawablePaddingPx > cellPaddingY && !isVerticalLayout
@@ -844,14 +847,16 @@
         return isVerticalBarLayout();
     }
 
-    public int getCellHeight(@ContainerType int containerType) {
+    public int getCellContentHeight(@ContainerType int containerType) {
         switch (containerType) {
             case CellLayout.WORKSPACE:
                 return cellHeightPx;
             case CellLayout.FOLDER:
                 return folderCellHeightPx;
             case CellLayout.HOTSEAT:
-                return hotseatCellHeightPx;
+                // The hotseat is the only container where the cell height is going to be
+                // different from the content within that cell.
+                return iconSizePx;
             default:
                 // ??
                 return 0;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 42b4e89..0a6f06c 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -207,8 +207,8 @@
                 ? dp.workspacePadding.bottom
                 : dp.hotseatBarSizePx - dp.hotseatCellHeightPx - mQsbHeight;
 
-        if (dp.isScalableGrid && dp.qsbBottomMarginPx <= freeSpace) {
-            return dp.qsbBottomMarginPx;
+        if (dp.isScalableGrid) {
+            return Math.min(dp.qsbBottomMarginPx, freeSpace);
         } else {
             return (int) (freeSpace * QSB_CENTER_FACTOR) + (dp.isTaskbarPresent
                     ? dp.taskbarSize
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 2a5187d..519b63d 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -122,7 +122,7 @@
 
     public int getCellContentHeight() {
         return Math.min(getMeasuredHeight(),
-                mActivity.getDeviceProfile().getCellHeight(mContainerType));
+                mActivity.getDeviceProfile().getCellContentHeight(mContainerType));
     }
 
     public void measureChild(View child) {
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index ea1fbdb..98c0cfc 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -21,11 +21,11 @@
 import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.util.Log;
@@ -129,10 +129,19 @@
                     canvas.restore();
                 });
 
+        Bitmap bgBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
+                (canvas) -> {
+                    Paint p = new Paint();
+                    p.setColor(bg.getBgColor());
+
+                    canvas.drawCircle(dragViewSize.x / 2f, dragViewSize.y / 2f, bg.getRadius(), p);
+                });
+
         ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBmp, 0, 0);
         ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, 0, 0);
+        ShiftedBitmapDrawable background = new ShiftedBitmapDrawable(bgBitmap, 0, 0);
 
-        return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
+        return new FolderAdaptiveIcon(background, foreground, badge, mask);
     }
 
     @Override
diff --git a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
index 54967a99..8cd91d3 100644
--- a/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
+++ b/src/com/android/launcher3/folder/ClippedFolderIconLayoutRule.java
@@ -7,7 +7,9 @@
 
     private static final float MIN_SCALE = 0.44f;
     private static final float MAX_SCALE = 0.51f;
-    private static final float MAX_RADIUS_DILATION = 0.1f;
+    private static final float MAX_RADIUS_DILATION = 0.25f;
+    // The max amount of overlap the preview items can go outside of the background bounds.
+    public static final float ICON_OVERLAP_FACTOR = 1 + (MAX_RADIUS_DILATION / 2f);
     private static final float ITEM_RADIUS_SCALE_FACTOR = 1.15f;
 
     public static final int EXIT_INDEX = -2;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index e704957..96030f9 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.folder;
 
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
 import static com.android.launcher3.folder.PreviewItemManager.INITIAL_ITEM_ANIMATION_DURATION;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_AUTO_LABELED;
@@ -236,6 +237,8 @@
     public void getPreviewBounds(Rect outBounds) {
         mPreviewItemManager.recomputePreviewDrawingParams();
         mBackground.getBounds(outBounds);
+        // The preview items go outside of the bounds of the background.
+        Utilities.scaleRectAboutCenter(outBounds, ICON_OVERLAP_FACTOR);
     }
 
     public float getBackgroundStrokeWidth() {
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 460521f..18d0b10 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.folder;
 
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
 import static com.android.launcher3.graphics.IconShape.getShape;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 
@@ -186,7 +187,7 @@
         outBounds.set(left, top, right, bottom);
     }
 
-    int getRadius() {
+    public int getRadius() {
         return previewSize / 2;
     }
 
@@ -348,7 +349,12 @@
 
     public Path getClipPath() {
         mPath.reset();
-        getShape().addToPath(mPath, getOffsetX(), getOffsetY(), getScaledRadius());
+        float radius = getScaledRadius() * ICON_OVERLAP_FACTOR;
+        // Find the difference in radius so that the clip path remains centered.
+        float radiusDifference = radius - getRadius();
+        float offsetX = basePreviewOffsetX - radiusDifference;
+        float offsetY = basePreviewOffsetY - radiusDifference;
+        getShape().addToPath(mPath, offsetX, offsetY, radius);
         return mPath;
     }
 
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index cf3da4b..a387f04 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.graphics;
 
+import static android.app.WallpaperManager.FLAG_SYSTEM;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 import static android.view.View.VISIBLE;
@@ -26,6 +27,8 @@
 
 import android.annotation.TargetApi;
 import android.app.Fragment;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
@@ -41,6 +44,7 @@
 import android.os.Looper;
 import android.os.Process;
 import android.util.AttributeSet;
+import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -84,6 +88,7 @@
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.LocalColorExtractor;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.util.ArrayList;
@@ -201,8 +206,12 @@
     private final InsettableFrameLayout mRootView;
     private final Hotseat mHotseat;
     private final CellLayout mWorkspace;
+    private final SparseIntArray mWallpaperColorResources;
 
-    public LauncherPreviewRenderer(Context context, InvariantDeviceProfile idp) {
+    public LauncherPreviewRenderer(Context context,
+            InvariantDeviceProfile idp,
+            WallpaperColors wallpaperColorsOverride) {
+
         super(context);
         mUiHandler = new Handler(Looper.getMainLooper());
         mContext = context;
@@ -254,6 +263,16 @@
                 mDp.workspacePadding.top,
                 mDp.workspacePadding.right + mDp.cellLayoutPaddingLeftRightPx,
                 mDp.workspacePadding.bottom);
+
+        if (Utilities.ATLEAST_S) {
+            WallpaperColors wallpaperColors = wallpaperColorsOverride != null
+                    ? wallpaperColorsOverride
+                    : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
+            mWallpaperColorResources = LocalColorExtractor.newInstance(context)
+                    .generateColorsOverride(wallpaperColors);
+        } else {
+            mWallpaperColorResources = null;
+        }
     }
 
     /** Populate preview and render it. */
@@ -357,6 +376,11 @@
         view.setAppWidget(-1, providerInfo);
         view.updateAppWidget(null);
         view.setTag(info);
+
+        if (mWallpaperColorResources != null) {
+            view.setColorResources(mWallpaperColorResources);
+        }
+
         addInScreenFromBind(view, info);
     }
 
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index a8c3d15..df49359 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -209,7 +209,7 @@
         if (mDestroyed) {
             return;
         }
-        View view = new LauncherPreviewRenderer(inflationContext, mIdp)
+        View view = new LauncherPreviewRenderer(inflationContext, mIdp, mWallpaperColors)
                 .getRenderedView(dataModel, widgetProviderInfoMap);
         // This aspect scales the view to fit in the surface and centers it
         final float scale = Math.min(mWidth / (float) view.getMeasuredWidth(),
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 90f37f3..5f8a4d4 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -65,12 +65,12 @@
     protected LauncherState mToState;
     protected AnimatorPlaybackController mCurrentAnimation;
     protected boolean mGoingBetweenStates = true;
+    // Ratio of transition process [0, 1] to drag displacement (px)
+    protected float mProgressMultiplier;
 
     private boolean mNoIntercept;
     private boolean mIsLogContainerSet;
     private float mStartProgress;
-    // Ratio of transition process [0, 1] to drag displacement (px)
-    private float mProgressMultiplier;
     private float mDisplacementShift;
     private boolean mCanBlockFling;
     private boolean mAllAppsOvershootStarted;
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index a88b8b7..1c2534d 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -278,12 +278,7 @@
                 mIgnoreDragGesture |= absDeltaY > mConfig.getScaledPagingTouchSlop();
 
                 if (!mIsDragging && !mIgnoreDragGesture && mRv.supportsFastScrolling()) {
-                    // condition #1: triggering thumb is distance, angle based
-                    if ((isNearThumb(mDownX, mLastY)
-                            && absDeltaY > mConfig.getScaledPagingTouchSlop()
-                            && absDeltaY > absDeltaX)
-                            // condition#2: Fastscroll function is now time based
-                            || (isNearScrollBar(mDownX) && ev.getEventTime() - mDownTimeStampMillis
+                    if ((isNearThumb(mDownX, mLastY) && ev.getEventTime() - mDownTimeStampMillis
                                     > FASTSCROLL_THRESHOLD_MILLIS)) {
                         calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY);
                     }
@@ -433,9 +428,6 @@
     }
 
     private void updatePopupY(int lastTouchY) {
-        if (!mPopupVisible) {
-            return;
-        }
         int height = mPopupView.getHeight();
         // Aligns the rounded corner of the pop up with the top of the thumb.
         float top = mRv.getScrollBarTop() + lastTouchY + (getScrollThumbRadius() / 2f)
diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java
index 8ae6b2e..23d9e15 100644
--- a/src/com/android/launcher3/widget/LocalColorExtractor.java
+++ b/src/com/android/launcher3/widget/LocalColorExtractor.java
@@ -76,6 +76,14 @@
     public void applyColorsOverride(Context base, WallpaperColors colors) { }
 
     /**
+     * Generates color resource overrides from {@link WallpaperColors}.
+     */
+    @Nullable
+    public SparseIntArray generateColorsOverride(WallpaperColors colors) {
+        return null;
+    }
+
+    /**
      * Takes a view and returns its rect that can be used by the wallpaper local color extractor.
      *
      * @param launcher Launcher class class.