Merge "Revert "Create new ShortcutInfo when dropping predicted deep shortcuts."" into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 256d95d..3945746 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,42 +20,61 @@
 # Prebuilt Java Libraries
 #
 include $(CLEAR_VARS)
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-    libSharedSystemUI:quickstep/libs/sysui_shared.jar
-include $(BUILD_MULTI_PREBUILT)
+LOCAL_MODULE := libSharedSystemUI
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_SRC_FILES := quickstep/libs/sysui_shared.jar
+LOCAL_UNINSTALLABLE_MODULE := true
+LOCAL_SDK_VERSION := current
+include $(BUILD_PREBUILT)
 
 #
-# Build rule for Launcher3 app.
+# Build rule for Launcher3 dependencies lib.
 #
 include $(CLEAR_VARS)
-
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
     android-support-v4 \
     android-support-v7-recyclerview \
     android-support-dynamic-animation
 
 LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-java-files-under, src_ui_overrides) \
-    $(call all-java-files-under, src_flags) \
     $(call all-proto-files-under, protos) \
     $(call all-proto-files-under, proto_overrides)
 
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/res \
-    prebuilts/sdk/current/support/v7/recyclerview/res \
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
 LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
 
-LOCAL_AAPT_FLAGS := \
-    --auto-add-overlay \
-    --extra-packages android.support.v7.recyclerview \
+LOCAL_SDK_VERSION := current
+LOCAL_MIN_SDK_VERSION := 21
+LOCAL_MODULE := Launcher3CommonDepsLib
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := AndroidManifest-common.xml
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#
+# Build rule for Launcher3 app.
+#
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-java-files-under, src_ui_overrides) \
+    $(call all-java-files-under, src_flags)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 21
@@ -73,91 +92,78 @@
 # Build rule for Launcher3 Go app for Android Go devices.
 #
 include $(CLEAR_VARS)
-
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-v4 \
-    android-support-v7-recyclerview \
-    android-support-dynamic-animation
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
 
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src) \
     $(call all-java-files-under, src_ui_overrides) \
-    $(call all-java-files-under, go/src_flags) \
-    $(call all-proto-files-under, protos) \
-    $(call all-proto-files-under, proto_overrides)
+    $(call all-java-files-under, go/src_flags)
 
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/go/res \
-    $(LOCAL_PATH)/res \
-    prebuilts/sdk/current/support/v7/recyclerview/res \
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/go/res
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
-
-LOCAL_AAPT_FLAGS := \
-    --auto-add-overlay \
-    --extra-packages android.support.v7.recyclerview \
-
 LOCAL_SDK_VERSION := current
 LOCAL_MIN_SDK_VERSION := 21
 LOCAL_PACKAGE_NAME := Launcher3Go
 LOCAL_PRIVILEGED_MODULE := true
-LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3QuickStep
 
 LOCAL_FULL_LIBS_MANIFEST_FILES := \
     $(LOCAL_PATH)/AndroidManifest.xml \
     $(LOCAL_PATH)/AndroidManifest-common.xml
 
+LOCAL_MANIFEST_FILE := go/AndroidManifest.xml
 LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
-
 include $(BUILD_PACKAGE)
 
 #
+# Build rule for Quickstep library.
+#
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT2_ONLY := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-java-files-under, quickstep/src) \
+    $(call all-java-files-under, src_flags)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SDK_VERSION := system_current
+LOCAL_MIN_SDK_VERSION := 26
+LOCAL_MODULE := Launcher3QuickStepLib
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#
 # Build rule for Quickstep app.
 #
 include $(CLEAR_VARS)
-
+LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-v4 \
-    android-support-v7-recyclerview \
-    android-support-dynamic-animation \
-    libSharedSystemUI
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-java-files-under, quickstep/src) \
-    $(call all-java-files-under, src_flags) \
-    $(call all-proto-files-under, protos) \
-    $(call all-proto-files-under, proto_overrides)
-
-LOCAL_RESOURCE_DIR := \
-    $(LOCAL_PATH)/quickstep/res \
-    $(LOCAL_PATH)/res \
-    prebuilts/sdk/current/support/v7/recyclerview/res \
-
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3QuickStepLib
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ --proto_path=$(LOCAL_PATH)/proto_overrides/
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java
-
-LOCAL_AAPT_FLAGS := \
-    --auto-add-overlay \
-    --extra-packages android.support.v7.recyclerview \
-
 LOCAL_SDK_VERSION := system_current
 LOCAL_MIN_SDK_VERSION := 26
 LOCAL_PACKAGE_NAME := Launcher3QuickStep
 LOCAL_PRIVILEGED_MODULE := true
 LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
 
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
+
 LOCAL_FULL_LIBS_MANIFEST_FILES := \
     $(LOCAL_PATH)/AndroidManifest.xml \
     $(LOCAL_PATH)/AndroidManifest-common.xml
@@ -168,6 +174,41 @@
 include $(BUILD_PACKAGE)
 
 
+#
+# Build rule for Launcher3 Go app with quickstep for Android Go devices.
+#
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_STATIC_JAVA_LIBRARIES := libSharedSystemUI
+LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src) \
+    $(call all-java-files-under, quickstep/src) \
+    $(call all-java-files-under, go/src_flags)
+
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/quickstep/res \
+    $(LOCAL_PATH)/go/res
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SDK_VERSION := system_current
+LOCAL_MIN_SDK_VERSION := 26
+LOCAL_PACKAGE_NAME := Launcher3QuickStepGo
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3 Launcher3QuickStep
+
+LOCAL_FULL_LIBS_MANIFEST_FILES := \
+    $(LOCAL_PATH)/go/AndroidManifest.xml \
+    $(LOCAL_PATH)/AndroidManifest.xml \
+    $(LOCAL_PATH)/AndroidManifest-common.xml
+
+LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
+include $(BUILD_PACKAGE)
 
 
 # ==================================================
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index bb03f50..8f4d5be 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -20,7 +20,6 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3">
-    <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
 
     <!--
     The manifest defines the common entries that should be present in any derivative of Launcher3.
@@ -45,6 +44,28 @@
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
     <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
 
+
+    <!--
+    Permissions required for read/write access to the workspace data. These permission name
+    should not conflict with that defined in other apps, as such an app should embed its package
+    name in the permissions. eq com.mypackage.permission.READ_SETTINGS
+    -->
+    <permission
+        android:name="${packageName}.permission.READ_SETTINGS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signatureOrSystem"
+        android:label="@string/permlab_read_settings"
+        android:description="@string/permdesc_read_settings"/>
+    <permission
+        android:name="${packageName}.permission.WRITE_SETTINGS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signatureOrSystem"
+        android:label="@string/permlab_write_settings"
+        android:description="@string/permdesc_write_settings"/>
+
+    <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
+    <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
         android:fullBackupOnly="true"
@@ -82,14 +103,16 @@
         </receiver>
 
         <service
-            android:name="com.android.launcher3.compat.WallpaperManagerCompatVL$ColorExtractionService"
+            android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
             android:exported="false"
             android:process=":wallpaper_chooser"
             android:permission="android.permission.BIND_JOB_SERVICE" />
 
-        <service android:name="com.android.launcher3.notification.NotificationListener"
-                 android:enabled="@bool/notification_badging_enabled"
-                 android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
+        <service
+            android:name="com.android.launcher3.notification.NotificationListener"
+            android:label="@string/icon_badging_service_title"
+            android:enabled="@bool/notification_badging_enabled"
+            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
             <intent-filter>
                 <action android:name="android.service.notification.NotificationListenerService" />
             </intent-filter>
@@ -117,5 +140,31 @@
             android:name="com.android.launcher3.launcher_dump_provider"
             android:value="com.android.launcher3.LauncherProvider" />
 
+        <!--
+        The settings provider contains Home's data, like the workspace favorites. The permissions
+        should be changed to what is defined above. The authorities should also be changed to
+        represent the package name.
+        -->
+        <provider
+            android:name="com.android.launcher3.LauncherProvider"
+            android:authorities="${packageName}.settings"
+            android:exported="true"
+            android:writePermission="${packageName}.permission.WRITE_SETTINGS"
+            android:readPermission="${packageName}.permission.READ_SETTINGS" />
+
+        <!--
+        The settings activity. To extend point settings_fragment_name to appropriate fragment class
+        -->
+        <activity
+            android:name="com.android.launcher3.SettingsActivity"
+            android:label="@string/settings_button_text"
+            android:theme="@android:style/Theme.DeviceDefault.Settings"
+            android:autoRemoveFromRecents="true">
+            <intent-filter>
+                <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
     </application>
 </manifest>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6ef7828..4ac51ab 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,29 +26,6 @@
     Refer comments around specific entries on how to extend individual components.
     -->
 
-    <!--
-    Permissions required for read/write access to the workspace data. These permission name
-    should not conflict with that defined in other apps, as such an app should embed its package
-    name in the permissions. eq com.mypackage.permission.READ_SETTINGS
-    -->
-    <permission
-        android:name="com.android.launcher3.permission.READ_SETTINGS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="normal"
-        android:label="@string/permlab_read_settings"
-        android:description="@string/permdesc_read_settings"/>
-    <permission
-        android:name="com.android.launcher3.permission.WRITE_SETTINGS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signatureOrSystem"
-        android:label="@string/permlab_write_settings"
-        android:description="@string/permdesc_write_settings"/>
-
-    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
-    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
-    <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
-    <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
-
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
         android:fullBackupOnly="true"
@@ -56,7 +33,7 @@
         android:hardwareAccelerated="true"
         android:icon="@drawable/ic_launcher_home"
         android:label="@string/derived_app_name"
-        android:theme="@style/LauncherTheme"
+        android:theme="@style/AppTheme"
         android:largeHeap="@bool/config_largeHeap"
         android:restoreAnyVersion="true"
         android:supportsRtl="true" >
@@ -71,8 +48,8 @@
             android:clearTaskOnLaunch="true"
             android:stateNotNeeded="true"
             android:windowSoftInputMode="adjustPan"
-            android:screenOrientation="nosensor"
-            android:configChanges="keyboard|keyboardHidden|navigation"
+            android:screenOrientation="unspecified"
+            android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
             android:resizeableActivity="true"
             android:resumeWhilePausing="true"
             android:taskAffinity=""
@@ -86,31 +63,5 @@
             </intent-filter>
         </activity>
 
-        <!--
-        The settings activity. When extending keep the intent filter present
-        -->
-        <activity
-            android:name="com.android.launcher3.SettingsActivity"
-            android:label="@string/settings_button_text"
-            android:theme="@android:style/Theme.DeviceDefault.Settings"
-            android:autoRemoveFromRecents="true">
-            <intent-filter>
-                <action android:name="android.intent.action.APPLICATION_PREFERENCES" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
-        <!--
-        The settings provider contains Home's data, like the workspace favorites. The permissions
-        should be changed to what is defined above. The authorities should also be changed to
-        represent the package name.
-        -->
-        <provider
-            android:name="com.android.launcher3.LauncherProvider"
-            android:authorities="com.android.launcher3.settings"
-            android:exported="true"
-            android:writePermission="com.android.launcher3.permission.WRITE_SETTINGS"
-            android:readPermission="com.android.launcher3.permission.READ_SETTINGS" />
-
     </application>
 </manifest>
diff --git a/build.gradle b/build.gradle
index 0030b8b..4ae6600 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,16 @@
 buildscript {
     repositories {
         mavenCentral()
-        jcenter()
+        google()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
-        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
+        classpath 'com.android.tools.build:gradle:3.2.0-alpha12'
+        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.3'
     }
 }
 
+final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
+
 apply plugin: 'com.android.application'
 apply plugin: 'com.google.protobuf'
 
@@ -23,6 +25,7 @@
         versionName "1.0"
 
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        vectorDrawables.useSupportLibrary = true
     }
     buildTypes {
         debug {
@@ -30,18 +33,28 @@
         }
     }
 
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    flavorDimensions "default"
+
     productFlavors {
         aosp {
+            dimension "default"
             applicationId 'com.android.launcher3'
             testApplicationId 'com.android.launcher3.tests'
         }
 
         l3go {
+            dimension "default"
             applicationId 'com.android.launcher3'
             testApplicationId 'com.android.launcher3.tests'
         }
 
         quickstep {
+            dimension "default"
             applicationId 'com.android.launcher3'
             testApplicationId 'com.android.launcher3.tests'
         }
@@ -98,27 +111,28 @@
 }
 
 repositories {
+    maven { url "../../../prebuilts/fullsdk-darwin/extras/android/m2repository" }
+    maven { url "../../../prebuilts/fullsdk-linux/extras/android/m2repository" }
     mavenCentral()
-    jcenter()
+    google()
 }
 
-final String SUPPORT_LIBS_VERSION = '28.0.0-SNAPSHOT'
 dependencies {
-    compile "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
-    compile "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
-    compile "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
-    compile 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
+    implementation "com.android.support:support-v4:${SUPPORT_LIBS_VERSION}"
+    implementation "com.android.support:support-dynamic-animation:${SUPPORT_LIBS_VERSION}"
+    implementation "com.android.support:recyclerview-v7:${SUPPORT_LIBS_VERSION}"
+    implementation 'com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7'
 
-    quickstepCompile fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
+    quickstepImplementation fileTree(dir: "quickstep/libs", include: 'sysui_shared.jar')
 
-    testCompile 'junit:junit:4.12'
-    androidTestCompile "org.mockito:mockito-core:1.9.5"
-    androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
-    androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
-    androidTestCompile 'com.android.support.test:runner:1.0.0'
-    androidTestCompile 'com.android.support.test:rules:1.0.0'
-    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
-    androidTestCompile "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation "org.mockito:mockito-core:1.9.5"
+    androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
+    androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
+    androidTestImplementation 'com.android.support.test:runner:1.0.0'
+    androidTestImplementation 'com.android.support.test:rules:1.0.0'
+    androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
+    androidTestImplementation "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
 }
 
 protobuf {
diff --git a/go/AndroidManifest.xml b/go/AndroidManifest.xml
new file mode 100644
index 0000000..0a9ad7b
--- /dev/null
+++ b/go/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.launcher3" >
+
+    <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+
+    <application
+        android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+        android:fullBackupOnly="true"
+        android:fullBackupContent="@xml/backupscheme"
+        android:hardwareAccelerated="true"
+        android:icon="@drawable/ic_launcher_home"
+        android:label="@string/derived_app_name"
+        android:theme="@style/AppTheme"
+        android:largeHeap="@bool/config_largeHeap"
+        android:restoreAnyVersion="true"
+        android:supportsRtl="true" >
+
+        <!-- Activity for handling PinItemRequest. Only supports shortcuts -->
+        <activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
+            android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+            android:excludeFromRecents="true"
+            android:autoRemoveFromRecents="true"
+            android:label="@string/action_add_to_workspace"
+            tools:node="replace" >
+            <intent-filter>
+                <action android:name="android.content.pm.action.CONFIRM_PIN_SHORTCUT" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/go/res/drawable/ic_widget.xml b/go/res/drawable/ic_widget.xml
new file mode 100644
index 0000000..5336876
--- /dev/null
+++ b/go/res/drawable/ic_widget.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48dp"
+        android:height="48dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M3.9,18.35c2.5-2.49,5.78-3.64,10.14-3.64v3.05c0,0.47,0.57,0.71,0.9,0.37l5.74-5.74c0.41-0.41,0.41-1.08,0-1.49l-5.74-5.74
+        c-0.33-0.33-0.9-0.1-0.9,0.37v2.95c-6.32,0.9-9.56,4.9-11.02,9.34C2.86,18.34,3.51,18.74,3.9,18.35z"/>
+</vector>
diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml
new file mode 100644
index 0000000..49506d9
--- /dev/null
+++ b/go/res/layout/widget_cell_content.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/widget_preview_label_vertical_padding"
+        android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
+        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+        android:orientation="horizontal">
+
+        <!-- The name of the widget. -->
+        <TextView
+            android:id="@+id/widget_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="center"
+            android:singleLine="true"
+            android:maxLines="1"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp" />
+
+        <!-- The original dimensions of the widget (can't be the same text as above due to different
+             style. -->
+        <TextView
+            android:id="@+id/widget_dims"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="5dp"
+            android:layout_marginLeft="5dp"
+            android:visibility="gone"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif-condensed"
+            android:alpha="0.8" />
+    </LinearLayout>
+
+    <!-- The image of the widget. This view does not support padding. Any placement adjustment
+         should be done using margins. -->
+    <com.android.launcher3.widget.WidgetImageView
+        android:id="@+id/widget_preview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</merge>
\ No newline at end of file
diff --git a/go/res/values-af/strings.xml b/go/res/values-af/strings.xml
new file mode 100644
index 0000000..10ac473
--- /dev/null
+++ b/go/res/values-af/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Raak en hou om \'n kortpad op te tel."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Kortpaaie"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-kortpaaie"</string>
+</resources>
diff --git a/go/res/values-am/strings.xml b/go/res/values-am/strings.xml
new file mode 100644
index 0000000..b3b253f
--- /dev/null
+++ b/go/res/values-am/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"አቋራጮች"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> አቋራጮች"</string>
+</resources>
diff --git a/go/res/values-ar/strings.xml b/go/res/values-ar/strings.xml
new file mode 100644
index 0000000..9888d0f
--- /dev/null
+++ b/go/res/values-ar/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"المس مع الاستمرار لاختيار اختصار."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"يمكنك النقر مرّتين مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"الاختصارات"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"اختصارات <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-as/strings.xml b/go/res/values-as/strings.xml
new file mode 100644
index 0000000..6b5807f
--- /dev/null
+++ b/go/res/values-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ স্পৰ্শ কৰি ৰাখক।"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ দুবাৰ টিপি ৰাখক বা নিজৰ উপযোগিতা অনুসৰি বনোৱা কাৰ্যসমূহ ব্যৱহাৰ কৰক।"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"শ্বৰ্টকাটসমূহ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> শ্বৰ্টকাটসমূহ"</string>
+</resources>
diff --git a/go/res/values-az/strings.xml b/go/res/values-az/strings.xml
new file mode 100644
index 0000000..c4b8cb7
--- /dev/null
+++ b/go/res/values-az/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Qısayolu seçmək üçün toxunub saxlayın."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Qısayollar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> qısayolları"</string>
+</resources>
diff --git a/go/res/values-b+sr+Latn/strings.xml b/go/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..0da5699
--- /dev/null
+++ b/go/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite da biste izabrali prečicu."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-be/strings.xml b/go/res/values-be/strings.xml
new file mode 100644
index 0000000..4189e35
--- /dev/null
+++ b/go/res/values-be/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Ярлыкі"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлыкі <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-bg/strings.xml b/go/res/values-bg/strings.xml
new file mode 100644
index 0000000..1b85992
--- /dev/null
+++ b/go/res/values-bg/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Докоснете и задръжте за избор на пряк път."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Преки пътища"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Преки пътища за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-bn/strings.xml b/go/res/values-bn/strings.xml
new file mode 100644
index 0000000..c56c925
--- /dev/null
+++ b/go/res/values-bn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে রাখুন।"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"কোনও শর্টকাট বেছে নিতে ডাবল ট্যাপ করে ধরে রাখুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন।"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"শর্টকাট"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> এর শর্টকাট"</string>
+</resources>
diff --git a/go/res/values-bs/strings.xml b/go/res/values-bs/strings.xml
new file mode 100644
index 0000000..3141b9d
--- /dev/null
+++ b/go/res/values-bs/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i držite da uzmete prečicu."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečice aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ca/strings.xml b/go/res/values-ca/strings.xml
new file mode 100644
index 0000000..3b5c3f7
--- /dev/null
+++ b/go/res/values-ca/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén premuda una drecera per seleccionar-la."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Dreceres"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Dreceres de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-cs/strings.xml b/go/res/values-cs/strings.xml
new file mode 100644
index 0000000..e4018f2
--- /dev/null
+++ b/go/res/values-cs/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Zkratku vyberete podržením."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Zkratky"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Zkratky aplikace <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-da/strings.xml b/go/res/values-da/strings.xml
new file mode 100644
index 0000000..821d36a
--- /dev/null
+++ b/go/res/values-da/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Hold en genvej nede for at samle den op."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryk to gange, og hold en genvej nede for at samle den op og bruge tilpassede handlinger."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Genveje"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-genveje"</string>
+</resources>
diff --git a/go/res/values-de/strings.xml b/go/res/values-de/strings.xml
new file mode 100644
index 0000000..43a1b3a
--- /dev/null
+++ b/go/res/values-de/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Doppeltippen und halten, um eine Verknüpfung auszuwählen."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Verknüpfungen"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-Verknüpfungen"</string>
+</resources>
diff --git a/go/res/values-el/strings.xml b/go/res/values-el/strings.xml
new file mode 100644
index 0000000..ae59907
--- /dev/null
+++ b/go/res/values-el/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Αγγίξτε παρατεταμένα για να σηκώσετε μια συντόμευση."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Πατήσετε δύο φορές παρατεταμένα για να σηκώσετε μια συντόμευση ή για να χρησιμοποιήσετε προσαρμοσμένες ενέργειες."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Συντομεύσεις"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Συντομεύσεις <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rAU/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rGB/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..2ee2c26
--- /dev/null
+++ b/go/res/values-en-rIN/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shortcuts"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shortcuts"</string>
+</resources>
diff --git a/go/res/values-es-rUS/strings.xml b/go/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..5212c03
--- /dev/null
+++ b/go/res/values-es-rUS/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén presionado para elegir un acceso directo."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Accesos directos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Accesos directos de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-es/strings.xml b/go/res/values-es/strings.xml
new file mode 100644
index 0000000..3ae4588
--- /dev/null
+++ b/go/res/values-es/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén pulsado el acceso directo que quieras."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Accesos directos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Accesos directos de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-et/strings.xml b/go/res/values-et/strings.xml
new file mode 100644
index 0000000..2513e65
--- /dev/null
+++ b/go/res/values-et/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Otsetee valimiseks puudutage seda pikalt."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Otseteed"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> otseteed"</string>
+</resources>
diff --git a/go/res/values-eu/strings.xml b/go/res/values-eu/strings.xml
new file mode 100644
index 0000000..9949ef0
--- /dev/null
+++ b/go/res/values-eu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Eduki sakatuta lasterbide bat aukeratzeko."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Lasterbideak"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioaren lasterbidea"</string>
+</resources>
diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml
new file mode 100644
index 0000000..f1584d9
--- /dev/null
+++ b/go/res/values-fa/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"برای انتخاب یک میان‌بر، لمس کنید و نگه‌دارید."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"برای انتخاب میان‌بر، دو ضربه سریع بزنید و نگه دارید یا از کنش‌های سفارشی استفاده کنید."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"میان‌برها"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"میان‌برهای <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-fi/strings.xml b/go/res/values-fi/strings.xml
new file mode 100644
index 0000000..da9b0e1
--- /dev/null
+++ b/go/res/values-fi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Valitse pikakuvake painamalla sitä pitkään."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Pikakuvakkeet"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Kohteen <xliff:g id="NAME">%1$s</xliff:g> pikakuvakkeet"</string>
+</resources>
diff --git a/go/res/values-fr-rCA/strings.xml b/go/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..c7fd6d6
--- /dev/null
+++ b/go/res/values-fr-rCA/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Maintenez un doigt sur le raccourci pour l\'ajouter"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Raccourcis"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Raccourcis : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-fr/strings.xml b/go/res/values-fr/strings.xml
new file mode 100644
index 0000000..238fe73
--- /dev/null
+++ b/go/res/values-fr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Appui prolongé pour sélectionner raccourci."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Appuyez 2 fois et maintenez pression pour sélectionner raccourci ou utilisez actions personnalisées."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Raccourcis"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Raccourcis <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-gl/strings.xml b/go/res/values-gl/strings.xml
new file mode 100644
index 0000000..31621d5
--- /dev/null
+++ b/go/res/values-gl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Mantén premido un atallo para seleccionalo."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Atallos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atallos da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-gu/strings.xml b/go/res/values-gu/strings.xml
new file mode 100644
index 0000000..bdb549f
--- /dev/null
+++ b/go/res/values-gu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"એક શૉર્ટકટ ચૂંટવા ટૅપ કરી રાખો."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરી રાખો."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"શૉર્ટકટ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> શૉર્ટકટ"</string>
+</resources>
diff --git a/go/res/values-hi/strings.xml b/go/res/values-hi/strings.xml
new file mode 100644
index 0000000..2c1650a
--- /dev/null
+++ b/go/res/values-hi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"शॉर्टकट चुनने के लिए छूकर रखें."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"शॉर्टकट चुनने के लिए दो बार छूएं और कुछ देर दबाएं रखें या अपने मुताबिक कार्रवाइयों का इस्तेमाल करें."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"शॉर्टकट"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> शॉर्टकट"</string>
+</resources>
diff --git a/go/res/values-hr/strings.xml b/go/res/values-hr/strings.xml
new file mode 100644
index 0000000..fccdeb5
--- /dev/null
+++ b/go/res/values-hr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dodirnite i zadržite kako biste podigli prečac."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Prečaci"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Prečaci za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-hu/strings.xml b/go/res/values-hu/strings.xml
new file mode 100644
index 0000000..369c227
--- /dev/null
+++ b/go/res/values-hu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Felvételhez tartsa nyomva a parancsikont."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Parancsikonok"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-parancsikonok"</string>
+</resources>
diff --git a/go/res/values-hy/strings.xml b/go/res/values-hy/strings.xml
new file mode 100644
index 0000000..4747f6d
--- /dev/null
+++ b/go/res/values-hy/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Դյուրանցումներ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> դյուրանցումներ"</string>
+</resources>
diff --git a/go/res/values-in/strings.xml b/go/res/values-in/strings.xml
new file mode 100644
index 0000000..c8b9da3
--- /dev/null
+++ b/go/res/values-in/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tap lama untuk memilih pintasan."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tap dua kali &amp; tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-is/strings.xml b/go/res/values-is/strings.xml
new file mode 100644
index 0000000..b8bb923
--- /dev/null
+++ b/go/res/values-is/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Haltu fingri á flýtileið til að grípa hana."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Flýtileiðir"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> flýtileiðir"</string>
+</resources>
diff --git a/go/res/values-it/strings.xml b/go/res/values-it/strings.xml
new file mode 100644
index 0000000..bc5d998
--- /dev/null
+++ b/go/res/values-it/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tocca e tieni premuto per scegliere la scorciatoia"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Scorciatoie"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Scorciatoie di <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-iw/strings.xml b/go/res/values-iw/strings.xml
new file mode 100644
index 0000000..f541d4d
--- /dev/null
+++ b/go/res/values-iw/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"כדי להוסיף קיצור דרך, מקישים עליו פעמיים ומחזיקים."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, מקישים על קיצור הדרך פעמיים ומחזיקים."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"קיצורי דרך"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"קיצורי דרך לאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ja/strings.xml b/go/res/values-ja/strings.xml
new file mode 100644
index 0000000..8f02d7f
--- /dev/null
+++ b/go/res/values-ja/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ショートカットを追加するには押し続けます。"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ショートカット"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"「<xliff:g id="NAME">%1$s</xliff:g>」のショートカット"</string>
+</resources>
diff --git a/go/res/values-ka/strings.xml b/go/res/values-ka/strings.xml
new file mode 100644
index 0000000..1b46534
--- /dev/null
+++ b/go/res/values-ka/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"მალსახმობები"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-ის მალსახმობები"</string>
+</resources>
diff --git a/go/res/values-kk/strings.xml b/go/res/values-kk/strings.xml
new file mode 100644
index 0000000..e909818
--- /dev/null
+++ b/go/res/values-kk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Таңбашаны таңдау үшін оны түртіп, ұстап тұрыңыз."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Таңбашаны таңдау немесе арнаулы әрекеттерді пайдалану үшін екі рет түртіп, ұстап тұрыңыз."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Таңбашалар"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> таңбаша"</string>
+</resources>
diff --git a/go/res/values-km/strings.xml b/go/res/values-km/strings.xml
new file mode 100644
index 0000000..40082a4
--- /dev/null
+++ b/go/res/values-km/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ប៉ះ ហើយចុចឲ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ។"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ប៉ះពីរដង ហើយចុចឱ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ផ្លូវកាត់"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ផ្លូវកាត់សម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-kn/strings.xml b/go/res/values-kn/strings.xml
new file mode 100644
index 0000000..9c121fd
--- /dev/null
+++ b/go/res/values-kn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
+</resources>
diff --git a/go/res/values-ko/strings.xml b/go/res/values-ko/strings.xml
new file mode 100644
index 0000000..60f925e
--- /dev/null
+++ b/go/res/values-ko/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"바로가기를 선택하려면 길게 터치하세요."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"바로가기"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> 바로가기"</string>
+</resources>
diff --git a/go/res/values-ky/strings.xml b/go/res/values-ky/strings.xml
new file mode 100644
index 0000000..4c7e973
--- /dev/null
+++ b/go/res/values-ky/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Кыска жолду тандоо үчүн басып туруңуз."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Кыска жолдор"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> кыска жол"</string>
+</resources>
diff --git a/go/res/values-lo/strings.xml b/go/res/values-lo/strings.xml
new file mode 100644
index 0000000..7864884
--- /dev/null
+++ b/go/res/values-lo/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ປຸ່ມລັດ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ປຸ່ມລັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-lt/strings.xml b/go/res/values-lt/strings.xml
new file mode 100644
index 0000000..8f49032
--- /dev/null
+++ b/go/res/values-lt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Dukart pal. ir palaik., kad pasir. spart. klav."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Spartieji klavišai"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"„<xliff:g id="NAME">%1$s</xliff:g>“ spartieji klavišai"</string>
+</resources>
diff --git a/go/res/values-lv/strings.xml b/go/res/values-lv/strings.xml
new file mode 100644
index 0000000..04315eb
--- /dev/null
+++ b/go/res/values-lv/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Lai izvēlētos saīsni, pieskarieties un turiet to."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to vai arī veiciet pielāgotas darbības."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Saīsnes"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> saīsnes"</string>
+</resources>
diff --git a/go/res/values-mk/strings.xml b/go/res/values-mk/strings.xml
new file mode 100644
index 0000000..52d66b5
--- /dev/null
+++ b/go/res/values-mk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Допрете двапати и задржете за да изберете кратенка."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Допрете двапати и задржете за да изберете кратенка или да користите приспособени дејства."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Кратенки"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Кратенки за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ml/strings.xml b/go/res/values-ml/strings.xml
new file mode 100644
index 0000000..b3c12e1
--- /dev/null
+++ b/go/res/values-ml/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ഒരു കുറുക്കുവഴി ചേർക്കുന്നതിന് അത് സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"കുറുക്കുവഴികൾ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> കുറുക്കുവഴികൾ"</string>
+</resources>
diff --git a/go/res/values-mn/strings.xml b/go/res/values-mn/strings.xml
new file mode 100644
index 0000000..c89dfd1
--- /dev/null
+++ b/go/res/values-mn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Товчлол авах бол удаан дарна уу."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Товчлол авах болон тохируулсан үйлдлийг ашиглахын тулд хоёр товшоод хүлээнэ үү."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Товчлол"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-н товчлол"</string>
+</resources>
diff --git a/go/res/values-mr/strings.xml b/go/res/values-mr/strings.xml
new file mode 100644
index 0000000..2c767b4
--- /dev/null
+++ b/go/res/values-mr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"शॉर्टकट"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> शॉर्टकट"</string>
+</resources>
diff --git a/go/res/values-ms/strings.xml b/go/res/values-ms/strings.xml
new file mode 100644
index 0000000..42add9a
--- /dev/null
+++ b/go/res/values-ms/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Sentuh &amp; tahan untuk mengambil pintasan."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ketik dua kali &amp; tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Pintasan"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Pintasan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-my/strings.xml b/go/res/values-my/strings.xml
new file mode 100644
index 0000000..5784df6
--- /dev/null
+++ b/go/res/values-my/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"လက်ကွက်ဖြတ်လမ်းတစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"လက်ကွက်ဖြတ်လမ်းကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန်နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ဖြတ်လမ်းလင့်ခ်များ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ဖြတ်လမ်းလင့်ခ်များ"</string>
+</resources>
diff --git a/go/res/values-nb/strings.xml b/go/res/values-nb/strings.xml
new file mode 100644
index 0000000..2a5ffb6
--- /dev/null
+++ b/go/res/values-nb/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Trykk og hold for å velge en snarvei."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Snarveier"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-snarveier"</string>
+</resources>
diff --git a/go/res/values-ne/strings.xml b/go/res/values-ne/strings.xml
new file mode 100644
index 0000000..0be0375
--- /dev/null
+++ b/go/res/values-ne/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"कुनै सटकर्ट छनौट गर्न छोइराख्नुहोस्।"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"कुनै सर्टकट छनौट गर्न दुईपटक ट्याप गरेर होल्ड गर्नुहोस् वा रोजेका कारबाहीहरू प्रयोग गर्नुहोस्।"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"सर्टकटहरू"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> सर्टकटहरू"</string>
+</resources>
diff --git a/go/res/values-nl/strings.xml b/go/res/values-nl/strings.xml
new file mode 100644
index 0000000..5bcd016
--- /dev/null
+++ b/go/res/values-nl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tik en houd vast om snelkoppeling toe te voegen."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Snelkoppelingen"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>-snelkoppelingen"</string>
+</resources>
diff --git a/go/res/values-or/strings.xml b/go/res/values-or/strings.xml
new file mode 100644
index 0000000..3ec8a72
--- /dev/null
+++ b/go/res/values-or/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଦାବି ଧରନ୍ତୁ।"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ଡବଲ୍‌-ଟାପ୍‌ କରନ୍ତୁ ଏବଂ ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଧରି ରଖନ୍ତୁ କିମ୍ୱା କଷ୍ଟମ୍ ପ୍ରକ୍ରିୟା ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ଶର୍ଟକଟ୍‍"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>ର ଶର୍ଟକଟ୍"</string>
+</resources>
diff --git a/go/res/values-pa/strings.xml b/go/res/values-pa/strings.xml
new file mode 100644
index 0000000..c7e4abf
--- /dev/null
+++ b/go/res/values-pa/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ਸ਼ਾਰਟਕੱਟ"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ"</string>
+</resources>
diff --git a/go/res/values-pl/strings.xml b/go/res/values-pl/strings.xml
new file mode 100644
index 0000000..0861daa
--- /dev/null
+++ b/go/res/values-pl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Naciśnij i przytrzymaj, by wybrać skrót."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Skróty"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> – skróty"</string>
+</resources>
diff --git a/go/res/values-pt-rPT/strings.xml b/go/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..7a75a05
--- /dev/null
+++ b/go/res/values-pt-rPT/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque sem soltar para escolher um atalho."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos da aplicação <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-pt/strings.xml b/go/res/values-pt/strings.xml
new file mode 100644
index 0000000..53bbfc4
--- /dev/null
+++ b/go/res/values-pt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Toque e segure para selecionar um atalho."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Atalhos"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Atalhos do app <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ro/strings.xml b/go/res/values-ro/strings.xml
new file mode 100644
index 0000000..75d1796
--- /dev/null
+++ b/go/res/values-ro/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Atingeți și țineți apăsat pentru a selecta o comandă rapidă."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Atingeți de două ori și țineți apăsat pentru comandă rapidă sau folosiți acțiuni personalizate."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Comenzi rapide"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Comenzi rapide pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ru/strings.xml b/go/res/values-ru/strings.xml
new file mode 100644
index 0000000..9c5c8cd
--- /dev/null
+++ b/go/res/values-ru/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Чтобы выбрать ярлык, нажмите на него и удерживайте."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Чтобы выбрать ярлык или использовать специальные действия, нажмите на него дважды и не отпускайте."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Ярлыки"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>: ярлыки"</string>
+</resources>
diff --git a/go/res/values-si/strings.xml b/go/res/values-si/strings.xml
new file mode 100644
index 0000000..4b25c90
--- /dev/null
+++ b/go/res/values-si/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"කෙටි මං"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"කෙටි මං <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sk/strings.xml b/go/res/values-sk/strings.xml
new file mode 100644
index 0000000..fc02933
--- /dev/null
+++ b/go/res/values-sk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Skratku pridáte pridržaním."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Skratky"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Skratky aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sl/strings.xml b/go/res/values-sl/strings.xml
new file mode 100644
index 0000000..6ecedfb
--- /dev/null
+++ b/go/res/values-sl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Pridržite bližnjico, da jo izberete."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Bližnjice"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Bližnjice za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sq/strings.xml b/go/res/values-sq/strings.xml
new file mode 100644
index 0000000..bb74db6
--- /dev/null
+++ b/go/res/values-sq/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Shkurtoret"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> shkurtore"</string>
+</resources>
diff --git a/go/res/values-sr/strings.xml b/go/res/values-sr/strings.xml
new file mode 100644
index 0000000..0b9aea2
--- /dev/null
+++ b/go/res/values-sr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Додирните и задржите да бисте изабрали пречицу."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Пречице"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Пречице за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sv/strings.xml b/go/res/values-sv/strings.xml
new file mode 100644
index 0000000..c3f434c
--- /dev/null
+++ b/go/res/values-sv/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Tryck länge om du vill ta upp en genväg."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Genvägar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Genvägar för <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-sw/strings.xml b/go/res/values-sw/strings.xml
new file mode 100644
index 0000000..13c12e4
--- /dev/null
+++ b/go/res/values-sw/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Gusa na ushikilie ili uchague njia ya mkato."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Gusa mara mbili na ushikilie ile uchague njia ya mkato au utumie vitendo maalum."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Njia za mkato"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Njia za mkato za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ta/strings.xml b/go/res/values-ta/strings.xml
new file mode 100644
index 0000000..50059b6
--- /dev/null
+++ b/go/res/values-ta/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"குறுக்குவழியைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"குறுக்குவழியை சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"குறுக்குவழிகள்"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> குறுக்குவழிகள்"</string>
+</resources>
diff --git a/go/res/values-te/strings.xml b/go/res/values-te/strings.xml
new file mode 100644
index 0000000..0bdf743
--- /dev/null
+++ b/go/res/values-te/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"సత్వరమార్గాన్ని ఎంచుకోవడానికి తాకి &amp; నొక్కి ఉంచండి."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"సత్వరమార్గాన్ని ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి &amp;ఉంచండి."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"సత్వరమార్గాలు"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> సత్వరమార్గాలు"</string>
+</resources>
diff --git a/go/res/values-th/strings.xml b/go/res/values-th/strings.xml
new file mode 100644
index 0000000..e73d89f
--- /dev/null
+++ b/go/res/values-th/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"แตะค้างไว้เพื่อเลือกทางลัด"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"ทางลัด"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"ทางลัด <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-tl/strings.xml b/go/res/values-tl/strings.xml
new file mode 100644
index 0000000..8f44ec5
--- /dev/null
+++ b/go/res/values-tl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Pindutin nang matagal upang kumuha ng shortcut."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"I-double tap nang matagal upang kumuha ng shortcut o gumamit ng mga custom na pagkilos."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Mga Shortcut"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Mga shortcut sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-tr/strings.xml b/go/res/values-tr/strings.xml
new file mode 100644
index 0000000..f0f3cce
--- /dev/null
+++ b/go/res/values-tr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Kısayol seçmek için dokunun ve basılı tutun."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Kısayollar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> kısayolları"</string>
+</resources>
diff --git a/go/res/values-uk/strings.xml b/go/res/values-uk/strings.xml
new file mode 100644
index 0000000..8d1f583
--- /dev/null
+++ b/go/res/values-uk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Натисніть і утримуйте, щоб вибрати ярлик."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Двічі натисніть і утримуйте, щоб вибрати ярлик, або виконайте іншу дію."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Ярлики"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Ярлики додатка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-ur/strings.xml b/go/res/values-ur/strings.xml
new file mode 100644
index 0000000..46bd823
--- /dev/null
+++ b/go/res/values-ur/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"کوئی شارٹ کٹ منتخب کرنے کیلئے ٹچ کریں اور دبائے رکھیں۔"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"کوئی شارٹ کٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"شارٹ کٹس"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> شارٹ کٹس"</string>
+</resources>
diff --git a/go/res/values-uz/strings.xml b/go/res/values-uz/strings.xml
new file mode 100644
index 0000000..318bc15
--- /dev/null
+++ b/go/res/values-uz/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Yorliqni tanlab olish uchun bosib turing."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Yorliqlar"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi yorliqlari"</string>
+</resources>
diff --git a/go/res/values-vi/strings.xml b/go/res/values-vi/strings.xml
new file mode 100644
index 0000000..1197619
--- /dev/null
+++ b/go/res/values-vi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Chạm và giữ để chọn lối tắt."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Lối tắt"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"Lối tắt <xliff:g id="NAME">%1$s</xliff:g>"</string>
+</resources>
diff --git a/go/res/values-zh-rCN/strings.xml b/go/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..57351d3
--- /dev/null
+++ b/go/res/values-zh-rCN/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"触摸并按住快捷方式即可选择快捷方式。"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"快捷方式"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g>快捷方式"</string>
+</resources>
diff --git a/go/res/values-zh-rHK/strings.xml b/go/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..dea7749
--- /dev/null
+++ b/go/res/values-zh-rHK/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"按住捷徑即可選取捷徑。"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"扲兩下然後扲住就可以揀選捷徑,或者用自訂嘅操作。"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"捷徑"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> 捷徑"</string>
+</resources>
diff --git a/go/res/values-zh-rTW/strings.xml b/go/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..07ae2ed
--- /dev/null
+++ b/go/res/values-zh-rTW/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"按住捷徑即可選取。"</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"捷徑"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"「<xliff:g id="NAME">%1$s</xliff:g>」捷徑"</string>
+</resources>
diff --git a/go/res/values-zu/strings.xml b/go/res/values-zu/strings.xml
new file mode 100644
index 0000000..e5051df
--- /dev/null
+++ b/go/res/values-zu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="long_press_widget_to_add" msgid="4001616142797446267">"Thinta futhi ubambe ukuze ukhethe isinqamuleli."</string>
+    <string name="long_accessible_way_to_add" msgid="2725225828389948328">"Thepha kabulu futhi ubambe ukuze ukhethe isinqamuleli noma usebenzise izenzo zangokwezifiso."</string>
+    <string name="widget_button_text" msgid="4221900832360456858">"Izinqamuleli"</string>
+    <string name="widgets_bottom_sheet_title" msgid="3949835990909395998">"<xliff:g id="NAME">%1$s</xliff:g> izinqamuleli"</string>
+</resources>
diff --git a/go/res/values/strings.xml b/go/res/values/strings.xml
new file mode 100644
index 0000000..8ef2e62
--- /dev/null
+++ b/go/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Message to tell the user to press and hold on a shortcut to add it [CHAR_LIMIT=50] -->
+    <string name="long_press_widget_to_add">Touch &amp; hold to pick up a shortcut.</string>
+    <!-- Accessibility spoken hint message in widget picker, which allows user to add a shortcut. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=100] -->
+    <string name="long_accessible_way_to_add">Double-tap &amp; hold to pick up a shortcut or use custom actions.</string>
+    <!-- Text for shortcut add button -->
+    <string name="widget_button_text">Shortcuts</string>
+
+    <!-- Strings for widgets & more in the popup container/bottom sheet -->
+    <!-- Title for a bottom sheet that shows shortcuts for a particular app -->
+    <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> shortcuts</string>
+
+</resources>
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
index f324fcd..b11bb7c 100644
--- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -24,5 +24,6 @@
     private FeatureFlags() {}
 
     // Features to control Launcher3Go behavior
+    public static final boolean GO_DISABLE_WIDGETS = true;
     public static final boolean LAUNCHER3_SPRING_ICONS = false;
 }
diff --git a/proguard.flags b/proguard.flags
index b8cade5..ddae07e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -39,7 +39,7 @@
   public int getY();
 }
 
--keep class com.android.launcher3.dragndrop.DragLayer$LayoutParams {
+-keep class com.android.launcher3.views.BaseDragLayer$LayoutParams {
   public void setWidth(int);
   public int getWidth();
   public void setHeight(int);
@@ -97,19 +97,29 @@
 # support jar.
 -keep class android.support.v7.widget.RecyclerView { *; }
 
-# LauncherAppTransitionManager
--keep class com.android.launcher3.LauncherAppTransitionManagerImpl {
+# Preference fragments
+-keep class ** extends android.preference.PreferenceFragment {
+    public <init>(...);
+}
+
+## Prevent obfuscating various overridable objects
+-keep class ** implements com.android.launcher3.util.ResourceBasedOverride {
     public <init>(...);
 }
 
 -keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
   *;
 }
-
 -keep interface com.android.launcher3.model.nano.LauncherDumpProto.** {
   *;
 }
 
+# Discovery bounce animation
+-keep class com.android.launcher3.allapps.DiscoveryBounce$VerticalProgressWrapper {
+  public void setProgress(float);
+  public float getProgress();
+}
+
 # BUG(70852369): Surpress additional warnings after changing from Proguard to R8
 -dontwarn android.app.**
 -dontwarn android.view.**
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index de74fce..41dd0bd 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -55,6 +55,7 @@
   optional int32 span_y = 14 [default = 1];// Used for ItemType.WIDGET
   optional int32 predictedRank = 15;
   optional TargetExtension extension = 16;
+  optional TipType tip_type = 17;
 }
 
 // Used to define what type of item a Target would represent.
@@ -68,6 +69,8 @@
   SEARCHBOX = 6;
   EDITTEXT = 7;
   NOTIFICATION = 8;
+  TASK = 9;         // Each page of Recents UI (QuickStep)
+  WEB_APP = 10;
 }
 
 // Used to define what type of container a Target would represent.
@@ -78,11 +81,16 @@
   FOLDER = 3;
   ALLAPPS = 4;
   WIDGETS = 5;
-  OVERVIEW = 6;
+  OVERVIEW = 6;   // Zoomed out workspace (without QuickStep)
   PREDICTION = 7;
   SEARCHRESULT = 8;
   DEEPSHORTCUTS = 9;
   PINITEM = 10;    // confirmation screen
+  NAVBAR = 11;
+  TASKSWITCHER = 12; // Recents UI Container (QuickStep)
+  APP = 13; // Foreground activity is another app (QuickStep)
+  TIP = 14; // Onboarding texts (QuickStep)
+  SIDELOADED_LAUNCHER = 15;
 }
 
 // Used to define what type of control a Target would represent.
@@ -99,7 +107,19 @@
   VERTICAL_SCROLL = 9;
   HOME_INTENT = 10; // Deprecated, use enum Command instead
   BACK_BUTTON = 11; // Deprecated, use enum Command instead
-  // GO_TO_PLAYSTORE
+  QUICK_SCRUB_BUTTON = 12;
+  CLEAR_ALL_BUTTON = 13;
+  CANCEL_TARGET = 14;
+  TASK_PREVIEW = 15;
+  SPLIT_SCREEN_TARGET = 16;
+}
+
+enum TipType {
+  DEFAULT_NONE = 0;
+  BOUNCE = 1;
+  SWIPE_UP_TEXT = 2;
+  QUICK_SCRUB_TEXT = 3;
+  PREDICTION_TEXT = 4;
 }
 
 // Used to define the action component of the LauncherEvent.
@@ -108,8 +128,10 @@
     TOUCH = 0;
     AUTOMATED = 1;
     COMMAND = 2;
+    TIP = 3;
     // SOFT_KEYBOARD, HARD_KEYBOARD, ASSIST
   }
+
   enum Touch {
     TAP = 0;
     LONGPRESS = 1;
@@ -118,7 +140,8 @@
     FLING = 4;
     PINCH = 5;
   }
- enum Direction {
+
+  enum Direction {
     NONE = 0;
     UP = 1;
     DOWN = 2;
@@ -128,11 +151,13 @@
   enum Command {
     HOME_INTENT = 0;
     BACK = 1;
-    ENTRY = 2;    // Indicates entry to one of Launcher container type target
-                  // not using the HOME_INTENT
-    CANCEL = 3;   // Indicates that a confirmation screen was cancelled
-    CONFIRM = 4;  // Indicates thata confirmation screen was accepted
-    STOP = 5;     // Indicates onStop() was called (screen time out, power off)
+    ENTRY = 2;          // Indicates entry to one of Launcher container type target
+                        // not using the HOME_INTENT
+    CANCEL = 3;         // Indicates that a confirmation screen was cancelled
+    CONFIRM = 4;        // Indicates thata confirmation screen was accepted
+    STOP = 5;           // Indicates onStop() was called (screen time out, power off)
+    RECENTS_BUTTON = 6; // Indicates that Recents button was pressed
+    RESUME = 7;         // Indicates onResume() was called
   }
 
   optional Type type = 1;
@@ -141,6 +166,7 @@
   optional Command command = 4;
   // Log if the action was performed on outside of the container
   optional bool is_outside = 5;
+  optional bool is_state_change = 6;
 }
 
 //
@@ -150,7 +176,6 @@
 //
 message LauncherEvent {
   required Action action = 1;
-
   // List of targets that touch actions can be operated on.
   repeated Target src_target = 2;
   repeated Target dest_target = 3;
@@ -159,8 +184,8 @@
   optional int64 elapsed_container_millis = 5;
   optional int64 elapsed_session_millis = 6;
 
-  optional bool is_in_multi_window_mode = 7;
-  optional bool is_in_landscape_mode = 8;
+  optional bool is_in_multi_window_mode = 7 [deprecated = true];
+  optional bool is_in_landscape_mode = 8 [deprecated = true];
 
   optional LauncherEventExtension extension = 9;
 }
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 02b4379..74e0b1e 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -19,11 +19,12 @@
 -->
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     package="com.android.launcher3" >
 
-    <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
-
+    <uses-sdk android:targetSdkVersion="28" android:minSdkVersion="28"/>
     <uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
+
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
         android:fullBackupOnly="true"
@@ -31,18 +32,51 @@
         android:hardwareAccelerated="true"
         android:icon="@drawable/ic_launcher_home"
         android:label="@string/derived_app_name"
-        android:theme="@style/LauncherTheme"
+        android:theme="@style/AppTheme"
         android:largeHeap="@bool/config_largeHeap"
         android:restoreAnyVersion="true"
         android:supportsRtl="true" >
 
-        <service android:name="com.android.quickstep.TouchInteractionService"
-            android:exported="true" />
+        <service
+            android:name="com.android.quickstep.TouchInteractionService"
+            android:permission="android.permission.STATUS_BAR_SERVICE" >
+            <intent-filter>
+                <action android:name="android.intent.action.QUICKSTEP_SERVICE" />
+            </intent-filter>
+        </service>
 
         <!-- STOPSHIP: Change exported to false once all the integration is complete.
         It is set to true so that the activity can be started from command line -->
         <activity android:name="com.android.quickstep.RecentsActivity"
-            android:exported="true" />
+            android:exported="true"
+            android:excludeFromRecents="true"
+            android:launchMode="singleTask"
+            android:clearTaskOnLaunch="true"
+            android:stateNotNeeded="true"
+            android:theme="@style/LauncherTheme"
+            android:screenOrientation="unspecified"
+            android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+            android:resizeableActivity="true"
+            android:resumeWhilePausing="true"
+            android:taskAffinity="" />
+
+        <!-- Content provider to settings search. The autority should be same as the packageName -->
+        <provider
+            android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
+            android:authorities="${packageName}"
+            android:grantUriPermissions="true"
+            android:multiprocess="true"
+            android:permission="android.permission.READ_SEARCH_INDEXABLES"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
+            </intent-filter>
+        </provider>
+
+        <service
+            android:name="com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL$ColorExtractionService"
+            tools:node="remove" />
+
     </application>
 
 </manifest>
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index d1ac936..27de1e9 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index d4f995d..0000000
--- a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_left.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 9013c1a..0000000
--- a/quickstep/res/drawable-hdpi/recents_horizontal_scrim_right.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 6e924ec..0000000
--- a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_left.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 33d0edd..0000000
--- a/quickstep/res/drawable-mdpi/recents_horizontal_scrim_right.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 20c85e6..0000000
--- a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_left.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 58a1ca0..0000000
--- a/quickstep/res/drawable-xhdpi/recents_horizontal_scrim_right.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 9d3dc31..0000000
--- a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_left.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index 7fb248b..0000000
--- a/quickstep/res/drawable-xxhdpi/recents_horizontal_scrim_right.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png
deleted file mode 100644
index 49ec7aa..0000000
--- a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_left.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png b/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png
deleted file mode 100644
index a8922e2..0000000
--- a/quickstep/res/drawable-xxxhdpi/recents_horizontal_scrim_right.png
+++ /dev/null
Binary files differ
diff --git a/quickstep/res/drawable/ic_empty_recents.xml b/quickstep/res/drawable/ic_empty_recents.xml
new file mode 100644
index 0000000..5183733
--- /dev/null
+++ b/quickstep/res/drawable/ic_empty_recents.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2018 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="92dp"
+    android:height="80dp"
+    android:viewportWidth="92.0"
+    android:viewportHeight="80.0"
+    android:tint="?android:attr/textColorPrimary">
+    <path
+        android:fillColor="#AAFFFFFF"
+        android:pathData="M18,6H2C0.9,6,0,6.9,0,8v64c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C20,6.9,19.1,6,18,6z M16,69.25
+        c0,0.41-0.34,0.75-0.75,0.75H4.75C4.34,70,4,69.66,4,69.25v-58.5C4,10.34,4.34,10,4.75,10h10.5c0.41,0,0.75,0.34,0.75,0.75V69.25
+        z M90,6H74c-1.1,0-2,0.9-2,2v64c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8C92,6.9,91.1,6,90,6z M88,69.25c0,0.41-0.34,0.75-0.75,0.75
+        h-10.5C76.34,70,76,69.66,76,69.25v-58.5c0-0.41,0.34-0.75,0.75-0.75h10.5c0.41,0,0.75,0.34,0.75,0.75V69.25z M64,0H28
+        c-2.21,0-4,1.79-4,4v72c0,2.21,1.79,4,4,4h36c2.21,0,4-1.79,4-4V4C68,1.79,66.21,0,64,0z M64,75c0,0.55-0.45,1-1,1H29
+        c-0.55,0-1-0.45-1-1V5c0-0.55,0.45-1,1-1h34c0.55,0,1,0.45,1,1V75z"/>
+</vector>
diff --git a/quickstep/res/drawable/ic_split_screen.xml b/quickstep/res/drawable/ic_split_screen.xml
index 77bd333..110af91 100644
--- a/quickstep/res/drawable/ic_split_screen.xml
+++ b/quickstep/res/drawable/ic_split_screen.xml
@@ -13,33 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="88.0dp"
-        android:height="88.0dp"
-        android:viewportWidth="88.0"
-        android:viewportHeight="88.0" >
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
 
     <path
-        android:pathData="M 32,11
-           C 32,11 68,11 68,11
-             76.74,11.06 76.98,12.76 77,21
-             77.01,25.97 78.50,38.23 73.85,40.98
-             71.80,42.19 68.35,42 66,42
-             66,42 22,42 22,42
-             18.82,41.99 14.87,42.38 12.60,39.69
-             10.71,37.44 11.01,33.77 11,31
-             10.99,25.54 9.53,16.08 13.31,12.02
-             18.07,10.21 26.66,11 32,11 Z
-           M 32,46
-           C 32,46 68,46 68,46
-             76.74,46.06 76.98,47.76 77,56
-             77.01,60.97 78.50,73.23 73.85,75.98
-             71.80,77.19 68.35,77 66,77
-             66,77 22,77 22,77
-             18.82,76.99 14.87,77.38 12.60,74.69
-             10.71,72.44 11.01,68.77 11,66
-             10.99,60.54 9.53,51.08 13.31,47.02
-             18.07,45.21 26.66,46 32,46 Z"
-        android:fillColor="@android:color/white" />
-</vector>
\ No newline at end of file
+        android:fillColor="@android:color/white"
+        android:pathData="M18,4v5H6V4H18 M18,2H6C4.9,2,4,2.9,4,4v5c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V4C20,2.9,19.1,2,18,2L18,2z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18,15v5H6v-5H18 M18,13H6c-1.1,0-2,0.9-2,2v5c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2v-5C20,13.9,19.1,13,18,13L18,13z" />
+</vector>
diff --git a/quickstep/res/drawable/task_menu_bg.xml b/quickstep/res/drawable/task_menu_bg.xml
new file mode 100644
index 0000000..d5597a9
--- /dev/null
+++ b/quickstep/res/drawable/task_menu_bg.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="bottom">
+        <!-- Shadow -->
+        <shape>
+            <gradient android:angle="270"
+                android:endColor="@android:color/transparent"
+                android:startColor="#26000000" />
+            <size android:height="@dimen/task_card_menu_shadow_height" />
+        </shape>
+    </item>
+    <item android:bottom="@dimen/task_card_menu_shadow_height">
+        <!-- Background -->
+        <shape>
+            <corners
+                android:topLeftRadius="@dimen/task_corner_radius"
+                android:topRightRadius="@dimen/task_corner_radius"
+                android:bottomLeftRadius="0dp"
+                android:bottomRightRadius="0dp" />
+            <solid android:color="?attr/popupColorPrimary" />
+        </shape>
+    </item>
+</layer-list>
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
new file mode 100644
index 0000000..ef272ed
--- /dev/null
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+     Copyright (C) 2018 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.quickstep.fallback.RecentsRootView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/drag_layer"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+
+    <com.android.quickstep.fallback.FallbackRecentsView
+        android:id="@id/overview_panel"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:outlineProvider="none"
+        android:theme="@style/HomeScreenElementTheme" />
+</com.android.quickstep.fallback.RecentsRootView>
diff --git a/quickstep/res/layout/longpress_options_menu.xml b/quickstep/res/layout/longpress_options_menu.xml
deleted file mode 100644
index 9cf0fcf..0000000
--- a/quickstep/res/layout/longpress_options_menu.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.uioverrides.OptionsPopupView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="96dp"
-    android:background="?attr/popupColorPrimary"
-    android:elevation="@dimen/deep_shortcuts_elevation"
-    android:orientation="horizontal"
-    launcher:layout_ignoreInsets="true">
-
-    <FrameLayout
-        android:id="@+id/wallpaper_button"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground">
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:drawablePadding="4dp"
-            android:drawableTint="?android:attr/textColorPrimary"
-            android:drawableTop="@drawable/ic_wallpaper"
-            android:fontFamily="sans-serif-condensed"
-            android:gravity="center"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
-            android:text="@string/wallpaper_button_text"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="12sp"/>
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/widget_button"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground">
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:drawablePadding="4dp"
-            android:drawableTint="?android:attr/textColorPrimary"
-            android:drawableTop="@drawable/ic_widget"
-            android:fontFamily="sans-serif-condensed"
-            android:gravity="center"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
-            android:text="@string/widget_button_text"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="12sp"/>
-
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/settings_button"
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground">
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:drawablePadding="4dp"
-            android:drawableTint="?android:attr/textColorPrimary"
-            android:drawableTop="@drawable/ic_setting"
-            android:fontFamily="sans-serif-condensed"
-            android:gravity="center"
-            android:paddingLeft="16dp"
-            android:paddingRight="16dp"
-            android:text="@string/settings_button_text"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="12sp"/>
-
-    </FrameLayout>
-
-</com.android.launcher3.uioverrides.OptionsPopupView>
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_scrim.xml b/quickstep/res/layout/overview_clear_all_button.xml
similarity index 60%
copy from res/layout/widgets_bottom_sheet_scrim.xml
copy to quickstep/res/layout/overview_clear_all_button.xml
index 6c6626c..ea7a494 100644
--- a/res/layout/widgets_bottom_sheet_scrim.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!--
+     Copyright (C) 2018 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.
@@ -13,11 +14,13 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<com.android.launcher3.graphics.GradientView
+<com.android.quickstep.views.ClearAllButton
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/gradient_bg"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    launcher:layout_ignoreInsets="true" />
\ No newline at end of file
+    style="@android:style/Widget.DeviceDefault.Button.Borderless"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/recents_clear_all"
+    android:textColor="?attr/workspaceTextColor"
+    android:textSize="14sp"
+    android:translationY="@dimen/task_thumbnail_half_top_margin"
+    />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 9f4f8a1..7f1425b 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -14,18 +14,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.RecentsView
+<com.android.quickstep.views.LauncherRecentsView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:theme="@style/HomeScreenElementTheme"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:alpha="0.0"
-    android:visibility="invisible" >
-
-    <com.android.launcher3.uioverrides.WorkspaceCard
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</com.android.quickstep.RecentsView>
\ No newline at end of file
+    android:accessibilityPaneTitle="@string/accessibility_recent_apps"
+    android:visibility="invisible" />
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_scrim.xml b/quickstep/res/layout/scrim_view.xml
similarity index 75%
rename from res/layout/widgets_bottom_sheet_scrim.xml
rename to quickstep/res/layout/scrim_view.xml
index 6c6626c..2cc37f9 100644
--- a/res/layout/widgets_bottom_sheet_scrim.xml
+++ b/quickstep/res/layout/scrim_view.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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.
@@ -13,11 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<com.android.launcher3.graphics.GradientView
+<com.android.quickstep.views.ShelfScrimView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/gradient_bg"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    launcher:layout_ignoreInsets="true" />
\ No newline at end of file
+    android:id="@+id/scrim_view" />
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 91b6aa3..36d327d 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -13,20 +13,25 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.views.TaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:elevation="4dp">
+    android:defaultFocusHighlightEnabled="false"
+    android:elevation="4dp"
+    android:focusable="true">
 
-    <com.android.quickstep.TaskThumbnailView
+    <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginTop="@dimen/task_thumbnail_top_margin" />
 
-    <ImageView
+    <com.android.quickstep.views.IconView
         android:id="@+id/icon"
         android:layout_width="@dimen/task_thumbnail_icon_size"
         android:layout_height="@dimen/task_thumbnail_icon_size"
-        android:layout_gravity="top|center_horizontal" />
-</com.android.quickstep.TaskView>
\ No newline at end of file
+        android:layout_gravity="top|center_horizontal"
+        android:focusable="false"
+        android:importantForAccessibility="no" />
+</com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 6e3fb4f..098b34f 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -14,23 +14,41 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.TaskMenuView
+<com.android.quickstep.views.TaskMenuView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/bg_popup_item_width"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:visibility="invisible"
-    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:animateLayoutChanges="true"
+    android:background="@drawable/task_menu_bg"
+    android:paddingBottom="@dimen/task_card_menu_shadow_height"
     android:orientation="vertical"
-    android:background="?attr/popupColorPrimary"
-    android:divider="@drawable/all_apps_divider"
-    android:showDividers="middle"
-    android:animateLayoutChanges="true">
-        <TextView
-            android:id="@+id/task_icon_and_name"
-            android:layout_width="match_parent"
-            android:layout_height="112dp"
-            android:textSize="14sp"
-            android:paddingTop="18dp"
-            android:drawablePadding="8dp"
-            android:gravity="center_horizontal"/>
-</com.android.quickstep.TaskMenuView>
\ No newline at end of file
+    android:visibility="invisible">
+
+    <com.android.quickstep.views.IconView
+      android:id="@+id/task_icon"
+      android:layout_width="@dimen/task_thumbnail_icon_size"
+      android:layout_height="@dimen/task_thumbnail_icon_size"
+      android:layout_gravity="top|center_horizontal"
+      android:layout_marginBottom="@dimen/deep_shortcut_drawable_padding"
+      android:focusable="false"
+      android:importantForAccessibility="no" />
+
+    <TextView
+        android:id="@+id/task_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:layout_marginBottom="16dp"
+        android:textSize="12sp"/>
+
+    <LinearLayout
+        android:id="@+id/menu_option_layout"
+        style="@style/TaskMenu"
+        android:divider="@drawable/all_apps_divider"
+        android:showDividers="beginning"
+        android:paddingStart="@dimen/task_card_menu_horizontal_padding"
+        android:paddingEnd="@dimen/task_card_menu_horizontal_padding"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+</com.android.quickstep.views.TaskMenuView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
new file mode 100644
index 0000000..102ae9b
--- /dev/null
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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"
+    style="@style/TaskMenu.Option"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    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/selectableItemBackground"
+    android:theme="@style/PopupItem" >
+
+    <View
+      android:id="@+id/icon"
+      android:layout_width="@dimen/system_shortcut_icon_size"
+      android:layout_height="@dimen/system_shortcut_icon_size"
+      android:layout_marginTop="@dimen/system_shortcut_header_icon_padding"
+      android:layout_marginBottom="@dimen/deep_shortcut_drawable_padding"
+      android:layout_gravity="center_horizontal"
+      android:backgroundTint="?android:attr/textColorTertiary"/>
+
+    <TextView
+        style="@style/BaseIcon"
+        android:id="@+id/text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/popup_padding_end"
+        android:textSize="12sp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:fontFamily="sans-serif"
+        android:gravity="center_horizontal"
+        android:layout_gravity="center_horizontal"
+        android:focusable="false" />
+
+</LinearLayout>
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index b4c735b..8ae493f 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Verdeelde skerm"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Swiep van onder af op om programme te wissel"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oorsig"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Maak toe"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Onlangse programme"</string>
 </resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 62d54db..4ca0c67 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"የተከፈለ ማያ ገጽ"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ማጠቃለያ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ዝጋ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"የቅርብ ጊዜ መተግበሪያዎች"</string>
 </resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index de210b7..c04b618 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"تقسيم الشاشة"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"نظرة عامة"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"إغلاق"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"التطبيقات التي تمّ استخدامها مؤخرًا"</string>
 </resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
new file mode 100644
index 0000000..812a246
--- /dev/null
+++ b/quickstep/res/values-as/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recent_task_option_split_screen" msgid="5353188922202653570">"বিভাজিত স্ক্ৰীণ"</string>
+    <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"অৱলোকন"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"বন্ধ কৰক"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"সকলো মচক"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"শেহতীয়া এপসমূহ"</string>
+</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 91c5179..832ed8c 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Bölünmüş ekran"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Tətbiqləri dəyişmək üçün aşağıdan yuxarı doğru sürüşdürün"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"İcmal"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Bağlayın"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Son tətbiqlər"</string>
 </resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index a4eb3e8..fc4c8c0 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Podeljeni ekran"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Prevucite nagore da biste prešli na drugu aplikaciju"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zatvori"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
 </resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index f798802..c5d03d4 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Падзяліць экран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Для пераключэння праграм правядзіце па экране пальцам знізу ўверх"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Агляд"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Закрыць"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Нядаўнія праграмы"</string>
 </resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index de88634..2672b83 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Разделен екран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Прекарайте пръст нагоре от долната част, за да превключите между приложенията"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Общ преглед"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Затваряне"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Скорошни приложения"</string>
 </resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 028a475..0a824c2 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"স্ক্রিন স্প্লিট করুন"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"অ্যাপগুলির মধ্যে সুইচ করতে উপর থেকে নিচের দিকে সোয়াইপ করুন"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"এক নজরে"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"কোনো সাম্প্রতিক আইটেম নেই"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"বন্ধ করুন"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"সম্প্রতি ব্যবহৃত অ্যাপ"</string>
 </resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 16b72ea..6bf38eb 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Način rada podijeljenog ekrana"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Prevucite od dolje prema gore za promjenu aplikacije"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zatvaranje"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
 </resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 6d65fd7..2d51703 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Divideix la pantalla"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Llisca cap amunt des de la part inferior per canviar d\'aplicació"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aplicacions recents"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Tanca"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacions recents"</string>
 </resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index b6894c0..a178df0 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Rozdělená obrazovka"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"PIN"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Aplikace můžete přepínat přejetím zdola nahoru"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Přehled"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Žádné nedávné položky"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zavřít"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Poslední aplikace"</string>
 </resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index ff2d25d..d0d629f 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Delt skærm"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Stryg opad fra bunden for at skifte apps"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oversigt"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Luk"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Seneste apps"</string>
 </resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index e5242c7..aee8b85 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Bildschirm teilen"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Zum Wechseln zwischen Apps vom unteren Bildschirmrand nach oben wischen"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Übersicht"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Schließen"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Zuletzt aktive Apps"</string>
 </resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 9d7023d..7364b82 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Διαχωρισμός οθόνης"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Επισκόπηση"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Κλείσιμο"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Πρόσφατες εφαρμογές"</string>
 </resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 694e73a..d0dc1e8 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Split screen"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Swipe up from the bottom to switch apps"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
 </resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 694e73a..d0dc1e8 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Split screen"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Swipe up from the bottom to switch apps"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
 </resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 694e73a..d0dc1e8 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Split screen"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Swipe up from the bottom to switch apps"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Close"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Recent apps"</string>
 </resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 37a3168..83e9d96 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Pantalla dividida"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Desliza el dedo hacia arriba para cambiar de app"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Recientes"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Cerrar"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recientes"</string>
 </resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 60c87d3..e076df5 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Dividir pantalla"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Desliza el dedo hacia arriba desde la parte inferior para cambiar de aplicación"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aplicaciones recientes"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Cerrar"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicaciones recientes"</string>
 </resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 33d1cba..85de9c0 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Jagatud ekraan"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Rakenduste vahetamiseks pühkige alaosast üles"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ülevaade"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Sule"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Hiljutised rakendused"</string>
 </resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index d0e86c2..60943cc 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Zatitu pantaila"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Aplikazioak aldatzeko, pasatu hatza pantailako behealdetik gora"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikuspegi orokorra"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Itxi"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Azken aplikazioak"</string>
 </resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 198f33d..4a30daa 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"تقسیم صفحه"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"برای تغییر برنامه‌ها،‌ از پایین تند به بالا بکشید"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"نمای کلی"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"بدون موارد اخیر"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"بستن"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"برنامه‌های اخیر"</string>
 </resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index f244586..8f41350 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Jaettu näyttö"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Vaihda sovellusta pyyhkäisemällä alareunasta ylös."</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Viimeisimmät"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Sulje"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Viimeisimmät sovellukset"</string>
 </resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index d9b2a51..7177996 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Écran divisé"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Balayez l\'écran du bas vers le haut pour changer d\'application"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aperçu"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Fermer"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
 </resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 8c1a5d2..0deb00b 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Écran partagé"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Balayer l\'écran de bas en haut pour changer d\'application"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Aperçu"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Fermer"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
 </resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index d6f26ac..8c217eb 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Pantalla dividida"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Pasa o dedo cara arriba desde a parte inferior para cambiar de aplicacións"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Visión xeral"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Pecha a aplicación"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicacións recentes"</string>
 </resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 8c779d6..8b9a538 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"સ્ક્રીનને વિભાજિત કરો"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ઍપને સ્વિચ કરવા માટે નીચેથી ઉપર સ્વાઇપ કરો"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ઝલક"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"બંધ કરો"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"તાજેતરની ઍપ"</string>
 </resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 65507a9..83c31e7 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"स्क्रीन को दो हिस्सों में बाँटना (स्प्लिट स्क्रीन)"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करना"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ऐप्लिकेशन स्विच करने के लिए सबसे नीचे से ऊपर की ओर स्वाइप करें"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"खास जानकारी"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"हाल ही में इस्तेमाल किया गया कोई ऐप्लिकेशन नहीं है"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"बंद करें"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"सभी ऐप्लिकेशन बंद करें"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"हाल ही में इस्तेमाल किए गए एेप्लिकेशन"</string>
 </resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index eaa4416..baa8d85 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Podijeljeni zaslon"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Prijeđite prstom od dna prema gore da biste promijenili aplikaciju"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zatvori"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
 </resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index b72c760..d971374 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Osztott képernyő"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Rögzítés"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Ha váltani szeretne az alkalmazások között, csúsztassa gyorsan az ujját a képernyő aljától felfelé"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Áttekintés"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Bezárás"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Legutóbbi alkalmazások"</string>
 </resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 632ea3e..b4b9b98 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Տրոհել էկրանը"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Սահեցրեք ներքևից վերև՝ մյուս հավելվածին անցնելու համար"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ընդհանուր տեղեկություններ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Փակել"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին օգտագործած հավելվածները"</string>
 </resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d731bce..787c143 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Layar terpisah"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pasang pin"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Geser dari bawah ke atas untuk beralih aplikasi"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ringkasan"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Tutup"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikasi baru-baru ini"</string>
 </resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index d4d54d3..1aface0 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Skipta skjá"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Strjúktu upp til að skipta um forrit"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Yfirlit"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Loka"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nýleg forrit"</string>
 </resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 6223ddb..192ec44 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Schermo diviso"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Scorri verso l\'alto dalla parte inferiore per cambiare app"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Panoramica"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Chiudi"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"App recenti"</string>
 </resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 1da258a..64c35ec 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"מסך מפוצל"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"יש להחליק כלפי מעלה מהחלק התחתון כדי לעבור בין אפליקציות"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"מסכים אחרונים"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"סגירה"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"אפליקציות אחרונות"</string>
 </resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index bee863f..558112c 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"分割画面"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"アプリを切り替えるには、下から上にスワイプします"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概要"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"閉じる"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使ったアプリ"</string>
 </resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 4488cf8..5f061de 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ეკრანის გაყოფა"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"აპების გადასართავად გადაფურცლეთ ქვედა კიდედან ზემოთ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"მიმოხილვა"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"დახურვა"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ბოლოდროინდელი აპები"</string>
 </resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 8c82ef1..3e72130 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Экранды бөлу"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Қолданбалар арасында ауысу үшін төменнен жоғары қарай саусақпен сырғытыңыз"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Шолу"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Жабу"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Соңғы пайдаланылған қолданбалар"</string>
 </resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 64136c9..6ae9482 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"មុខងារ​បំបែកអេក្រង់"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ដៅ"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"អូស​ពី​ក្រោម​ឡើង​លើ ដើម្បី​ប្ដូរ​កម្មវិធី"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ទិដ្ឋភាពរួម"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"បិទ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"សម្អាត​ទាំងអស់"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"កម្មវិធី​ថ្មីៗ"</string>
 </resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 7f12dee..591418b 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ಪರದೆಯನ್ನು ಬೇರ್ಪಡಿಸಿ"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ಅವಲೋಕನ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ಮುಚ್ಚಿ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
 </resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 39fdf33..5b1ecbd 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"화면 분할"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"아래에서 위로 스와이프하여 앱을 전환합니다."</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"최근 사용"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"닫기"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"최근 앱"</string>
 </resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 2602b51..9f84037 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Экранды бөлүү"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Колдонмолорду которуштуруу үчүн экранды төмөндөн жогору карай сүрүңүз"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Сереп салуу"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Жабуу"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Акыркы колдонмолор"</string>
 </resources>
diff --git a/res/drawable/all_apps_search_divider.xml b/quickstep/res/values-land/dimens.xml
similarity index 70%
copy from res/drawable/all_apps_search_divider.xml
copy to quickstep/res/values-land/dimens.xml
index 99905e4..c03eaa2 100644
--- a/res/drawable/all_apps_search_divider.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2018 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.
@@ -13,8 +14,6 @@
      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="?android:attr/colorAccent" />
-    <size android:height="1dp" />
-</shape>
\ No newline at end of file
+<resources>
+    <dimen name="task_card_menu_horizontal_padding">24dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-land/styles.xml b/quickstep/res/values-land/styles.xml
new file mode 100644
index 0000000..0824b4f
--- /dev/null
+++ b/quickstep/res/values-land/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 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>
+    <!-- Task Menu layout styles. -->
+    <style name="TaskMenu">
+        <item name="android:orientation">horizontal</item>
+    </style>
+
+    <!-- Task Menu Option layout styles. -->
+    <style name="TaskMenu.Option">
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_weight">1</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 7ba29d2..ed1cb6e 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ແບ່ງໜ້າຈໍ"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ປັດຂຶ້ນຈາກລຸ່ມສຸດເພື່ອສະຫຼັບແອັບ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ພາບຮວມ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ປິດ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ແອັບຫຼ້າສຸດ"</string>
 </resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 2252381..c16fc56 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Skaidyti ekraną"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Perbraukite aukštyn iš apačios, kad perjungtumėte programas"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Apžvalga"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Uždaryti"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Naujausios programos"</string>
 </resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index d5f5e9c..2dee41c 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Sadalīt ekrānu"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Lai pārslēgtu lietotnes, velciet augšup no apakšdaļas."</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pārskats"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Aizvērt"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Pēdējās izmantotās lietotnes"</string>
 </resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 6458aa0..ff16cea 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Поделен екран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Прикачување"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Повлечете нагоре од дното за да ги смените апликациите"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Преглед"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Затвори"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Исчисти ги сите"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Неодамнешни апликации"</string>
 </resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 4d2745a..624aded 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"സ്‌ക്രീൻ വിഭജിക്കുക"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"അവലോകനം"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"അവസാനിപ്പിക്കുക"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്‌ക്കുക"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"സമീപകാല ആപ്പുകൾ"</string>
 </resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 4aec257..f902125 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Дэлгэцийг хуваах"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Тогтоох"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Аппыг сэлгэхийн тулд доороос дээш шударна уу"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Тойм"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Хаах"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг устгах"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Саяхны аппууд"</string>
 </resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 3f85d77..7a669dd 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"विभाजित स्क्रीन"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"अ‍ॅप्स स्विच करण्यासाठी तळापासून वर स्वाइप करा"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"अवलोकन"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"बंद"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"अलीकडील अॅप्स"</string>
 </resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 80e942c..6995863 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Skrin pisah"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Leret ke atas dari bawah untuk menukar apl"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Ikhtisar"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Tutup"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Apl terbaharu"</string>
 </resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index b6b0300..ae6dc7d 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးခြင်း"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"အနှစ်ချုပ်"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ပိတ်ရန်"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးကို ရှင်းရန်"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"လတ်တလောသုံး အက်ပ်များ"</string>
 </resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 4dc144c..cb8ee10 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Delt skjerm"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Sveip opp fra bunnen for å bytte app"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Oversikt"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Lukk"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nylige apper"</string>
 </resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index a171b73..4efae7b 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"स्क्रिन विभाजन गर्नुहोस्"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"परिदृश्य"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"बन्द गर्नुहोस्"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका अनुप्रयोगहरू"</string>
 </resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 4acddc5..8ef2a5d 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Gesplitst scherm"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Veeg omhoog vanaf de onderkant om tussen apps te wisselen"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overzicht"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Sluiten"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Recente apps"</string>
 </resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
new file mode 100644
index 0000000..6895ef5
--- /dev/null
+++ b/quickstep/res/values-or/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2017 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ସ୍କ୍ରୀନ୍‌କୁ ଭାଗ କରନ୍ତୁ"</string>
+    <string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍‍"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ସଂକ୍ଷିପ୍ତ ବିବରଣ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"କୌଣସି ସାମ୍ପ୍ରତିକ ଆଇଟମ୍ ନାହିଁ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ବନ୍ଦ କରନ୍ତୁ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ସାମ୍ପ୍ରତିକ ଆପ୍‌"</string>
+</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 6bc1876..4159c30 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ਐਪਾਂ ਵਿੱਚ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ਰੂਪ-ਰੇਖਾ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ਬੰਦ ਕਰੋ"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ਹਾਲੀਆ ਐਪਾਂ"</string>
 </resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 174a96a..cf15abd 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Podziel ekran"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Przesuń palcem z dołu ekranu, by przełączać aplikacje"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Przegląd"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zamknij"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Ostatnie aplikacje"</string>
 </resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index c3df4f2..36c7e3c 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ecrã dividido"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Deslize rapidamente para cima a partir da parte inferior para alternar entre aplicações."</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Vista geral"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Fechar"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicações recentes"</string>
 </resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 9730b98..41f53f0 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Tela dividida"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Deslize de baixo para cima para alternar entre apps"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Visão geral"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Fechar"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Apps recentes"</string>
 </resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 46671e8..032d886 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ecran divizat"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixați"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Glisați de jos în sus pentru a schimba aplicațiile"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Recente"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Închideți"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Ștergeți tot"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplicații recente"</string>
 </resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index c2edf75..6a218fc 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Разделить экран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Блокировать"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Чтобы переключить приложение, проведите по экрану снизу вверх"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Обзор"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Закрыть"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавние приложения"</string>
 </resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 7702543..c01211a 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"බෙදුම් තිරය"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"දළ විශ්ලේෂණය"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"වසන්න"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"මෑත යෙදුම්"</string>
 </resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 84e7793..2cd3942 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Rozdeliť obrazovku"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Aplikácie môžete prepínať potiahnutím prstom zdola nahor"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Prehľad"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zavrieť"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedávne aplikácie"</string>
 </resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index c01fcd4..06eb95d 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Razdeljen zaslon"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Če želite preklopiti med aplikacijami, z dna zaslona s prstom povlecite navzgor"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Pregled"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Zapri"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
 </resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index ae6e6bc..00231e1 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ekrani i ndarë"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Rrëshqit larg nga poshtë për të ndryshuar aplikacionet"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Përmbledhja"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Mbyll"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Aplikacionet e fundit"</string>
 </resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 84debfd..0077ee2 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Подељени екран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Превуците нагоре да бисте прешли на другу апликацију"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Преглед"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Затвори"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавне апликације"</string>
 </resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 495bca7..f05d79f 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Delad skärm"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Växla mellan appar genom att svepa uppåt från nederkanten"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Översikt"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Listan med de senaste åtgärderna är tom"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Stäng"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Senaste apparna"</string>
 </resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 63594f2..e6ce953 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Gawa skrini"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Telezesha kidole juu kuanzia chini ili ubadilishe programu"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Muhtasari"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Funga"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Programu za hivi karibuni"</string>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 2d740ca..19518e1 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"திரைப் பிரிப்பு"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்க"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"மேலோட்டப் பார்வை"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"மூடும்"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"சமீபத்திய ஆப்ஸ்"</string>
 </resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 36e5e3e..4c0e5ac 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"స్క్రీన్‌ని విభజించు"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయి"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"యాప్‌లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"అవలోకనం"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"మూసివేయండి"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"ఇటీవలి యాప్‌లు"</string>
 </resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 882b096..8dfda24 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"แยกหน้าจอ"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ตรึง"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"ภาพรวม"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"ปิด"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"แอปล่าสุด"</string>
 </resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index dbd03b1..ab3cac9 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Hatiin ang screen"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Mag-swipe pataas mula sa ibaba para lumipat ng app"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Overview"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Isara"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Mga kamakailang app"</string>
 </resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 57cb349..9693413 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Bölünmüş ekran"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Uygulamaları değiştirmek için alttan yukarı kaydırın"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Genel bakış"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Kapat"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Son uygulamalar"</string>
 </resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 8c2c6f6..2afcb31 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Розділити екран"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Щоб переходити між додатками, проводьте пальцем знизу вгору"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Огляд"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Закрити"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Нещодавні додатки"</string>
 </resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index ab5b38f..f493a2f 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"اسپلٹ اسکرین وضع"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"ایپس کو سوئچ کرنے کیلئے نیچے سے اوپر سوائپ کریں"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"مجموعی جائزہ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"بند کریں"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"حالیہ ایپس"</string>
 </resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 280bd88..4911925 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Ekranni ikkiga ajratish"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Mahkamlash"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Ilovalarni almashtirish uchun pastdan yuqoriga suring"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Nazar"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Yopish"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Yaqinda ishlatilgan ilovalar"</string>
 </resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 2aca3b8..406faf5 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Chia đôi màn hình"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Vuốt từ dưới lên để chuyển đổi ứng dụng"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Tổng quan"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Đóng"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Ứng dụng gần đây"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 165f141..71ac114 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"分屏"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"从屏幕底部向上滑动即可切换应用"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概览"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"关闭"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"最近用过的应用"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 6ba0244..ab29a91 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"分割畫面"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"從螢幕底部向上快速滑動,即可切換應用程式"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"概覽"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"關閉"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 9834038..1a9448c 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"分割畫面"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"從畫面底部向上滑動以切換應用程式"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"總覽"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"關閉"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"最近使用的應用程式"</string>
 </resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index a4ba48c..3d4f372 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -21,5 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_split_screen" msgid="5353188922202653570">"Hlukanisa isikrini"</string>
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
-    <string name="recents_swipe_up_onboarding" msgid="1025535041275136564">"Swayiphela phezulu kusukela phansi ukuze ushintshe izinhlelo zokusebenza"</string>
+    <string name="accessibility_desc_recent_apps" msgid="1444379410873162882">"Buka konke"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
+    <string name="accessibility_close_task" msgid="5354563209433803643">"Vala"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Izinhlelo zokusebenza zakamuva"</string>
 </resources>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 94211c6..c294376 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -16,4 +16,7 @@
 <resources>
     <string name="task_overlay_factory_class" translatable="false"></string>
 
+    <string name="overview_callbacks_class" translatable="false"></string>
+
+    <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d8504f1..49c4492 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,25 +16,43 @@
 
 <resources>
 
-    <dimen name="options_menu_icon_size">24dp</dimen>
-
     <dimen name="task_thumbnail_top_margin">24dp</dimen>
+    <dimen name="task_thumbnail_half_top_margin">12dp</dimen>
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
-    <dimen name="task_menu_background_radius">12dp</dimen>
     <dimen name="task_corner_radius">2dp</dimen>
-    <dimen name="task_fade_length">20dp</dimen>
     <dimen name="recents_page_spacing">10dp</dimen>
+    <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
+    <dimen name="quickscrub_adjacent_visible_width">20dp</dimen>
 
+    <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
+             loading full resolution screenshots. -->
+    <dimen name="recents_fast_fling_velocity">600dp</dimen>
 
     <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
     <dimen name="quickstep_fling_min_velocity">250dp</dimen>
 
-    <dimen name="workspace_overview_offset_x">-24dp</dimen>
-
-    <!-- TODO: This can be calculated using other resource values -->
-    <dimen name="all_apps_search_box_full_height">90dp</dimen>
-
     <!-- Launcher app transition -->
-    <dimen name="content_trans_y">25dp</dimen>
-    <dimen name="workspace_trans_y">80dp</dimen>
+    <dimen name="content_trans_y">50dp</dimen>
+    <dimen name="workspace_trans_y">50dp</dimen>
+    <dimen name="closing_window_trans_y">115dp</dimen>
+
+    <dimen name="recents_empty_message_text_size">16sp</dimen>
+    <dimen name="recents_empty_message_text_padding">16dp</dimen>
+
+    <!-- Total space (start + end) between the task card and the edge of the screen
+         in various configurations -->
+    <dimen name="task_card_vert_space">40dp</dimen>
+    <dimen name="task_card_menu_option_vertical_padding">8dp</dimen>
+    <dimen name="task_card_menu_shadow_height">3dp</dimen>
+    <dimen name="task_card_menu_horizontal_padding">0dp</dimen>
+    <dimen name="portrait_task_card_horz_space">136dp</dimen>
+    <dimen name="landscape_task_card_horz_space">200dp</dimen>
+    <dimen name="multi_window_task_card_horz_space">100dp</dimen>
+    <!-- Copied from framework resource:
+       docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
+    <dimen name="multi_window_task_divider_size">10dp</dimen>
+
+    <dimen name="shelf_surface_radius">16dp</dimen>
+    <!-- same as vertical_drag_handle_size -->
+    <dimen name="shelf_surface_offset">24dp</dimen>
 </resources>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index ba99d81..d683659 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -16,5 +16,9 @@
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
   <string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>
+
+  <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
+
+  <string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
 </resources>
 
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index ec8eb52..a76899d 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -27,6 +27,18 @@
     <!-- Title for an option to keep an app pinned to the screen until it is unpinned -->
     <string name="recent_task_option_pin">Pin</string>
 
-    <!-- Text that shows above the navigation bar after launching a few apps -->
-    <string name="recents_swipe_up_onboarding">Swipe up from the bottom to switch apps</string>
+    <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_recent_apps">Overview</string>
+
+    <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
+    <string name="recents_empty_message">No recent items</string>
+
+    <!-- Content description for the recent apps's accessibility option that closes it. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_close_task">Close</string>
+
+    <!-- Recents: Title of a button that clears the task list, i.e. closes all tasks. [CHAR LIMIT=30] -->
+    <string name="recents_clear_all">Clear all</string>
+
+    <!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] -->
+    <string name="accessibility_recent_apps">Recent apps</string>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
new file mode 100644
index 0000000..bb364ff
--- /dev/null
+++ b/quickstep/res/values/styles.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 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>
+    <!-- Task Menu layout styles. -->
+    <style name="TaskMenu">
+        <item name="android:orientation">vertical</item>
+    </style>
+
+    <!-- Task Menu Option layout styles. -->
+    <style name="TaskMenu.Option">
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/xml/indexable_launcher_prefs.xml b/quickstep/res/xml/indexable_launcher_prefs.xml
new file mode 100644
index 0000000..30f3100
--- /dev/null
+++ b/quickstep/res/xml/indexable_launcher_prefs.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 Google Inc.
+
+     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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <SwitchPreference
+        android:key="pref_add_icon_to_home"
+        android:title="@string/auto_add_shortcuts_label"
+        android:summary="@string/auto_add_shortcuts_description"
+        android:defaultValue="true"  />
+
+    <SwitchPreference
+        android:key="pref_allowRotation"
+        android:title="@string/allow_rotation_title"
+        android:summary="@string/allow_rotation_desc"
+        android:defaultValue="@bool/allow_rotation"
+        android:persistent="true" />
+
+    <ListPreference
+        android:key="pref_override_icon_shape"
+        android:title="@string/icon_shape_override_label"
+        android:summary="@string/icon_shape_override_label_location"
+        android:entries="@array/icon_shape_override_paths_names"
+        android:entryValues="@array/icon_shape_override_paths_values"
+        android:defaultValue=""
+        android:persistent="false" />
+
+</PreferenceScreen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 872e6ca..e346310 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -15,27 +15,125 @@
  */
 package com.android.launcher3;
 
-import android.animation.AnimatorSet;
-
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
-
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.BinderThread;
+import android.support.annotation.UiThread;
+
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+@TargetApi(Build.VERSION_CODES.P)
 public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
 
-    AnimatorSet mAnimator;
-    private Launcher mLauncher;
+    private final Handler mHandler;
+    private final boolean mStartAtFrontOfQueue;
+    private AnimationResult mAnimationResult;
 
-    LauncherAnimationRunner(Launcher launcher) {
-        mLauncher = launcher;
+    /**
+     * @param startAtFrontOfQueue If true, the animation start will be posted at the front of the
+     *                            queue to minimize latency.
+     */
+    public LauncherAnimationRunner(Handler handler, boolean startAtFrontOfQueue) {
+        mHandler = handler;
+        mStartAtFrontOfQueue = startAtFrontOfQueue;
     }
 
+    @BinderThread
+    @Override
+    public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats, Runnable runnable) {
+        Runnable r = () -> {
+            finishExistingAnimation();
+            mAnimationResult = new AnimationResult(runnable);
+            onCreateAnimation(targetCompats, mAnimationResult);
+        };
+        if (mStartAtFrontOfQueue) {
+            postAtFrontOfQueueAsynchronously(mHandler, r);
+        } else {
+            postAsyncCallback(mHandler, r);
+        }
+    }
+
+    /**
+     * Called on the UI thread when the animation targets are received. The implementation must
+     * call {@link AnimationResult#setAnimation(AnimatorSet)} with the target animation to be run.
+     */
+    @UiThread
+    public abstract void onCreateAnimation(
+            RemoteAnimationTargetCompat[] targetCompats, AnimationResult result);
+
+    @UiThread
+    private void finishExistingAnimation() {
+        if (mAnimationResult != null) {
+            mAnimationResult.finish();
+            mAnimationResult = null;
+        }
+    }
+
+    /**
+     * Called by the system
+     */
+    @BinderThread
     @Override
     public void onAnimationCancelled() {
-        postAtFrontOfQueueAsynchronously(mLauncher.getWindow().getDecorView().getHandler(), () -> {
-            if (mAnimator != null) {
-                mAnimator.cancel();
+        postAsyncCallback(mHandler, this::finishExistingAnimation);
+    }
+
+    public static final class AnimationResult {
+
+        private final Runnable mFinishRunnable;
+
+        private AnimatorSet mAnimator;
+        private boolean mFinished = false;
+        private boolean mInitialized = false;
+
+        private AnimationResult(Runnable finishRunnable) {
+            mFinishRunnable = finishRunnable;
+        }
+
+        @UiThread
+        private void finish() {
+            if (!mFinished) {
+                mFinishRunnable.run();
+                mFinished = true;
             }
-        });
+        }
+
+        @UiThread
+        public void setAnimation(AnimatorSet animation) {
+            if (mInitialized) {
+                throw new IllegalStateException("Animation already initialized");
+            }
+            mInitialized = true;
+            mAnimator = animation;
+            if (mAnimator == null) {
+                finish();
+            } else if (mFinished) {
+                // Animation callback was already finished, skip the animation.
+                mAnimator.start();
+                mAnimator.end();
+            } else {
+                // Start the animation
+                mAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        finish();
+                    }
+                });
+                mAnimator.start();
+
+                // Because t=0 has the app icon in its original spot, we can skip the
+                // first frame and have the same movement one frame earlier.
+                mAnimator.setCurrentPlayTime(SINGLE_FRAME_MS);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 549c65e..37d0b12 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,10 +16,24 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
+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.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
-import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
-import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
+import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
+import static com.android.quickstep.TaskUtils.findTaskViewToLaunch;
+import static com.android.quickstep.TaskUtils.getRecentsWindowAnimator;
+import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
 import android.animation.Animator;
@@ -28,37 +42,45 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
-import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.Handler;
-import android.util.Log;
-import android.view.Surface;
+import android.os.Looper;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.Interpolator;
 
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.graphics.DrawableFactory;
-import com.android.quickstep.RecentsAnimationInterpolator;
-import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TaskView;
+import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.system.ActivityCompat;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
 /**
@@ -70,41 +92,75 @@
         implements OnDeviceProfileChangeListener {
 
     private static final String TAG = "LauncherTransition";
-    private static final int REFRESH_RATE_MS = 16;
+
+    /** Duration of status bar animations. */
+    public static final int STATUS_BAR_TRANSITION_DURATION = 120;
+
+    /**
+     * Since our animations decelerate heavily when finishing, we want to start status bar animations
+     * x ms before the ending.
+     */
+    public static final int STATUS_BAR_TRANSITION_PRE_DELAY = 96;
 
     private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
             "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
 
-    private static final int RECENTS_LAUNCH_DURATION = 336;
-    private static final int LAUNCHER_RESUME_START_DELAY = 150;
-    private static final int CLOSING_TRANSITION_DURATION_MS = 350;
+    private static final int APP_LAUNCH_DURATION = 500;
+    // Use a shorter duration for x or y translation to create a curve effect
+    private static final int APP_LAUNCH_CURVED_DURATION = APP_LAUNCH_DURATION / 2;
+    // We scale the durations for the downward app launch animations (minus the scale animation).
+    private static final float APP_LAUNCH_DOWN_DUR_SCALE_FACTOR = 0.8f;
+    private static final int APP_LAUNCH_ALPHA_START_DELAY = 32;
+    private static final int APP_LAUNCH_ALPHA_DURATION = 50;
+
+    public static final int RECENTS_LAUNCH_DURATION = 336;
+    public static final int RECENTS_QUICKSCRUB_LAUNCH_DURATION = 300;
+    private static final int LAUNCHER_RESUME_START_DELAY = 100;
+    private static final int CLOSING_TRANSITION_DURATION_MS = 250;
 
     // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
-    private static final float ALL_APPS_PROGRESS_START = 1.3059858f;
-    private static final float ALL_APPS_PROGRESS_SLIDE_END = 0.99581414f;
+    public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
 
-    private final DragLayer mDragLayer;
     private final Launcher mLauncher;
-    private DeviceProfile mDeviceProfile;
+    private final DragLayer mDragLayer;
+    private final AlphaProperty mDragLayerAlpha;
+
+    private final Handler mHandler;
+    private final boolean mIsRtl;
 
     private final float mContentTransY;
     private final float mWorkspaceTransY;
+    private final float mClosingWindowTransY;
 
+    private DeviceProfile mDeviceProfile;
     private View mFloatingView;
-    private boolean mIsRtl;
 
-    private LauncherTransitionAnimator mCurrentAnimator;
+    private RemoteAnimationProvider mRemoteAnimationProvider;
+
+    private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mLauncher.addForceInvisibleFlag(INVISIBLE_BY_APP_TRANSITIONS);
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mLauncher.clearForceInvisibleFlag(INVISIBLE_BY_APP_TRANSITIONS);
+        }
+    };
 
     public LauncherAppTransitionManagerImpl(Context context) {
         mLauncher = Launcher.getLauncher(context);
         mDragLayer = mLauncher.getDragLayer();
-        mDeviceProfile = mLauncher.getDeviceProfile();
-
+        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);
         mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
+        mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
 
         mLauncher.addOnDeviceProfileChangeListener(this);
         registerRemoteAnimations();
@@ -115,277 +171,259 @@
         mDeviceProfile = dp;
     }
 
-    private void setCurrentAnimator(LauncherTransitionAnimator animator) {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
-            mCurrentAnimator.cancel();
-        }
-        mCurrentAnimator = animator;
-    }
-
-    @Override
-    public void finishLauncherAnimation() {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
-            mCurrentAnimator.finishLauncherAnimation();
-        }
-        mCurrentAnimator = null;
-    }
-
     /**
-     * @return A Bundle with remote animations that controls how the window of the opening
+     * @return ActivityOptions with remote animations that controls how the window of the opening
      *         targets are displayed.
      */
     @Override
-    public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         if (hasControlRemoteAppTransitionPermission()) {
-            try {
-                RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mLauncher) {
-                    @Override
-                    public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
-                                                 Runnable finishedCallback) {
-                        // Post at front of queue ignoring sync barriers to make sure it gets
-                        // processed before the next frame.
-                        postAtFrontOfQueueAsynchronously(v.getHandler(), () -> {
-                            final boolean removeTrackingView;
-                            LauncherTransitionAnimator animator =
-                                    composeRecentsLaunchAnimator(v, targets);
-                            if (animator != null) {
-                                // We are animating the task view directly, do not remove it after
-                                removeTrackingView = false;
-                            } else {
-                                animator = composeAppLaunchAnimator(v, targets);
-                                // A new floating view is created for the animation, remove it after
-                                removeTrackingView = true;
-                            }
+            RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler,
+                    true /* startAtFrontOfQueue */) {
 
-                            setCurrentAnimator(animator);
-                            mAnimator = animator.getAnimatorSet();
-                            mAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
+                        AnimationResult result) {
+                    AnimatorSet anim = new AnimatorSet();
+
+                    boolean launcherClosing =
+                            launcherIsATargetWithMode(targetCompats, MODE_CLOSING);
+
+                    if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) {
+                        // Set the state animation first so that any state listeners are called
+                        // before our internal listeners.
+                        mLauncher.getStateManager().setCurrentAnimation(anim);
+
+                        Rect windowTargetBounds = getWindowTargetBounds(targetCompats);
+                        playIconAnimators(anim, v, windowTargetBounds);
+                        if (launcherClosing) {
+                            Pair<AnimatorSet, Runnable> launcherContentAnimator =
+                                    getLauncherContentAnimator(true /* isAppOpening */);
+                            anim.play(launcherContentAnimator.first);
+                            anim.addListener(new AnimatorListenerAdapter() {
                                 @Override
                                 public void onAnimationEnd(Animator animation) {
-                                    // Reset launcher to normal state
-                                    v.setVisibility(View.VISIBLE);
-                                    if (removeTrackingView) {
-                                        ((ViewGroup) mDragLayer.getParent()).removeView(
-                                                mFloatingView);
-                                    }
-
-                                    mDragLayer.setAlpha(1f);
-                                    mDragLayer.setTranslationY(0f);
-
-                                    View appsView = mLauncher.getAppsView();
-                                    appsView.setAlpha(1f);
-                                    appsView.setTranslationY(0f);
-
-                                    finishedCallback.run();
+                                    launcherContentAnimator.second.run();
                                 }
                             });
-                            mAnimator.start();
-                            // Because t=0 has the app icon in its original spot, we can skip the
-                            // first frame and have the same movement one frame earlier.
-                            mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
-                        });
+                        }
+                        anim.play(getOpeningWindowAnimators(v, targetCompats, windowTargetBounds));
                     }
-                };
 
-                return ActivityOptionsCompat.makeRemoteAnimation(
-                        new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle();
-            } catch (NoClassDefFoundError e) {
-                // Gracefully fall back to default launch options if the user's platform doesn't
-                // have the latest changes.
+                    if (launcherClosing) {
+                        anim.addListener(mForceInvisibleListener);
+                    }
+
+                    result.setAnimation(anim);
+                }
+            };
+
+            boolean fromRecents = mLauncher.getStateManager().getState().overviewUi
+                    && findTaskViewToLaunch(launcher, v, null) != null;
+            int duration = fromRecents
+                    ? RECENTS_LAUNCH_DURATION
+                    : APP_LAUNCH_DURATION;
+
+            int statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
+                    - STATUS_BAR_TRANSITION_PRE_DELAY;
+            return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+                    runner, duration, statusBarTransitionDelay));
+        }
+        return super.getActivityLaunchOptions(launcher, v);
+    }
+
+    /**
+     * Return the window bounds of the opening target.
+     * In multiwindow mode, we need to get the final size of the opening app window target to help
+     * figure out where the floating view should animate to.
+     */
+    private Rect getWindowTargetBounds(RemoteAnimationTargetCompat[] targets) {
+        Rect bounds = new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx);
+        if (mLauncher.isInMultiWindowModeCompat()) {
+            for (RemoteAnimationTargetCompat target : targets) {
+                if (target.mode == MODE_OPENING) {
+                    bounds.set(target.sourceContainerBounds);
+                    bounds.offsetTo(target.position.x, target.position.y);
+                    return bounds;
+                }
             }
         }
-        return getDefaultActivityLaunchOptions(launcher, v);
+        return bounds;
+    }
+
+    public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider,
+            CancellationSignal cancellationSignal) {
+        mRemoteAnimationProvider = animationProvider;
+        cancellationSignal.setOnCancelListener(() -> {
+            if (animationProvider == mRemoteAnimationProvider) {
+                mRemoteAnimationProvider = null;
+            }
+        });
     }
 
     /**
      * Composes the animations for a launch from the recents list if possible.
      */
-    private LauncherTransitionAnimator composeRecentsLaunchAnimator(View v,
-            RemoteAnimationTargetCompat[] targets) {
+    private boolean composeRecentsLaunchAnimator(View v,
+            RemoteAnimationTargetCompat[] targets, AnimatorSet target) {
         // Ensure recents is actually visible
-        if (!mLauncher.isInState(LauncherState.OVERVIEW)) {
-            return null;
+        if (!mLauncher.getStateManager().getState().overviewUi) {
+            return false;
         }
 
-        // Resolve the opening task id
-        int openingTaskId = -1;
-        for (RemoteAnimationTargetCompat target : targets) {
-            if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
-                openingTaskId = target.taskId;
-                break;
-            }
-        }
-
-        // If there is no opening task id, fall back to the normal app icon launch animation
-        if (openingTaskId == -1) {
-            return null;
-        }
-
-        // If the opening task id is not currently visible in overview, then fall back to normal app
-        // icon launch animation
         RecentsView recentsView = mLauncher.getOverviewPanel();
-        TaskView taskView = recentsView.getTaskView(openingTaskId);
-        if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
-            return null;
+        boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING);
+        boolean skipLauncherChanges = !launcherClosing;
+        boolean isLaunchingFromQuickscrub =
+                recentsView.getQuickScrubController().isWaitingForTaskLaunch();
+
+        TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets);
+        if (taskView == null) {
+            return false;
         }
 
+        int duration = isLaunchingFromQuickscrub
+                ? RECENTS_QUICKSCRUB_LAUNCH_DURATION
+                : RECENTS_LAUNCH_DURATION;
+
+        ClipAnimationHelper helper = new ClipAnimationHelper();
+        target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper)
+                .setDuration(duration));
+
+        Animator childStateAnimation = null;
         // Found a visible recents task that matches the opening app, lets launch the app from there
-        return new LauncherTransitionAnimator(null, getRecentsWindowAnimator(taskView, targets));
-    }
+        Animator launcherAnim;
+        final AnimatorListenerAdapter windowAnimEndListener;
+        if (launcherClosing) {
+            launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView, helper);
+            launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+            launcherAnim.setDuration(duration);
 
-    /**
-     * @return Animator that controls the window of the opening targets for the recents launch
-     * animation.
-     */
-    private ValueAnimator getRecentsWindowAnimator(TaskView v,
-            RemoteAnimationTargetCompat[] targets) {
-        Rect taskViewBounds = new Rect();
-        mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
-
-        // TODO: Use the actual target insets instead of the current thumbnail insets in case the
-        // device state has changed
-        RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator(
-                new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
-                v.getThumbnail().getInsets(),
-                taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0));
-
-        Rect crop = new Rect();
-        Matrix matrix = new Matrix();
-
-        ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
-        appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
-        appAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
-        appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            boolean isFirstFrame = true;
-
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final Surface surface = getSurface(v);
-                final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1;
-                if (frameNumber == -1) {
-                    // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
-                    Log.w(TAG, "Failed to animate, surface got destroyed.");
-                    return;
+            // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+            windowAnimEndListener = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mLauncher.getStateManager().moveToRestState();
+                    mLauncher.getStateManager().reapplyState();
                 }
-                final float percent = animation.getAnimatedFraction();
-                TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
-
-                v.setScaleX(tw.taskScale);
-                v.setScaleY(tw.taskScale);
-                v.setTranslationX(tw.taskX);
-                v.setTranslationY(tw.taskY);
-                // Defer fading out the view until after the app window gets faded in
-                v.setAlpha(getValue(1f, 0f, 75, 75,
-                        appAnimator.getDuration() * percent, Interpolators.LINEAR));
-
-                matrix.setScale(tw.winScale, tw.winScale);
-                matrix.postTranslate(tw.winX, tw.winY);
-                crop.set(tw.winCrop);
-
-                // Fade in the app window.
-                float alphaDelay = 0;
-                float alphaDuration = 75;
-                float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
-                        appAnimator.getDuration() * percent, Interpolators.LINEAR);
-
-                TransactionCompat t = new TransactionCompat();
-                for (RemoteAnimationTargetCompat target : targets) {
-                    if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
-                        t.setAlpha(target.leash, alpha);
-
-                        // TODO: This isn't correct at the beginning of the animation, but better
-                        // than nothing.
-                        matrix.postTranslate(target.position.x, target.position.y);
-                        t.setMatrix(target.leash, matrix);
-                        t.setWindowCrop(target.leash, crop);
-                        t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
-                    }
-                    if (isFirstFrame) {
-                        t.show(target.leash);
-                    }
+            };
+        } else {
+            AnimatorPlaybackController controller =
+                    mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL, duration);
+            controller.dispatchOnStart();
+            childStateAnimation = controller.getTarget();
+            launcherAnim = controller.getAnimationPlayer().setDuration(duration);
+            windowAnimEndListener = new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mLauncher.getStateManager().goToState(NORMAL, false);
                 }
-                t.apply();
+            };
+        }
+        target.play(launcherAnim);
 
-                matrix.reset();
-                isFirstFrame = false;
-            }
-        });
-        return appAnimator;
-    }
-
-    /**
-     * Composes the animations for a launch from an app icon.
-     */
-    private LauncherTransitionAnimator composeAppLaunchAnimator(View v,
-            RemoteAnimationTargetCompat[] targets) {
-        return new LauncherTransitionAnimator(getLauncherAnimators(v),
-                getWindowAnimators(v, targets));
-    }
-
-    /**
-     * @return Animators that control the movements of the Launcher and icon of the opening target.
-     */
-    private AnimatorSet getLauncherAnimators(View v) {
-        AnimatorSet launcherAnimators = new AnimatorSet();
-        launcherAnimators.play(getLauncherContentAnimator(false /* show */));
-        launcherAnimators.play(getIconAnimator(v));
-        return launcherAnimators;
+        // Set the current animation first, before adding windowAnimEndListener. Setting current
+        // animation adds some listeners which need to be called before windowAnimEndListener
+        // (the ordering of listeners matter in this case).
+        mLauncher.getStateManager().setCurrentAnimation(target, childStateAnimation);
+        target.addListener(windowAnimEndListener);
+        return true;
     }
 
     /**
      * Content is everything on screen except the background and the floating view (if any).
      *
-     * @param show If true: Animate the content so that it moves upwards and fades in.
-     *             Else: Animate the content so that it moves downwards and fades out.
+     * @param isAppOpening True when this is called when an app is opening.
+     *                     False when this is called when an app is closing.
      */
-    private AnimatorSet getLauncherContentAnimator(boolean show) {
+    private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening) {
         AnimatorSet launcherAnimator = new AnimatorSet();
+        Runnable endListener;
 
-        float[] alphas = show
-                ? new float[] {0, 1}
-                : new float[] {1, 0};
-        float[] trans = show
-                ? new float[] {mContentTransY, 0,}
-                : new float[] {0, mContentTransY};
+        float[] alphas = isAppOpening
+                ? new float[] {1, 0}
+                : new float[] {0, 1};
+        float[] trans = isAppOpening
+                ? new float[] {0, mContentTransY}
+                : new float[] {-mContentTransY, 0};
 
-        if (mLauncher.isInState(LauncherState.ALL_APPS) && !mDeviceProfile.isVerticalBarLayout()) {
+        if (mLauncher.isInState(ALL_APPS)) {
             // All Apps in portrait mode is full screen, so we only animate AllAppsContainerView.
-            View appsView = mLauncher.getAppsView();
+            final View appsView = mLauncher.getAppsView();
+            final float startAlpha = appsView.getAlpha();
+            final float startY = appsView.getTranslationY();
             appsView.setAlpha(alphas[0]);
             appsView.setTranslationY(trans[0]);
 
             ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas);
             alpha.setDuration(217);
-            alpha.setInterpolator(Interpolators.LINEAR);
+            alpha.setInterpolator(LINEAR);
+            appsView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            alpha.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    appsView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            });
             ObjectAnimator transY = ObjectAnimator.ofFloat(appsView, View.TRANSLATION_Y, trans);
-            transY.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+            transY.setInterpolator(AGGRESSIVE_EASE);
             transY.setDuration(350);
 
             launcherAnimator.play(alpha);
             launcherAnimator.play(transY);
+
+            endListener = () -> {
+                appsView.setAlpha(startAlpha);
+                appsView.setTranslationY(startY);
+                appsView.setLayerType(View.LAYER_TYPE_NONE, null);
+            };
+        } else if (mLauncher.isInState(OVERVIEW)) {
+            AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
+            launcherAnimator.play(ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS,
+                    allAppsController.getProgress(), ALL_APPS_PROGRESS_OFF_SCREEN));
+
+            RecentsView overview = mLauncher.getOverviewPanel();
+            ObjectAnimator alpha = ObjectAnimator.ofFloat(overview,
+                    RecentsView.CONTENT_ALPHA, alphas);
+            alpha.setDuration(217);
+            alpha.setInterpolator(LINEAR);
+            launcherAnimator.play(alpha);
+
+            ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans);
+            transY.setInterpolator(AGGRESSIVE_EASE);
+            transY.setDuration(350);
+            launcherAnimator.play(transY);
+
+            endListener = mLauncher.getStateManager()::reapplyState;
         } else {
-            mDragLayer.setAlpha(alphas[0]);
+            mDragLayerAlpha.setValue(alphas[0]);
+            ObjectAnimator alpha =
+                    ObjectAnimator.ofFloat(mDragLayerAlpha, MultiValueAlpha.VALUE, alphas);
+            alpha.setDuration(217);
+            alpha.setInterpolator(LINEAR);
+            launcherAnimator.play(alpha);
+
             mDragLayer.setTranslationY(trans[0]);
+            ObjectAnimator transY = ObjectAnimator.ofFloat(mDragLayer, View.TRANSLATION_Y, trans);
+            transY.setInterpolator(AGGRESSIVE_EASE);
+            transY.setDuration(350);
+            launcherAnimator.play(transY);
 
-            ObjectAnimator dragLayerAlpha = ObjectAnimator.ofFloat(mDragLayer, View.ALPHA, alphas);
-            dragLayerAlpha.setDuration(217);
-            dragLayerAlpha.setInterpolator(Interpolators.LINEAR);
-            ObjectAnimator dragLayerTransY = ObjectAnimator.ofFloat(mDragLayer, View.TRANSLATION_Y,
-                    trans);
-            dragLayerTransY.setInterpolator(Interpolators.AGGRESSIVE_EASE);
-            dragLayerTransY.setDuration(350);
+            mDragLayer.getScrim().hideSysUiScrim(true);
+            // Pause page indicator animations as they lead to layer trashing.
+            mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
+            mDragLayer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
 
-            launcherAnimator.play(dragLayerAlpha);
-            launcherAnimator.play(dragLayerTransY);
+            endListener = this::resetContentView;
         }
-        return launcherAnimator;
+        return new Pair<>(launcherAnimator, endListener);
     }
 
     /**
-     * @return Animator that controls the icon used to launch the target.
+     * Animators for the "floating view" of the view used to launch the target.
      */
-    private AnimatorSet getIconAnimator(View v) {
-        boolean isBubbleTextView = v instanceof BubbleTextView;
+    private void playIconAnimators(AnimatorSet appOpenAnimator, View v, Rect windowTargetBounds) {
+        final boolean isBubbleTextView = v instanceof BubbleTextView;
         mFloatingView = new View(mLauncher);
         if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
             // Create a copy of the app icon
@@ -395,32 +433,59 @@
 
         // Position the floating view exactly on top of the original
         Rect rect = new Rect();
-        mDragLayer.getDescendantRectRelativeToSelf(v, rect);
-        int viewLocationStart = mIsRtl
-                ? mDeviceProfile.widthPx - rect.right
-                : rect.left;
+        final boolean fromDeepShortcutView = v.getParent() instanceof DeepShortcutView;
+        if (fromDeepShortcutView) {
+            // Deep shortcut views have their icon drawn in a separate view.
+            DeepShortcutView view = (DeepShortcutView) v.getParent();
+            mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect);
+        } else {
+            mDragLayer.getDescendantRectRelativeToSelf(v, rect);
+        }
+        int viewLocationLeft = rect.left;
         int viewLocationTop = rect.top;
 
-        if (isBubbleTextView) {
-            ((BubbleTextView) v).getIconBounds(rect);
+        float startScale = 1f;
+        if (isBubbleTextView && !fromDeepShortcutView) {
+            BubbleTextView btv = (BubbleTextView) v;
+            btv.getIconBounds(rect);
+            Drawable dr = btv.getIcon();
+            if (dr instanceof FastBitmapDrawable) {
+                startScale = ((FastBitmapDrawable) dr).getAnimatedScale();
+            }
+        } else {
+            rect.set(0, 0, rect.width(), rect.height());
         }
+        viewLocationLeft += rect.left;
+        viewLocationTop += rect.top;
+        int viewLocationStart = mIsRtl
+                ? windowTargetBounds.width() - rect.right
+                : viewLocationLeft;
         LayoutParams lp = new LayoutParams(rect.width(), rect.height());
         lp.ignoreInsets = true;
-        lp.setMarginStart(viewLocationStart + rect.left);
-        lp.topMargin = viewLocationTop + rect.top;
+        lp.setMarginStart(viewLocationStart);
+        lp.topMargin = viewLocationTop;
         mFloatingView.setLayoutParams(lp);
 
+        // Set the properties here already to make sure they'are available when running the first
+        // animation frame.
+        mFloatingView.setLeft(viewLocationLeft);
+        mFloatingView.setTop(viewLocationTop);
+        mFloatingView.setRight(viewLocationLeft + rect.width());
+        mFloatingView.setBottom(viewLocationTop + rect.height());
+
         // Swap the two views in place.
         ((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
         v.setVisibility(View.INVISIBLE);
 
-        AnimatorSet appIconAnimatorSet = new AnimatorSet();
-        // Animate the app icon to the center
-        float centerX = mDeviceProfile.widthPx / 2;
-        float centerY = mDeviceProfile.heightPx / 2;
+        int[] dragLayerBounds = new int[2];
+        mDragLayer.getLocationOnScreen(dragLayerBounds);
+
+        // Animate the app icon to the center of the window bounds in screen coordinates.
+        float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
+        float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
 
         float xPosition = mIsRtl
-                ? mDeviceProfile.widthPx - lp.getMarginStart() - rect.width()
+                ? windowTargetBounds.width() - lp.getMarginStart() - rect.width()
                 : lp.getMarginStart();
         float dX = centerX - xPosition - (lp.width / 2);
         float dY = centerY - lp.topMargin - (lp.height / 2);
@@ -428,43 +493,70 @@
         ObjectAnimator x = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_X, 0f, dX);
         ObjectAnimator y = ObjectAnimator.ofFloat(mFloatingView, View.TRANSLATION_Y, 0f, dY);
 
-        // Adjust the duration to change the "curve" of the app icon to the center.
-        boolean isBelowCenterY = lp.topMargin < centerY;
-        x.setDuration(isBelowCenterY ? 500 : 233);
-        y.setDuration(isBelowCenterY ? 233 : 500);
-        appIconAnimatorSet.play(x);
-        appIconAnimatorSet.play(y);
+        // Use upward animation for apps that are either on the bottom half of the screen, or are
+        // relatively close to the center.
+        boolean useUpwardAnimation = lp.topMargin > centerY
+                || Math.abs(dY) < mLauncher.getDeviceProfile().cellHeightPx;
+        if (useUpwardAnimation) {
+            x.setDuration(APP_LAUNCH_CURVED_DURATION);
+            y.setDuration(APP_LAUNCH_DURATION);
+        } else {
+            x.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_DURATION));
+            y.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_CURVED_DURATION));
+        }
+        x.setInterpolator(AGGRESSIVE_EASE);
+        y.setInterpolator(AGGRESSIVE_EASE);
+        appOpenAnimator.play(x);
+        appOpenAnimator.play(y);
 
         // Scale the app icon to take up the entire screen. This simplifies the math when
         // animating the app window position / scale.
-        float maxScaleX = mDeviceProfile.widthPx / (float) rect.width();
-        float maxScaleY = mDeviceProfile.heightPx / (float) rect.height();
+        float maxScaleX = windowTargetBounds.width() / (float) rect.width();
+        float maxScaleY = windowTargetBounds.height() / (float) rect.height();
         float scale = Math.max(maxScaleX, maxScaleY);
-        ObjectAnimator sX = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_X, 1f, scale);
-        ObjectAnimator sY = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_Y, 1f, scale);
-        sX.setDuration(500);
-        sY.setDuration(500);
-        appIconAnimatorSet.play(sX);
-        appIconAnimatorSet.play(sY);
+        ObjectAnimator scaleAnim = ObjectAnimator
+                .ofFloat(mFloatingView, SCALE_PROPERTY, startScale, scale);
+        scaleAnim.setDuration(APP_LAUNCH_DURATION)
+                .setInterpolator(Interpolators.EXAGGERATED_EASE);
+        appOpenAnimator.play(scaleAnim);
 
         // Fade out the app icon.
         ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
-        alpha.setStartDelay(17);
-        alpha.setDuration(33);
-        appIconAnimatorSet.play(alpha);
-
-        for (Animator a : appIconAnimatorSet.getChildAnimations()) {
-            a.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+        if (useUpwardAnimation) {
+            alpha.setStartDelay(APP_LAUNCH_ALPHA_START_DELAY);
+            alpha.setDuration(APP_LAUNCH_ALPHA_DURATION);
+        } else {
+            alpha.setStartDelay((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR
+                    * APP_LAUNCH_ALPHA_START_DELAY));
+            alpha.setDuration((long) (APP_LAUNCH_DOWN_DUR_SCALE_FACTOR * APP_LAUNCH_ALPHA_DURATION));
         }
-        return appIconAnimatorSet;
+        alpha.setInterpolator(LINEAR);
+        appOpenAnimator.play(alpha);
+
+        appOpenAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Reset launcher to normal state
+                if (isBubbleTextView) {
+                    ((BubbleTextView) v).setStayPressed(false);
+                }
+                v.setVisibility(View.VISIBLE);
+                ((ViewGroup) mDragLayer.getParent()).removeView(mFloatingView);
+            }
+        });
     }
 
     /**
      * @return Animator that controls the window of the opening targets.
      */
-    private ValueAnimator getWindowAnimators(View v, RemoteAnimationTargetCompat[] targets) {
+    private ValueAnimator getOpeningWindowAnimators(View v, RemoteAnimationTargetCompat[] targets,
+            Rect windowTargetBounds) {
         Rect bounds = new Rect();
-        if (v instanceof BubbleTextView) {
+        if (v.getParent() instanceof DeepShortcutView) {
+            // Deep shortcut views have their icon drawn in a separate view.
+            DeepShortcutView view = (DeepShortcutView) v.getParent();
+            mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), bounds);
+        } else if (v instanceof BubbleTextView) {
             ((BubbleTextView) v).getIconBounds(bounds);
         } else {
             mDragLayer.getDescendantRectRelativeToSelf(v, bounds);
@@ -474,81 +566,75 @@
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
 
+        RemoteAnimationTargetSet openingTargets = new RemoteAnimationTargetSet(targets,
+                MODE_OPENING);
+        RemoteAnimationTargetSet closingTargets = new RemoteAnimationTargetSet(targets,
+                MODE_CLOSING);
+        SyncRtSurfaceTransactionApplier surfaceApplier = new SyncRtSurfaceTransactionApplier(
+                mFloatingView);
+
         ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
-        appAnimator.setDuration(500);
-        appAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            boolean isFirstFrame = true;
+        appAnimator.setDuration(APP_LAUNCH_DURATION);
+        appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+            // Fade alpha for the app window.
+            FloatProp mAlpha = new FloatProp(0f, 1f, 0, 60, LINEAR);
 
             @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final Surface surface = getSurface(mFloatingView);
-                final long frameNumber = surface != null ? getNextFrameNumber(surface) : -1;
-                if (frameNumber == -1) {
-                    // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
-                    Log.w(TAG, "Failed to animate, surface got destroyed.");
-                    return;
-                }
-                final float percent = animation.getAnimatedFraction();
-                final float easePercent = Interpolators.AGGRESSIVE_EASE.getInterpolation(percent);
+            public void onUpdate(float percent) {
+                final float easePercent = AGGRESSIVE_EASE.getInterpolation(percent);
 
                 // Calculate app icon size.
                 float iconWidth = bounds.width() * mFloatingView.getScaleX();
                 float iconHeight = bounds.height() * mFloatingView.getScaleY();
 
                 // Scale the app window to match the icon size.
-                float scaleX = iconWidth / mDeviceProfile.widthPx;
-                float scaleY = iconHeight / mDeviceProfile.heightPx;
+                float scaleX = iconWidth / windowTargetBounds.width();
+                float scaleY = iconHeight / windowTargetBounds.height();
                 float scale = Math.min(1f, Math.min(scaleX, scaleY));
-                matrix.setScale(scale, scale);
 
                 // Position the scaled window on top of the icon
-                int deviceWidth = mDeviceProfile.widthPx;
-                int deviceHeight = mDeviceProfile.heightPx;
-                float scaledWindowWidth = deviceWidth * scale;
-                float scaledWindowHeight = deviceHeight * scale;
+                int windowWidth = windowTargetBounds.width();
+                int windowHeight = windowTargetBounds.height();
+                float scaledWindowWidth = windowWidth * scale;
+                float scaledWindowHeight = windowHeight * scale;
 
                 float offsetX = (scaledWindowWidth - iconWidth) / 2;
                 float offsetY = (scaledWindowHeight - iconHeight) / 2;
-                mFloatingView.getLocationInWindow(floatingViewBounds);
+                mFloatingView.getLocationOnScreen(floatingViewBounds);
+
                 float transX0 = floatingViewBounds[0] - offsetX;
                 float transY0 = floatingViewBounds[1] - offsetY;
-                matrix.postTranslate(transX0, transY0);
-
-                // Fade in the app window.
-                float alphaDelay = 0;
-                float alphaDuration = 50;
-                float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
-                        appAnimator.getDuration() * percent, Interpolators.AGGRESSIVE_EASE);
 
                 // Animate the window crop so that it starts off as a square, and then reveals
                 // horizontally.
-                float cropHeight = deviceHeight * easePercent + deviceWidth * (1 - easePercent);
-                float initialTop = (deviceHeight - deviceWidth) / 2f;
+                float cropHeight = windowHeight * easePercent + windowWidth * (1 - easePercent);
+                float initialTop = (windowHeight - windowWidth) / 2f;
                 crop.left = 0;
                 crop.top = (int) (initialTop * (1 - easePercent));
-                crop.right = deviceWidth;
+                crop.right = windowWidth;
                 crop.bottom = (int) (crop.top + cropHeight);
 
-                TransactionCompat t = new TransactionCompat();
-                for (RemoteAnimationTargetCompat target : targets) {
+                SurfaceParams[] params = new SurfaceParams[targets.length];
+                for (int i = targets.length - 1; i >= 0; i--) {
+                    RemoteAnimationTargetCompat target = targets[i];
+
+                    Rect targetCrop;
+                    float alpha;
                     if (target.mode == MODE_OPENING) {
-                        t.setAlpha(target.leash, alpha);
+                        matrix.setScale(scale, scale);
+                        matrix.postTranslate(transX0, transY0);
+                        targetCrop = crop;
+                        alpha = mAlpha.value;
+                    } else {
+                        matrix.setTranslate(target.position.x, target.position.y);
+                        alpha = 1f;
+                        targetCrop = target.sourceContainerBounds;
+                    }
 
-                        // TODO: This isn't correct at the beginning of the animation, but better
-                        // than nothing.
-                        matrix.postTranslate(target.position.x, target.position.y);
-                        t.setMatrix(target.leash, matrix);
-                        t.setWindowCrop(target.leash, crop);
-                        t.deferTransactionUntil(target.leash, surface, getNextFrameNumber(surface));
-                    }
-                    if (isFirstFrame) {
-                        t.show(target.leash);
-                    }
+                    params[i] = new SurfaceParams(target.leash, alpha, matrix, targetCrop,
+                            RemoteAnimationProvider.getLayer(target, MODE_OPENING));
                 }
-                t.apply();
-
-                matrix.reset();
-                isFirstFrame = false;
+                surfaceApplier.scheduleApply(params);
             }
         });
         return appAnimator;
@@ -558,30 +644,21 @@
      * Registers remote animations used when closing apps to home screen.
      */
     private void registerRemoteAnimations() {
+        // Unregister this
         if (hasControlRemoteAppTransitionPermission()) {
-            try {
-                RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
-                definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
-                        new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
-                                CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+            RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
+            definition.addRemoteAnimation(WindowManagerWrapper.TRANSIT_WALLPAPER_OPEN,
+                    WindowManagerWrapper.ACTIVITY_TYPE_STANDARD,
+                    new RemoteAnimationAdapterCompat(getWallpaperOpenRunner(),
+                            CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
 
-//      TODO: App controlled transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
-
-                new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
-            } catch (NoClassDefFoundError e) {
-                // Gracefully fall back if the user's platform doesn't have the latest changes
-            }
+            // TODO: Transition for unlock to home TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER
+            new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
         }
     }
 
-    private boolean isLauncherInSetOfOpeningTargets(RemoteAnimationTargetCompat[] targets) {
-        int launcherTaskId = mLauncher.getTaskId();
-        for (RemoteAnimationTargetCompat target : targets) {
-            if (target.mode == MODE_OPENING && target.taskId == launcherTaskId) {
-                return true;
-            }
-        }
-        return false;
+    private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
+        return taskIsATargetWithMode(targets, mLauncher.getTaskId(), mode);
     }
 
     /**
@@ -589,40 +666,51 @@
      *         ie. pressing home, swiping up from nav bar.
      */
     private RemoteAnimationRunnerCompat getWallpaperOpenRunner() {
-        return new LauncherAnimationRunner(mLauncher) {
+        return new LauncherAnimationRunner(mHandler, false /* startAtFrontOfQueue */) {
             @Override
-            public void onAnimationStart(RemoteAnimationTargetCompat[] targets,
-                                         Runnable finishedCallback) {
-                Handler handler = mLauncher.getWindow().getDecorView().getHandler();
-                postAtFrontOfQueueAsynchronously(handler, () -> {
-                    if ((Utilities.getPrefs(mLauncher)
-                            .getBoolean("pref_use_screenshot_for_swipe_up", false)
-                            && mLauncher.isInState(LauncherState.OVERVIEW))
-                            || !isLauncherInSetOfOpeningTargets(targets)) {
-                        // We use a separate transition for Overview mode. And we can skip the
-                        // animation in cases where Launcher is not in the set of opening targets.
-                        // This can happen when Launcher is already visible. ie. Closing a dialog.
-                        setCurrentAnimator(null);
-                        finishedCallback.run();
-                        return;
+            public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
+                    AnimationResult result) {
+                if (!mLauncher.hasBeenResumed()) {
+                    // If launcher is not resumed, wait until new async-frame after resume
+                    mLauncher.setOnResumeCallback(() ->
+                            postAsyncCallback(mHandler, () ->
+                                    onCreateAnimation(targetCompats, result)));
+                    return;
+                }
+
+                if (mLauncher.hasSomeInvisibleFlag(PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION)) {
+                    mLauncher.addForceInvisibleFlag(INVISIBLE_BY_PENDING_FLAGS);
+                    mLauncher.getStateManager().moveToRestState();
+                }
+
+                AnimatorSet anim = null;
+                RemoteAnimationProvider provider = mRemoteAnimationProvider;
+                if (provider != null) {
+                    anim = provider.createWindowAnimation(targetCompats);
+                }
+
+                if (anim == null) {
+                    anim = new AnimatorSet();
+                    anim.play(getClosingWindowAnimators(targetCompats));
+
+                    // Normally, we run the launcher content animation when we are transitioning
+                    // home, but if home is already visible, then we don't want to animate the
+                    // contents of launcher unless we know that we are animating home as a result
+                    // of the home button press with quickstep, which will result in launcher being
+                    // started on touch down, prior to the animation home (and won't be in the
+                    // targets list because it is already visible). In that case, we force
+                    // invisibility on touch down, and only reset it after the animation to home
+                    // is initialized.
+                    if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)
+                            || mLauncher.isForceInvisible()) {
+                        // Only register the content animation for cancellation when state changes
+                        mLauncher.getStateManager().setCurrentAnimation(anim);
+                        createLauncherResumeAnimation(anim);
                     }
+                }
 
-                    LauncherTransitionAnimator animator = new LauncherTransitionAnimator(
-                            getLauncherResumeAnimation(), getClosingWindowAnimators(targets));
-                    setCurrentAnimator(animator);
-                    mAnimator = animator.getAnimatorSet();
-                    mAnimator.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            finishedCallback.run();
-                        }
-                    });
-                    mAnimator.start();
-
-                    // Because t=0 has the app icon in its original spot, we can skip the
-                    // first frame and have the same movement one frame earlier.
-                    mAnimator.setCurrentPlayTime(REFRESH_RATE_MS);
-                });
+                mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
+                result.setAnimation(anim);
             }
         };
     }
@@ -631,119 +719,101 @@
      * Animator that controls the transformations of the windows the targets that are closing.
      */
     private Animator getClosingWindowAnimators(RemoteAnimationTargetCompat[] targets) {
+        SyncRtSurfaceTransactionApplier surfaceApplier =
+                new SyncRtSurfaceTransactionApplier(mDragLayer);
         Matrix matrix = new Matrix();
-        float height = mLauncher.getDeviceProfile().heightPx;
-        float width = mLauncher.getDeviceProfile().widthPx;
-        float endX = (Utilities.isRtl(mLauncher.getResources()) ? -width : width) * 1.16f;
-
         ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
-        closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS);
-
-        closingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            boolean isFirstFrame = true;
+        int duration = CLOSING_TRANSITION_DURATION_MS;
+        closingAnimator.setDuration(duration);
+        closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
+            FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
+            FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DEACCEL_1_7);
+            FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR);
 
             @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = animation.getAnimatedFraction();
-                float currentPlayTime = percent * closingAnimator.getDuration();
-
-                float scale = getValue(1f, 0.8f, 0, 267, currentPlayTime,
-                        Interpolators.AGGRESSIVE_EASE);
-
-                float dX = getValue(0, endX, 0, 350, currentPlayTime,
-                        Interpolators.AGGRESSIVE_EASE_IN_OUT);
-
-                TransactionCompat t = new TransactionCompat();
-                for (RemoteAnimationTargetCompat app : targets) {
-                    if (app.mode == RemoteAnimationTargetCompat.MODE_CLOSING) {
-                        t.setAlpha(app.leash, getValue(1f, 0f, 0, 350, currentPlayTime,
-                                Interpolators.APP_CLOSE_ALPHA));
-                        matrix.setScale(scale, scale,
-                                app.sourceContainerBounds.centerX(),
-                                app.sourceContainerBounds.centerY());
-                        matrix.postTranslate(dX, 0);
-                        matrix.postTranslate(app.position.x, app.position.y);
-                        t.setMatrix(app.leash, matrix);
+            public void onUpdate(float percent) {
+                SurfaceParams[] params = new SurfaceParams[targets.length];
+                for (int i = targets.length - 1; i >= 0; i--) {
+                    RemoteAnimationTargetCompat target = targets[i];
+                    float alpha;
+                    if (target.mode == MODE_CLOSING) {
+                        matrix.setScale(mScale.value, mScale.value,
+                                target.sourceContainerBounds.centerX(),
+                                target.sourceContainerBounds.centerY());
+                        matrix.postTranslate(0, mDy.value);
+                        matrix.postTranslate(target.position.x, target.position.y);
+                        alpha = mAlpha.value;
+                    } else {
+                        matrix.setTranslate(target.position.x, target.position.y);
+                        alpha = 1f;
                     }
-                    if (isFirstFrame) {
-                        int layer = app.mode == RemoteAnimationTargetCompat.MODE_CLOSING
-                                ? Integer.MAX_VALUE
-                                : app.prefixOrderIndex;
-                        t.setLayer(app.leash, layer);
-                        t.show(app.leash);
-                    }
+                    params[i] = new SurfaceParams(target.leash, alpha, matrix,
+                            target.sourceContainerBounds,
+                            RemoteAnimationProvider.getLayer(target, MODE_CLOSING));
                 }
-                t.apply();
-
-                matrix.reset();
-                isFirstFrame = false;
+                surfaceApplier.scheduleApply(params);
             }
         });
+
         return closingAnimator;
     }
 
     /**
-     * @return Animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
+     * Creates an animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
      */
-    private AnimatorSet getLauncherResumeAnimation() {
-        if (mLauncher.isInState(LauncherState.ALL_APPS)
-                || mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */);
-            contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
-            return contentAnimator;
+    private void createLauncherResumeAnimation(AnimatorSet anim) {
+        if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+            Pair<AnimatorSet, Runnable> contentAnimator =
+                    getLauncherContentAnimator(false /* isAppOpening */);
+            contentAnimator.first.setStartDelay(LAUNCHER_RESUME_START_DELAY);
+            anim.play(contentAnimator.first);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    contentAnimator.second.run();
+                }
+            });
         } else {
             AnimatorSet workspaceAnimator = new AnimatorSet();
-            mLauncher.getWorkspace().setTranslationY(mWorkspaceTransY);
-            mLauncher.getWorkspace().setAlpha(0f);
-            workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(),
-                    View.TRANSLATION_Y, mWorkspaceTransY, 0));
-            workspaceAnimator.play(ObjectAnimator.ofFloat(mLauncher.getWorkspace(), View.ALPHA,
-                    0, 1f));
+
+            mDragLayer.setTranslationY(-mWorkspaceTransY);;
+            workspaceAnimator.play(ObjectAnimator.ofFloat(mDragLayer, View.TRANSLATION_Y,
+                    -mWorkspaceTransY, 0));
+
+            mDragLayerAlpha.setValue(0);
+            workspaceAnimator.play(ObjectAnimator.ofFloat(
+                    mDragLayerAlpha, MultiValueAlpha.VALUE, 0, 1f));
+
             workspaceAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
             workspaceAnimator.setDuration(333);
-            workspaceAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+            workspaceAnimator.setInterpolator(Interpolators.DEACCEL_1_7);
 
-            // Animate the shelf in two parts: slide in, and overeshoot.
-            AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-            // The shelf will start offscreen
-            final float startY = ALL_APPS_PROGRESS_START;
-            // And will end slightly pulled up, so that there is something to overshoot back to 1f.
-            final float slideEnd = ALL_APPS_PROGRESS_SLIDE_END;
+            mDragLayer.getScrim().hideSysUiScrim(true);
 
-            allAppsController.setProgress(startY);
+            // Pause page indicator animations as they lead to layer trashing.
+            mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
+            mDragLayer.setLayerType(View.LAYER_TYPE_HARDWARE, null);
 
-            Animator allAppsSlideIn =
-                    ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, startY, slideEnd);
-            allAppsSlideIn.setStartDelay(LAUNCHER_RESUME_START_DELAY);
-            allAppsSlideIn.setDuration(317);
-            allAppsSlideIn.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-
-            Animator allAppsOvershoot =
-                    ObjectAnimator.ofFloat(allAppsController, ALL_APPS_PROGRESS, slideEnd, 1f);
-            allAppsOvershoot.setDuration(153);
-            allAppsOvershoot.setInterpolator(Interpolators.OVERSHOOT_0);
-
-            AnimatorSet resumeLauncherAnimation = new AnimatorSet();
-            resumeLauncherAnimation.play(workspaceAnimator);
-            resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot);
-            return resumeLauncherAnimation;
+            workspaceAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    resetContentView();
+                }
+            });
+            anim.play(workspaceAnimator);
         }
     }
 
+    private void resetContentView() {
+        mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
+        mDragLayerAlpha.setValue(1f);
+        mDragLayer.setLayerType(View.LAYER_TYPE_NONE, null);
+        mDragLayer.setTranslationY(0f);
+        mDragLayer.getScrim().hideSysUiScrim(false);
+    }
+
     private boolean hasControlRemoteAppTransitionPermission() {
         return mLauncher.checkSelfPermission(CONTROL_REMOTE_APP_TRANSITION_PERMISSION)
                 == PackageManager.PERMISSION_GRANTED;
     }
-
-    /**
-     * Helper method that allows us to get interpolated values for embedded
-     * animations with a delay and/or different duration.
-     */
-    private static float getValue(float start, float end, float delay, float duration,
-            float currentPlayTime, Interpolator i) {
-        float time = Math.max(0, currentPlayTime - delay);
-        float newPercent = Math.min(1f, time / duration);
-        newPercent = i.getInterpolation(newPercent);
-        return end * newPercent + start * (1 - newPercent);
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
new file mode 100644
index 0000000..08b6bfc
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.OverviewCallbacks;
+import com.android.quickstep.util.RemoteAnimationProvider;
+
+import java.util.function.BiPredicate;
+
+@TargetApi(Build.VERSION_CODES.P)
+public class LauncherInitListener extends InternalStateHandler implements ActivityInitListener {
+
+    private final BiPredicate<Launcher, Boolean> mOnInitListener;
+
+    private RemoteAnimationProvider mRemoteAnimationProvider;
+
+    public LauncherInitListener(BiPredicate<Launcher, Boolean> onInitListener) {
+        mOnInitListener = onInitListener;
+    }
+
+    @Override
+    protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+        if (mRemoteAnimationProvider != null) {
+            LauncherAppTransitionManagerImpl appTransitionManager =
+                    (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager();
+
+            // Set a one-time animation provider. After the first call, this will get cleared.
+            // TODO: Probably also check the intended target id.
+            CancellationSignal cancellationSignal = new CancellationSignal();
+            appTransitionManager.setRemoteAnimationProvider((targets) -> {
+
+                // On the first call clear the reference.
+                cancellationSignal.cancel();
+                RemoteAnimationProvider provider = mRemoteAnimationProvider;
+                mRemoteAnimationProvider = null;
+
+                if (provider != null && launcher.getStateManager().getState().overviewUi) {
+                    return provider.createWindowAnimation(targets);
+                }
+                return null;
+            }, cancellationSignal);
+        }
+        OverviewCallbacks.get(launcher).onInitOverviewTransition();
+        return mOnInitListener.test(launcher, alreadyOnHome);
+    }
+
+    @Override
+    public void register() {
+        initWhenReady();
+    }
+
+    @Override
+    public void unregister() {
+        mRemoteAnimationProvider = null;
+        clearReference();
+    }
+
+    @Override
+    public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+            Context context, Handler handler, long duration) {
+        mRemoteAnimationProvider = animProvider;
+
+        register();
+
+        Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
+        context.startActivity(addToIntent(new Intent((intent))), options);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java b/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
deleted file mode 100644
index aec2869..0000000
--- a/quickstep/src/com/android/launcher3/LauncherTransitionAnimator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-
-/**
- * Creates an AnimatorSet consisting on one Animator for Launcher transition, and one Animator for
- * the Window transitions.
- *
- * Allows for ending the Launcher animator without ending the Window animator.
- */
-public class LauncherTransitionAnimator {
-
-    private AnimatorSet mAnimatorSet;
-    private Animator mLauncherAnimator;
-    private Animator mWindowAnimator;
-
-    LauncherTransitionAnimator(Animator launcherAnimator, Animator windowAnimator) {
-        if (launcherAnimator != null) {
-            mLauncherAnimator = launcherAnimator;
-        }
-        mWindowAnimator = windowAnimator;
-
-        mAnimatorSet = new AnimatorSet();
-        if (launcherAnimator != null) {
-            mAnimatorSet.play(launcherAnimator);
-        }
-        mAnimatorSet.play(windowAnimator);
-    }
-
-    public AnimatorSet getAnimatorSet() {
-        return mAnimatorSet;
-    }
-
-    public void cancel() {
-        mAnimatorSet.cancel();
-    }
-
-    public boolean isRunning() {
-        return mAnimatorSet.isRunning();
-    }
-
-    public void finishLauncherAnimation() {
-        if (mLauncherAnimator != null) {
-            mLauncherAnimator.end();
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 426fe35..1eaa8bc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -16,15 +16,12 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 
-import android.view.View;
-
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 /**
@@ -47,17 +44,14 @@
 
     @Override
     public void onStateEnabled(Launcher launcher) {
-        if (!launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)) {
-            launcher.getSharedPrefs().edit().putBoolean(APPS_VIEW_SHOWN, true).apply();
-        }
-
         AbstractFloatingView.closeAllOpenViews(launcher);
         dispatchWindowStateChanged(launcher);
     }
 
     @Override
     public String getDescription(Launcher launcher) {
-        return launcher.getString(R.string.all_apps_button_label);
+        AllAppsContainerView appsView = launcher.getAppsView();
+        return appsView.getDescription();
     }
 
     @Override
@@ -66,14 +60,11 @@
     }
 
     @Override
-    public View getFinalFocus(Launcher launcher) {
-        return launcher.getAppsView();
-    }
-
-    @Override
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
-        // TODO: interpolate
-        return LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(launcher);
+        float[] scaleAndTranslation = LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(
+                launcher);
+        scaleAndTranslation[0] = 1;
+        return scaleAndTranslation;
     }
 
     @Override
@@ -82,8 +73,13 @@
     }
 
     @Override
-    public float getHoseatAlpha(Launcher launcher) {
-        return 0;
+    public int getVisibleElements(Launcher launcher) {
+        return ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
+    }
+
+    @Override
+    public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+        return new float[] {0.9f, -0.2f};
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
new file mode 100644
index 0000000..722f51b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/BackButtonAlphaHandler.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.quickstep.OverviewInteractionState;
+
+public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
+
+    private static final String TAG = "BackButtonAlphaHandler";
+
+    private final Launcher mLauncher;
+    private final OverviewInteractionState mOverviewInteractionState;
+
+    public BackButtonAlphaHandler(Launcher launcher) {
+        mLauncher = launcher;
+        mOverviewInteractionState = OverviewInteractionState.getInstance(mLauncher);
+    }
+
+    @Override
+    public void setState(LauncherState state) {
+        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+    }
+
+    @Override
+    public void setStateWithAnimation(LauncherState toState,
+            AnimatorSetBuilder builder, LauncherStateManager.AnimationConfig config) {
+        if (!config.playNonAtomicComponent()) {
+            return;
+        }
+        float fromAlpha = mOverviewInteractionState.getBackButtonAlpha();
+        float toAlpha = toState.hideBackButton ? 0 : 1;
+        if (Float.compare(fromAlpha, toAlpha) != 0) {
+            ValueAnimator anim = ValueAnimator.ofFloat(fromAlpha, toAlpha);
+            anim.setDuration(config.duration);
+            anim.addUpdateListener(valueAnimator -> {
+                final float alpha = (float) valueAnimator.getAnimatedValue();
+                mOverviewInteractionState.setBackButtonAlpha(alpha, false);
+            });
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // Reapply the final alpha in case some state (e.g. window focus) changed.
+                    UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+                }
+            });
+            builder.play(anim);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java b/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java
new file mode 100644
index 0000000..2d9a161
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/DisplayRotationListener.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.systemui.shared.system.RotationWatcher;
+
+/**
+ * Utility class for listening for rotation changes
+ */
+public class DisplayRotationListener extends RotationWatcher {
+
+    private final Runnable mCallback;
+    private Handler mHandler;
+
+    public DisplayRotationListener(Context context, Runnable callback) {
+        super(context);
+        mCallback = callback;
+    }
+
+    @Override
+    public void enable() {
+        if (mHandler == null) {
+            mHandler = new Handler();
+        }
+        super.enable();
+    }
+
+    @Override
+    protected void onRotationChanged(int i) {
+        mHandler.post(mCallback);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java b/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
deleted file mode 100644
index 6df1aba..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/DragPauseDetector.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import com.android.launcher3.Alarm;
-import com.android.launcher3.OnAlarmListener;
-
-/**
- * Utility class to detect a pause during a drag.
- */
-public class DragPauseDetector implements OnAlarmListener {
-
-    private static final float MAX_VELOCITY_TO_PAUSE = 0.2f;
-    private static final long PAUSE_DURATION = 100;
-
-    private final Alarm mAlarm;
-    private final Runnable mOnPauseCallback;
-
-    private boolean mTriggered = false;
-    private int mDisabledFlags = 0;
-
-    public DragPauseDetector(Runnable onPauseCallback) {
-        mOnPauseCallback = onPauseCallback;
-
-        mAlarm = new Alarm();
-        mAlarm.setOnAlarmListener(this);
-        mAlarm.setAlarm(PAUSE_DURATION);
-    }
-
-    public void onDrag(float velocity) {
-        if (mTriggered || !isEnabled()) {
-            return;
-        }
-
-        if (Math.abs(velocity) > MAX_VELOCITY_TO_PAUSE) {
-            // Cancel any previous alarm and set a new alarm
-            mAlarm.setAlarm(PAUSE_DURATION);
-        }
-    }
-
-    @Override
-    public void onAlarm(Alarm alarm) {
-        if (!mTriggered && isEnabled()) {
-            mTriggered = true;
-            mOnPauseCallback.run();
-        }
-    }
-
-    public boolean isTriggered () {
-        return mTriggered;
-    }
-
-    public boolean isEnabled() {
-        return mDisabledFlags == 0;
-    }
-
-    public void addDisabledFlags(int flags) {
-        boolean wasEnabled = isEnabled();
-        mDisabledFlags |= flags;
-        resetAlarm(wasEnabled);
-    }
-
-    public void clearDisabledFlags(int flags) {
-        boolean wasEnabled = isEnabled();
-        mDisabledFlags  &= ~flags;
-        resetAlarm(wasEnabled);
-    }
-
-    private void resetAlarm(boolean wasEnabled) {
-        boolean isEnabled = isEnabled();
-        if (wasEnabled == isEnabled) {
-          // Nothing has changed
-        } if (isEnabled && !mTriggered) {
-            mAlarm.setAlarm(PAUSE_DURATION);
-        } else if (!isEnabled) {
-            mAlarm.cancelAlarm();
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
deleted file mode 100644
index bf55bd6..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2018 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_NEGATIVE;
-import static com.android.launcher3.touch.SwipeDetector.DIRECTION_POSITIVE;
-import static com.android.launcher3.touch.SwipeDetector.HORIZONTAL;
-import static com.android.launcher3.touch.SwipeDetector.VERTICAL;
-import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
-
-import android.graphics.Rect;
-import android.metrics.LogMaker;
-import android.view.MotionEvent;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.util.VerticalSwipeController;
-import com.android.quickstep.RecentsView;
-
-class EventLogTags {
-    private EventLogTags() {
-    }  // don't instantiate
-
-    /** 524292 sysui_multi_action (content|4) */
-    public static final int SYSUI_MULTI_ACTION = 524292;
-
-    public static void writeSysuiMultiAction(Object[] content) {
-        android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content);
-    }
-}
-
-class MetricsLogger {
-    private static MetricsLogger sMetricsLogger;
-
-    private static MetricsLogger getLogger() {
-        if (sMetricsLogger == null) {
-            sMetricsLogger = new MetricsLogger();
-        }
-        return sMetricsLogger;
-    }
-
-    protected void saveLog(Object[] rep) {
-        EventLogTags.writeSysuiMultiAction(rep);
-    }
-
-    public void write(LogMaker content) {
-        if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
-            content.setType(4/*MetricsEvent.TYPE_ACTION*/);
-        }
-        saveLog(content.serialize());
-    }
-}
-
-/**
- * Extension of {@link VerticalSwipeController} to go from NORMAL to OVERVIEW.
- */
-public class EdgeSwipeController extends VerticalSwipeController implements
-        OnDeviceProfileChangeListener {
-
-    private static final Rect sTempRect = new Rect();
-
-    private final MetricsLogger mMetricsLogger = new MetricsLogger();
-
-    public EdgeSwipeController(Launcher l) {
-        super(l, NORMAL, OVERVIEW, l.getDeviceProfile().isVerticalBarLayout()
-                ? HORIZONTAL : VERTICAL);
-        l.addOnDeviceProfileChangeListener(this);
-    }
-
-    @Override
-    public void onDeviceProfileChanged(DeviceProfile dp) {
-        mDetector.updateDirection(dp.isVerticalBarLayout() ? HORIZONTAL : VERTICAL);
-    }
-
-    @Override
-    protected boolean shouldInterceptTouch(MotionEvent ev) {
-        return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
-    }
-
-    @Override
-    protected int getSwipeDirection(MotionEvent ev) {
-        return isTransitionFlipped() ? DIRECTION_NEGATIVE : DIRECTION_POSITIVE;
-    }
-
-    @Override
-    protected boolean isTransitionFlipped() {
-        return mLauncher.getDeviceProfile().isSeascape();
-    }
-
-    @Override
-    protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
-        if (stateChanged && mToState instanceof OverviewState) {
-            // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
-            // "Recents" activity for app transition tests.
-            final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
-            builder.setPackageName("com.android.systemui");
-            builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
-                    "com.android.systemui.recents.RecentsActivity");
-            builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
-                    0/* zero time */);
-            mMetricsLogger.write(builder);
-        }
-        // TODO: Log something
-    }
-
-    @Override
-    protected void initSprings() {
-        mSpringHandlers = new SpringAnimationHandler[0];
-    }
-
-    @Override
-    protected float getShiftRange() {
-        return getShiftRange(mLauncher);
-    }
-
-    public static float getShiftRange(Launcher launcher) {
-        RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, sTempRect);
-        DragLayer dl = launcher.getDragLayer();
-        Rect insets = dl.getInsets();
-        DeviceProfile dp = launcher.getDeviceProfile();
-
-        if (dp.isVerticalBarLayout()) {
-            if (dp.isSeascape()) {
-                return insets.left + sTempRect.left;
-            } else {
-                return dl.getWidth() - sTempRect.right + insets.right;
-            }
-        } else {
-            return dl.getHeight() - sTempRect.bottom + insets.bottom;
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
new file mode 100644
index 0000000..2645302
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Extension of overview state used for QuickScrub
+ */
+public class FastOverviewState extends OverviewState {
+
+    private static final float MAX_PREVIEW_SCALE_UP = 1.3f;
+    /**
+     * Vertical transition of the task previews relative to the full container.
+     */
+    public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f;
+
+    private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION
+            | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY;
+
+    public FastOverviewState(int id) {
+        super(id, QuickScrubController.QUICK_SCRUB_FROM_HOME_START_DURATION, STATE_FLAGS);
+    }
+
+    @Override
+    public void onStateTransitionEnd(Launcher launcher) {
+        super.onStateTransitionEnd(launcher);
+        RecentsView recentsView = launcher.getOverviewPanel();
+        recentsView.getQuickScrubController().onFinishedTransitionToQuickScrub();
+    }
+
+    @Override
+    public int getVisibleElements(Launcher launcher) {
+        return NONE;
+    }
+
+    @Override
+    public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+        RecentsView recentsView = launcher.getOverviewPanel();
+        recentsView.getTaskSize(sTempRect);
+
+        return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher),
+                OVERVIEW_TRANSLATION_FACTOR};
+    }
+
+    public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) {
+        if (dp.isVerticalBarLayout()) {
+            return 1f;
+        }
+
+        Resources res = context.getResources();
+        float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin);
+        float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing)
+                + res.getDimension(R.dimen.quickscrub_adjacent_visible_width));
+        return Math.min(Math.min(dp.availableHeightPx / usedHeight,
+                dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP);
+    }
+
+    @Override
+    public void onStateDisabled(Launcher launcher) {
+        super.onStateDisabled(launcher);
+        launcher.<RecentsView>getOverviewPanel().getQuickScrubController().cancelActiveQuickscrub();
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java b/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java
deleted file mode 100644
index 2d5eb5a..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/IgnoreTouchesInQuickScrub.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 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.uioverrides;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.util.TouchController;
-import com.android.quickstep.TouchInteractionService;
-
-/**
- * Consumes touches when quick scrub is enabled.
- */
-public class IgnoreTouchesInQuickScrub implements TouchController {
-
-    public IgnoreTouchesInQuickScrub() {
-    }
-
-    @Override
-    public boolean onControllerTouchEvent(MotionEvent ev) {
-        return true;
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        return TouchInteractionService.isQuickScrubEnabled();
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
new file mode 100644
index 0000000..6d10619
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -0,0 +1,79 @@
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.AnimationComponents;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.quickstep.RecentsModel;
+
+/**
+ * Touch controller for handling edge swipes in landscape/seascape UI
+ */
+public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchController {
+
+    private static final String TAG = "LandscapeEdgeSwipeCtrl";
+
+    public LandscapeEdgeSwipeController(Launcher l) {
+        super(l, SwipeDetector.HORIZONTAL);
+    }
+
+    @Override
+    protected boolean canInterceptTouch(MotionEvent ev) {
+        if (mCurrentAnimation != null) {
+            // If we are already animating from a previous state, we can intercept.
+            return true;
+        }
+        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+            return false;
+        }
+        return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+    }
+
+    @Override
+    protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+        boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive;
+        return draggingFromNav ? OVERVIEW : NORMAL;
+    }
+
+    @Override
+    protected int getLogContainerTypeForNormalState() {
+        return LauncherLogProto.ContainerType.NAVBAR;
+    }
+
+    @Override
+    protected float getShiftRange() {
+        return mLauncher.getDragLayer().getWidth();
+    }
+
+    @Override
+    protected float initCurrentAnimation(@AnimationComponents int animComponent) {
+        float range = getShiftRange();
+        long maxAccuracy = (long) (2 * range);
+        mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
+                maxAccuracy, animComponent);
+        return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
+    }
+
+    @Override
+    protected int getDirectionForLog() {
+        return mLauncher.getDeviceProfile().isSeascape() ? Direction.RIGHT : Direction.LEFT;
+    }
+
+    @Override
+    protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+        super.onSwipeInteractionCompleted(targetState, logAction);
+        if (mStartState == NORMAL && targetState == OVERVIEW) {
+            RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
deleted file mode 100644
index c089d06..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2018 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.uioverrides;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Outline;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.widget.Toast;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.RevealOutlineAnimation;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.GradientView;
-import com.android.launcher3.widget.WidgetsFullSheet;
-
-/**
- * Popup shown on long pressing an empty space in launcher
- */
-public class OptionsPopupView extends AbstractFloatingView implements OnClickListener {
-
-    private final float mOutlineRadius;
-    private final Launcher mLauncher;
-    private final PointF mTouchPoint = new PointF();
-
-    private final GradientView mGradientView;
-
-    protected Animator mOpenCloseAnimator;
-
-    public OptionsPopupView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
-        setClipToOutline(true);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
-            }
-        });
-
-        mLauncher = Launcher.getLauncher(context);
-
-        mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
-                R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
-        mGradientView.setProgress(1, false);
-        mGradientView.setAlpha(0);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        findViewById(R.id.wallpaper_button).setOnClickListener(this);
-        findViewById(R.id.widget_button).setOnClickListener(this);
-        findViewById(R.id.settings_button).setOnClickListener(this);
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (view.getId() == R.id.wallpaper_button) {
-            mLauncher.onClickWallpaperPicker(null);
-            close(true);
-        } else if (view.getId() == R.id.widget_button) {
-            if (mLauncher.getPackageManager().isSafeMode()) {
-                Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
-            } else {
-                WidgetsFullSheet.show(mLauncher, true /* animated */);
-                close(true);
-            }
-        } else if (view.getId() == R.id.settings_button) {
-            mLauncher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
-                .setPackage(mLauncher.getPackageName())
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
-            close(true);
-        }
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() != MotionEvent.ACTION_DOWN) {
-            return false;
-        }
-        if (mLauncher.getDragLayer().isEventOverView(this, ev)) {
-            return false;
-        }
-        close(true);
-        return true;
-    }
-
-    @Override
-    protected void handleClose(boolean animate) {
-        if (animate) {
-            animateClose();
-        } else {
-            closeComplete();
-        }
-    }
-
-    protected void animateClose() {
-        if (!mIsOpen) {
-            return;
-        }
-        mIsOpen = false;
-
-        final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
-        closeAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
-
-        // Rectangular reveal (reversed).
-        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, true);
-        closeAnim.play(revealAnim);
-
-        Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
-        fadeOut.setInterpolator(Interpolators.DEACCEL);
-        closeAnim.play(fadeOut);
-
-        Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 0);
-        gradientAlpha.setInterpolator(Interpolators.DEACCEL);
-        closeAnim.play(gradientAlpha);
-
-        closeAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mOpenCloseAnimator = null;
-                closeComplete();
-            }
-        });
-        if (mOpenCloseAnimator != null) {
-            mOpenCloseAnimator.cancel();
-        }
-        mOpenCloseAnimator = closeAnim;
-        closeAnim.start();
-    }
-
-    /**
-     * Closes the popup without animation.
-     */
-    private void closeComplete() {
-        if (mOpenCloseAnimator != null) {
-            mOpenCloseAnimator.cancel();
-            mOpenCloseAnimator = null;
-        }
-        mIsOpen = false;
-        mLauncher.getDragLayer().removeView(this);
-        mLauncher.getDragLayer().removeView(mGradientView);
-    }
-
-    @Override
-    public void logActionCommand(int command) {
-        // TODO:
-    }
-
-    @Override
-    protected boolean isOfType(int type) {
-        return (type & TYPE_OPTIONS_POPUP) != 0;
-    }
-
-    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
-        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        Rect startRect = new Rect();
-        startRect.offset((int) (mTouchPoint.x - lp.x), (int) (mTouchPoint.y - lp.y));
-
-        Rect endRect = new Rect(0, 0, lp.width, lp.height);
-        if (getOutlineProvider() instanceof RevealOutlineAnimation) {
-            ((RevealOutlineAnimation) getOutlineProvider()).getOutline(endRect);
-        }
-
-        return new RoundedRectRevealOutlineProvider
-                (mOutlineRadius, mOutlineRadius, startRect, endRect);
-    }
-
-    private void animateOpen() {
-        mIsOpen = true;
-        final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
-        openAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
-
-        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, false);
-        openAnim.play(revealAnim);
-
-        Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 1);
-        gradientAlpha.setInterpolator(Interpolators.ACCEL);
-        openAnim.play(gradientAlpha);
-
-        mOpenCloseAnimator = openAnim;
-
-        openAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mOpenCloseAnimator = null;
-            }
-        });
-        openAnim.start();
-    }
-
-    public static void show(Launcher launcher, float x, float y) {
-        DragLayer dl = launcher.getDragLayer();
-        OptionsPopupView view = (OptionsPopupView) launcher.getLayoutInflater()
-                .inflate(R.layout.longpress_options_menu, dl, false);
-        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) view.getLayoutParams();
-
-        int maxWidth = dl.getWidth();
-        int maxHeight = dl.getHeight();
-        if (x <= 0 || y <= 0 || x >= maxWidth || y >= maxHeight) {
-            x = maxWidth / 2;
-            y = maxHeight / 2;
-        }
-        view.mTouchPoint.set(x, y);
-
-        int height = lp.height;
-
-        // Find a good width;
-        int childCount = view.getChildCount();
-        int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
-        int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth / childCount, MeasureSpec.AT_MOST);
-        int maxChildWidth = 0;
-
-        for (int i = 0; i < childCount; i ++) {
-            View child = ((ViewGroup) view.getChildAt(i)).getChildAt(0);
-            child.measure(widthSpec, heightSpec);
-            maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth());
-        }
-        Rect insets = dl.getInsets();
-        int margin = (int) (2 * view.getElevation());
-
-        int width = Math.min(maxWidth - insets.left - insets.right - 2 * margin,
-                maxChildWidth * childCount);
-        lp.width = width;
-
-        // Position is towards the finger
-        lp.customPosition = true;
-        lp.x = Utilities.boundToRange((int) (x - width / 2), insets.left + margin,
-                maxWidth - insets.right - width - margin);
-        lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin,
-                maxHeight - insets.bottom - height - margin);
-
-        launcher.getDragLayer().addView(view.mGradientView);
-        launcher.getDragLayer().addView(view);
-        view.animateOpen();
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 5706d32..7f956f8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,118 +16,118 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
+import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
 
-import android.content.Context;
-import android.graphics.Rect;
 import android.view.View;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.quickstep.RecentsView;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.views.RecentsView;
 
 /**
  * Definition for overview state
  */
 public class OverviewState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
-            | FLAG_DISABLE_RESTORE;
+    private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
+            | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI | FLAG_DISABLE_ACCESSIBILITY;
 
     public OverviewState(int id) {
-        super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
+        this(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
+    }
+
+    protected OverviewState(int id, int transitionDuration, int stateFlags) {
+        super(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
     }
 
     @Override
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
-        Rect pageRect = new Rect();
-        RecentsView.getScaledDownPageRect(launcher.getDeviceProfile(), launcher, pageRect);
-        RecentsView rv = launcher.getOverviewPanel();
+        RecentsView recentsView = launcher.getOverviewPanel();
+        Workspace workspace = launcher.getWorkspace();
+        View workspacePage = workspace.getPageAt(workspace.getCurrentPage());
+        float workspacePageWidth = workspacePage != null && workspacePage.getWidth() != 0
+                ? workspacePage.getWidth() : launcher.getDeviceProfile().availableWidthPx;
+        recentsView.getTaskSize(sTempRect);
+        float scale = (float) sTempRect.width() / workspacePageWidth;
+        float parallaxFactor = 0.5f;
+        return new float[]{scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor};
+    }
 
-        if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
-            return super.getWorkspaceScaleAndTranslation(launcher);
-        }
-
-        float overlap = 0;
-        if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
-            overlap = launcher.getResources().getDimension(R.dimen.workspace_overview_offset_x);
-        }
-        return getScaleAndTranslationForPageRect(launcher, overlap, pageRect);
+    @Override
+    public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+        return new float[] {1f, 0f};
     }
 
     @Override
     public void onStateEnabled(Launcher launcher) {
         RecentsView rv = launcher.getOverviewPanel();
         rv.setOverviewStateEnabled(true);
+        AbstractFloatingView.closeAllOpenViews(launcher);
     }
 
     @Override
     public void onStateDisabled(Launcher launcher) {
         RecentsView rv = launcher.getOverviewPanel();
         rv.setOverviewStateEnabled(false);
+        RecentsModel.getInstance(launcher).resetAssistCache();
     }
 
     @Override
-    public float getVerticalProgress(Launcher launcher) {
-        return getVerticalProgress(launcher.getDeviceProfile(), launcher);
-    }
-
-    @Override
-    public View getFinalFocus(Launcher launcher) {
-        return launcher.getOverviewPanel();
+    public void onStateTransitionEnd(Launcher launcher) {
+        launcher.getRotationHelper().setCurrentStateRequest(REQUEST_ROTATE);
+        DiscoveryBounce.showForOverviewIfNeeded(launcher);
     }
 
     public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
-        final int centerPage = launcher.getWorkspace().getNextPage();
-        return new PageAlphaProvider(ACCEL_2) {
+        return new PageAlphaProvider(DEACCEL_2) {
             @Override
             public float getPageAlpha(int pageIndex) {
-                return  pageIndex != centerPage ? 0 : 1f;
+                return 0;
             }
         };
     }
 
-    public static float[] getScaleAndTranslationForPageRect(Launcher launcher, float offsetX,
-            Rect pageRect) {
-        Workspace ws = launcher.getWorkspace();
-        float childWidth = ws.getNormalChildWidth();
-        float childHeight = ws.getNormalChildHeight();
-
-        float scale = pageRect.height() / childHeight;
-        Rect insets = launcher.getDragLayer().getInsets();
-
-        float halfHeight = ws.getExpectedHeight() / 2;
-        float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
-        float translationY = pageRect.top - childTop;
-
-        // Align the workspace horizontally centered with the task rect
-        float halfWidth = ws.getExpectedWidth() / 2;
-        float childCenter = halfWidth -
-                scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2);
-        float translationX = pageRect.centerX() - childCenter;
-
-        if (Utilities.isRtl(launcher.getResources())) {
-            translationX -= offsetX / scale;
+    @Override
+    public int getVisibleElements(Launcher launcher) {
+        if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+            return VERTICAL_SWIPE_INDICATOR;
         } else {
-            translationX += offsetX / scale;
+            return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR |
+                    (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
+                            ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
         }
-
-        return new float[] {scale, translationX, translationY};
     }
 
-    public static float getVerticalProgress(DeviceProfile grid, Context context) {
-        if (!grid.isVerticalBarLayout()) {
-            return 1f;
-        }
+    @Override
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
+        return 0.5f;
+    }
 
-        float total = grid.heightPx;
-        float searchHeight = total - grid.availableHeightPx +
-                context.getResources().getDimension(R.dimen.all_apps_search_box_full_height);
-        return 1 - (searchHeight / total);
+    @Override
+    public float getVerticalProgress(Launcher launcher) {
+        if ((getVisibleElements(launcher) & ALL_APPS_HEADER_EXTRA) == 0) {
+            // We have no all apps content, so we're still at the fully down progress.
+            return super.getVerticalProgress(launcher);
+        }
+        return 1 - (getDefaultSwipeHeight(launcher)
+                / launcher.getAllAppsController().getShiftRange());
+    }
+
+    @Override
+    public String getDescription(Launcher launcher) {
+        return launcher.getString(R.string.accessibility_desc_recent_apps);
+    }
+
+    public static float getDefaultSwipeHeight(Launcher launcher) {
+        DeviceProfile dp = launcher.getDeviceProfile();
+        return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
deleted file mode 100644
index 1fd541a..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2018 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.uioverrides;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.util.TouchController;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TaskView;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-
-/**
- * Touch controller for swipe interaction in Overview state
- */
-public class OverviewSwipeController extends AnimatorListenerAdapter
-        implements TouchController, SwipeDetector.Listener {
-
-    private static final String TAG = "OverviewSwipeController";
-
-    private static final float ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS = 0.1f;
-    private static final int SINGLE_FRAME_MS = 16;
-
-    // Progress after which the transition is assumed to be a success in case user does not fling
-    private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
-    private final Launcher mLauncher;
-    private final SwipeDetector mDetector;
-    private final RecentsView mRecentsView;
-    private final int[] mTempCords = new int[2];
-
-    private AnimatorPlaybackController mCurrentAnimation;
-    private boolean mCurrentAnimationIsGoingUp;
-
-    private boolean mNoIntercept;
-    private boolean mSwipeDownEnabled;
-
-    private float mDisplacementShift;
-    private float mProgressMultiplier;
-    private float mEndDisplacement;
-
-    private TaskView mTaskBeingDragged;
-
-    public OverviewSwipeController(Launcher launcher) {
-        mLauncher = launcher;
-        mRecentsView = launcher.getOverviewPanel();
-        mDetector = new SwipeDetector(launcher, this, SwipeDetector.VERTICAL);
-    }
-
-    private boolean canInterceptTouch() {
-        if (mCurrentAnimation != null) {
-            // If we are already animating from a previous state, we can intercept.
-            return true;
-        }
-        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
-            return false;
-        }
-        return mLauncher.isInState(OVERVIEW);
-    }
-
-    private boolean isEventOverHotseat(MotionEvent ev) {
-        if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            return ev.getY() >
-                    mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
-        } else {
-            return mLauncher.getDragLayer().isEventOverHotseat(ev);
-        }
-    }
-
-    @Override
-    public void onAnimationCancel(Animator animation) {
-        if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
-            Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
-            mDetector.finishedScrolling();
-            mCurrentAnimation = null;
-        }
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mNoIntercept = !canInterceptTouch();
-            if (mNoIntercept) {
-                return false;
-            }
-
-            // Now figure out which direction scroll events the controller will start
-            // calling the callbacks.
-            final int directionsToDetectScroll;
-            boolean ignoreSlopWhenSettling = false;
-
-            if (mCurrentAnimation != null) {
-                directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
-                ignoreSlopWhenSettling = true;
-            } else {
-                mTaskBeingDragged = null;
-                mSwipeDownEnabled = true;
-
-                int currentPage = mRecentsView.getCurrentPage();
-                if (currentPage == 0) {
-                    // User is on home tile
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
-                } else {
-                    View view = mRecentsView.getChildAt(currentPage);
-                    if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
-                            view instanceof TaskView) {
-                        // The tile can be dragged down to open the task.
-                        mTaskBeingDragged = (TaskView) view;
-                        directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
-                    } else if (isEventOverHotseat(ev)) {
-                        // The hotseat is being dragged
-                        directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
-                        mSwipeDownEnabled = false;
-                    } else {
-                        mNoIntercept = true;
-                        return false;
-                    }
-                }
-            }
-
-            mDetector.setDetectableScrollConditions(
-                    directionsToDetectScroll, ignoreSlopWhenSettling);
-        }
-
-        if (mNoIntercept) {
-            return false;
-        }
-
-        onControllerTouchEvent(ev);
-        return mDetector.isDraggingOrSettling();
-    }
-
-    @Override
-    public boolean onControllerTouchEvent(MotionEvent ev) {
-        return mDetector.onTouchEvent(ev);
-    }
-
-    private void reInitAnimationController(boolean goingUp) {
-        if (!goingUp && !mSwipeDownEnabled) {
-            goingUp = true;
-        }
-        if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) {
-            // No need to init
-            return;
-        }
-        if (mCurrentAnimation != null) {
-            mCurrentAnimation.setPlayFraction(0);
-        }
-        mCurrentAnimationIsGoingUp = goingUp;
-        float range = mLauncher.getAllAppsController().getShiftRange();
-        long maxDuration = (long) (2 * range);
-        DragLayer dl = mLauncher.getDragLayer();
-
-        if (mTaskBeingDragged == null) {
-            // User is either going to all apps or home
-            mCurrentAnimation = mLauncher.getStateManager()
-                    .createAnimationToNewWorkspace(goingUp ? ALL_APPS : NORMAL, maxDuration);
-            if (goingUp) {
-                mEndDisplacement = -range;
-            } else {
-                mEndDisplacement = EdgeSwipeController.getShiftRange(mLauncher);
-            }
-        } else {
-            if (goingUp) {
-                AnimatorSet anim = new AnimatorSet();
-                ObjectAnimator translate = ObjectAnimator.ofFloat(
-                        mTaskBeingDragged, View.TRANSLATION_Y, -mTaskBeingDragged.getBottom());
-                translate.setInterpolator(LINEAR);
-                translate.setDuration(maxDuration);
-                anim.play(translate);
-
-                ObjectAnimator alpha = ObjectAnimator.ofFloat(mTaskBeingDragged, View.ALPHA, 0);
-                alpha.setInterpolator(DEACCEL_1_5);
-                alpha.setDuration(maxDuration);
-                anim.play(alpha);
-                mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
-                mEndDisplacement = -mTaskBeingDragged.getBottom();
-            } else {
-                AnimatorSet anim = new AnimatorSet();
-                // TODO: Setup a zoom animation
-                mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
-
-                mTempCords[1] = mTaskBeingDragged.getHeight();
-                dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
-                mEndDisplacement = dl.getHeight() - mTempCords[1];
-            }
-        }
-
-        mCurrentAnimation.getTarget().addListener(this);
-        mCurrentAnimation.dispatchOnStart();
-        mProgressMultiplier = 1 / mEndDisplacement;
-    }
-
-    @Override
-    public void onDragStart(boolean start) {
-        if (mCurrentAnimation == null) {
-            reInitAnimationController(mDetector.wasInitialTouchPositive());
-            mDisplacementShift = 0;
-        } else {
-            mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
-            mCurrentAnimation.pause();
-        }
-    }
-
-    @Override
-    public boolean onDrag(float displacement, float velocity) {
-        float totalDisplacement = displacement + mDisplacementShift;
-        boolean isGoingUp =
-                totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
-        if (isGoingUp != mCurrentAnimationIsGoingUp) {
-            reInitAnimationController(isGoingUp);
-        }
-        mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier);
-        return true;
-    }
-
-    @Override
-    public void onDragEnd(float velocity, boolean fling) {
-        final boolean goingToEnd;
-
-        if (fling) {
-            boolean goingUp = velocity < 0;
-            if (!goingUp && !mSwipeDownEnabled) {
-                goingToEnd = false;
-            } else if (goingUp != mCurrentAnimationIsGoingUp) {
-                // In case the fling is in opposite direction, make sure if is close enough
-                // from the start position
-                if (mCurrentAnimation.getProgressFraction()
-                        >= ALLOWED_FLING_DIRECTION_CHANGE_PROGRESS) {
-                    // Not allowed
-                    goingToEnd = false;
-                } else {
-                    reInitAnimationController(goingUp);
-                    goingToEnd = true;
-                }
-            } else {
-                goingToEnd = true;
-            }
-        } else {
-            goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS;
-        }
-
-        float progress = mCurrentAnimation.getProgressFraction();
-        long animationDuration = SwipeDetector.calculateDuration(
-                velocity, goingToEnd ? (1 - progress) : progress);
-
-        float nextFrameProgress = Utilities.boundToRange(
-                progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f);
-
-
-        mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd));
-
-        ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
-        anim.setFloatValues(nextFrameProgress, goingToEnd ? 1f : 0f);
-        anim.setDuration(animationDuration);
-        anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
-        anim.start();
-    }
-
-    private void onCurrentAnimationEnd(boolean wasSuccess) {
-        // TODO: Might be a good time to log something.
-        if (mTaskBeingDragged == null) {
-            LauncherState state = wasSuccess ?
-                    (mCurrentAnimationIsGoingUp ? ALL_APPS : NORMAL) : OVERVIEW;
-            mLauncher.getStateManager().goToState(state, false);
-        } else if (wasSuccess) {
-            if (mCurrentAnimationIsGoingUp) {
-                mRecentsView.onTaskDismissed(mTaskBeingDragged);
-            } else {
-                mTaskBeingDragged.launchTask(false);
-            }
-        }
-        mDetector.finishedScrolling();
-        mTaskBeingDragged = null;
-        mCurrentAnimation = null;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
deleted file mode 100644
index 3ae8f41..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.VerticalSwipeController;
-
-/**
- * Extension of {@link VerticalSwipeController} which allows swipe up from OVERVIEW to ALL_APPS
- * Note that the swipe down is handled by {@link TwoStepSwipeController}.
- */
-public class OverviewSwipeUpController extends VerticalSwipeController {
-
-    public OverviewSwipeUpController(Launcher l) {
-        super(l, OVERVIEW);
-    }
-
-    @Override
-    protected boolean shouldInterceptTouch(MotionEvent ev) {
-        if (!mLauncher.isInState(OVERVIEW)) {
-            return false;
-        }
-        if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            return ev.getY() >
-                    mLauncher.getDragLayer().getHeight() * OVERVIEW.getVerticalProgress(mLauncher);
-        } else {
-            return mLauncher.getDragLayer().isEventOverHotseat(ev);
-        }
-    }
-
-    @Override
-    protected int getSwipeDirection(MotionEvent ev) {
-        return SwipeDetector.DIRECTION_POSITIVE;
-    }
-
-    @Override
-    protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
-        if (stateChanged) {
-            // Transition complete. log the action
-            mLauncher.getUserEventDispatcher().logActionOnContainer(
-                    wasFling ? Touch.FLING : Touch.SWIPE,
-                    Direction.UP,
-                    ContainerType.OVERVIEW,
-                    mLauncher.getWorkspace().getCurrentPage());
-        }
-
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java
new file mode 100644
index 0000000..0f9b57f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewToAllAppsTouchController.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.views.RecentsView;
+
+/**
+ * Touch controller from going from OVERVIEW to ALL_APPS.
+ *
+ * This is used in landscape mode. It is also used in portrait mode for the fallback recents.
+ */
+public class OverviewToAllAppsTouchController extends PortraitStatesTouchController {
+
+    public OverviewToAllAppsTouchController(Launcher l) {
+        super(l);
+    }
+
+    @Override
+    protected boolean canInterceptTouch(MotionEvent ev) {
+        if (mCurrentAnimation != null) {
+            // If we are already animating from a previous state, we can intercept.
+            return true;
+        }
+        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+            return false;
+        }
+        if (mLauncher.isInState(ALL_APPS)) {
+            // In all-apps only listen if the container cannot scroll itself
+            return mLauncher.getAppsView().shouldContainerScroll(ev);
+        } else if (mLauncher.isInState(NORMAL)) {
+            return true;
+        } else if (mLauncher.isInState(OVERVIEW)) {
+            RecentsView rv = mLauncher.getOverviewPanel();
+            return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+        if (fromState == ALL_APPS && !isDragTowardPositive) {
+            // Should swipe down go to OVERVIEW instead?
+            return TouchInteractionService.isConnected() ?
+                    mLauncher.getStateManager().getLastState() : NORMAL;
+        } else if (isDragTowardPositive) {
+            return ALL_APPS;
+        }
+        return fromState;
+    }
+
+    @Override
+    protected int getLogContainerTypeForNormalState() {
+        return LauncherLogProto.ContainerType.WORKSPACE;
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
new file mode 100644
index 0000000..1d1b7da
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.view.MotionEvent;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.AnimationComponents;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.TouchInteractionService;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+
+/**
+ * Touch controller for handling various state transitions in portrait UI.
+ */
+public class PortraitStatesTouchController extends AbstractStateChangeTouchController {
+
+    private static final String TAG = "PortraitStatesTouchCtrl";
+
+    /**
+     * The progress at which all apps content will be fully visible when swiping up from overview.
+     */
+    private static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f;
+
+    /**
+     * The progress at which recents will begin fading out when swiping up from overview.
+     */
+    private static final float RECENTS_FADE_THRESHOLD = 0.88f;
+
+    private InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
+
+    // If true, we will finish the current animation instantly on second touch.
+    private boolean mFinishFastOnSecondTouch;
+
+
+    public PortraitStatesTouchController(Launcher l) {
+        super(l, SwipeDetector.VERTICAL);
+    }
+
+    @Override
+    protected boolean canInterceptTouch(MotionEvent ev) {
+        if (mCurrentAnimation != null) {
+            if (mFinishFastOnSecondTouch) {
+                // TODO: Animate to finish instead.
+                mCurrentAnimation.getAnimationPlayer().end();
+            }
+
+            AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
+            if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
+                // If we are already animating from a previous state, we can intercept as long as
+                // the touch is below the current all apps progress (to allow for double swipe).
+                return true;
+            }
+            // Otherwise, make sure everything is settled and don't intercept so they can scroll
+            // recents, dismiss a task, etc.
+            if (mAtomicAnim != null) {
+                mAtomicAnim.end();
+            }
+            return false;
+        }
+        if (mLauncher.isInState(ALL_APPS)) {
+            // In all-apps only listen if the container cannot scroll itself
+            if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
+                return false;
+            }
+        } else {
+            // For all other states, only listen if the event originated below the hotseat height
+            DeviceProfile dp = mLauncher.getDeviceProfile();
+            int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+            if (ev.getY() < (mLauncher.getDragLayer().getHeight() - hotseatHeight)) {
+                return false;
+            }
+        }
+        if (AbstractFloatingView.getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE) != null) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+        if (fromState == ALL_APPS && !isDragTowardPositive) {
+            // Should swipe down go to OVERVIEW instead?
+            return TouchInteractionService.isConnected() ?
+                    mLauncher.getStateManager().getLastState() : NORMAL;
+        } else if (fromState == OVERVIEW) {
+            return isDragTowardPositive ? ALL_APPS : NORMAL;
+        } else if (fromState == NORMAL && isDragTowardPositive) {
+            return TouchInteractionService.isConnected() ? OVERVIEW : ALL_APPS;
+        }
+        return fromState;
+    }
+
+    @Override
+    protected int getLogContainerTypeForNormalState() {
+        return ContainerType.HOTSEAT;
+    }
+
+    private AnimatorSetBuilder getNormalToOverviewAnimation() {
+        mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
+
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        builder.setInterpolator(ANIM_VERTICAL_PROGRESS, mAllAppsInterpolatorWrapper);
+        return builder;
+    }
+
+    public static AnimatorSetBuilder getOverviewToAllAppsAnimation() {
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
+                0, ALL_APPS_CONTENT_FADE_THRESHOLD));
+        builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(DEACCEL,
+                RECENTS_FADE_THRESHOLD, 1));
+        return builder;
+    }
+
+    private AnimatorSetBuilder getAllAppsToOverviewAnimation() {
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL,
+                1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1));
+        builder.setInterpolator(ANIM_OVERVIEW_FADE, Interpolators.clampToProgress(ACCEL,
+                0f, 1 - RECENTS_FADE_THRESHOLD));
+        return builder;
+    }
+
+    @Override
+    protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
+            LauncherState toState) {
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        if (fromState == NORMAL && toState == OVERVIEW) {
+            builder = getNormalToOverviewAnimation();
+        } else if (fromState == OVERVIEW && toState == ALL_APPS) {
+            builder = getOverviewToAllAppsAnimation();
+        } else if (fromState == ALL_APPS && toState == OVERVIEW) {
+            builder = getAllAppsToOverviewAnimation();
+        }
+        return builder;
+    }
+
+    @Override
+    protected float initCurrentAnimation(@AnimationComponents int animComponents) {
+        float range = getShiftRange();
+        long maxAccuracy = (long) (2 * range);
+
+        float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
+        float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
+
+        float totalShift = endVerticalShift - startVerticalShift;
+
+        final AnimatorSetBuilder builder = totalShift == 0 ? new AnimatorSetBuilder()
+                : getAnimatorSetBuilderForStates(mFromState, mToState);
+
+        cancelPendingAnim();
+
+        RecentsView recentsView = mLauncher.getOverviewPanel();
+        TaskView taskView = recentsView.getTaskViewAt(recentsView.getNextPage());
+        if (recentsView.shouldSwipeDownLaunchApp() && mFromState == OVERVIEW && mToState == NORMAL
+                && taskView != null) {
+            // Reset the state manager, when changing the interaction mode
+            mLauncher.getStateManager().goToState(OVERVIEW, false /* animate */);
+            mPendingAnimation = recentsView.createTaskLauncherAnimation(taskView, maxAccuracy);
+            mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
+
+            Runnable onCancelRunnable = () -> {
+                cancelPendingAnim();
+                clearState();
+            };
+            mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation.anim, maxAccuracy,
+                    onCancelRunnable);
+            mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
+        } else {
+            mCurrentAnimation = mLauncher.getStateManager()
+                    .createAnimationToNewWorkspace(mToState, builder, maxAccuracy, this::clearState,
+                            animComponents);
+        }
+
+        if (totalShift == 0) {
+            totalShift = Math.signum(mFromState.ordinal - mToState.ordinal)
+                    * OverviewState.getDefaultSwipeHeight(mLauncher);
+        }
+        return 1 / totalShift;
+    }
+
+    private void cancelPendingAnim() {
+        if (mPendingAnimation != null) {
+            mPendingAnimation.finish(false, Touch.SWIPE);
+            mPendingAnimation = null;
+        }
+    }
+
+    @Override
+    protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
+            LauncherState targetState, float velocity, boolean isFling) {
+        super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
+                velocity, isFling);
+        handleFirstSwipeToOverview(animator, expectedDuration, targetState, velocity, isFling);
+    }
+
+    private void handleFirstSwipeToOverview(final ValueAnimator animator,
+            final long expectedDuration, final LauncherState targetState, final float velocity,
+            final boolean isFling) {
+        if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
+            mFinishFastOnSecondTouch = true;
+            if (isFling && expectedDuration != 0) {
+                // Update all apps interpolator to add a bit of overshoot starting from currFraction
+                final float currFraction = mCurrentAnimation.getProgressFraction();
+                mAllAppsInterpolatorWrapper.baseInterpolator = Interpolators.clampToProgress(
+                        Interpolators.overshootInterpolatorForVelocity(velocity), currFraction, 1);
+                animator.setDuration(Math.min(expectedDuration, ATOMIC_DURATION))
+                        .setInterpolator(LINEAR);
+            }
+        } else {
+            mFinishFastOnSecondTouch = false;
+        }
+    }
+
+    @Override
+    protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+        super.onSwipeInteractionCompleted(targetState, logAction);
+        if (mStartState == NORMAL && targetState == OVERVIEW) {
+            RecentsModel.getInstance(mLauncher).onOverviewShown(true, TAG);
+        }
+    }
+
+    private static class InterpolatorWrapper implements Interpolator {
+
+        public TimeInterpolator baseInterpolator = LINEAR;
+
+        @Override
+        public float getInterpolation(float v) {
+            return baseInterpolator.getInterpolation(v);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 57e588b..abd2846 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,141 +15,90 @@
  */
 package com.android.launcher3.uioverrides;
 
-import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR;
+import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_TRANSLATION_Y_FACTOR;
+import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR;
+import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.view.View;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.PagedView;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.RecentsView;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.quickstep.views.LauncherRecentsView;
 
+@TargetApi(Build.VERSION_CODES.O)
 public class RecentsViewStateController implements StateHandler {
 
     private final Launcher mLauncher;
-    private final RecentsView mRecentsView;
-    private final WorkspaceCard mWorkspaceCard;
-
-    private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
-    // The fraction representing the visibility of the RecentsView. This allows delaying the
-    // overall transition while the RecentsView is being shown or hidden.
-    private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
-
-    private boolean mIsRecentsScrollingToFirstTask;
+    private final LauncherRecentsView mRecentsView;
 
     public RecentsViewStateController(Launcher launcher) {
         mLauncher = launcher;
         mRecentsView = launcher.getOverviewPanel();
-        mRecentsView.setStateController(this);
-
-        mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
-        mWorkspaceCard.setup(launcher);
     }
 
     @Override
     public void setState(LauncherState state) {
-        mWorkspaceCard.setWorkspaceScrollingEnabled(state == OVERVIEW);
-        setVisibility(state == OVERVIEW);
-        setTransitionProgress(state == OVERVIEW ? 1 : 0);
+        mRecentsView.setContentAlpha(state.overviewUi ? 1 : 0);
+        float[] scaleTranslationYFactor = state.getOverviewScaleAndTranslationYFactor(mLauncher);
+        SCALE_PROPERTY.set(mRecentsView, scaleTranslationYFactor[0]);
+        mRecentsView.setTranslationYFactor(scaleTranslationYFactor[1]);
+        if (state.overviewUi) {
+            mRecentsView.updateEmptyMessage();
+            mRecentsView.resetTaskVisuals();
+        }
     }
 
     @Override
     public void setStateWithAnimation(final LauncherState toState,
             AnimatorSetBuilder builder, AnimationConfig config) {
-        boolean settingEnabled = Utilities.getPrefs(mLauncher)
-            .getBoolean("pref_scroll_to_first_task", false);
-        mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW
-                && settingEnabled;
-        // TODO: Instead of animating the workspace translationX, move the contents
-        mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask);
+        if (!config.playAtomicComponent()) {
+            // The entire recents animation is played atomically.
+            return;
+        }
+        PropertySetter setter = config.getPropertySetter(builder);
+        float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher);
+        Interpolator scaleAndTransYInterpolator = builder.getInterpolator(
+                ANIM_OVERVIEW_SCALE, LINEAR);
+        if (mLauncher.getStateManager().getState() == OVERVIEW && toState == FAST_OVERVIEW) {
+            scaleAndTransYInterpolator = Interpolators.clampToProgress(
+                    QUICK_SCRUB_START_INTERPOLATOR, 0, QUICK_SCRUB_TRANSLATION_Y_FACTOR);
+        }
+        setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0],
+                scaleAndTransYInterpolator);
+        setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1],
+                scaleAndTransYInterpolator);
+        setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0,
+                builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
 
-        // Scroll to the workspace card before changing to the NORMAL state.
-        int currPage = mRecentsView.getCurrentPage();
-        if (toState == NORMAL && currPage != 0 && !config.userControlled) {
-            int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
-            int durationPerPage = maxSnapDuration / 10;
-            int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
-            mRecentsView.snapToPage(0, snapDuration);
-            builder.setStartDelay(snapDuration);
+        if (!toState.overviewUi) {
+            builder.addOnFinishRunnable(mRecentsView::resetTaskVisuals);
         }
 
-        ObjectAnimator progressAnim =
-                mTransitionProgress.animateToValue(toState == OVERVIEW ? 1 : 0);
-        progressAnim.setDuration(config.duration);
-        progressAnim.setInterpolator(Interpolators.LINEAR);
-        progressAnim.addListener(new AnimationSuccessListener() {
-
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                mWorkspaceCard.setWorkspaceScrollingEnabled(toState == OVERVIEW);
-                mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
-            }
-        });
-        builder.play(progressAnim);
-
-        ObjectAnimator visibilityAnim = animateVisibility(toState == OVERVIEW);
-        visibilityAnim.setDuration(config.duration);
-        visibilityAnim.setInterpolator(Interpolators.LINEAR);
-        builder.play(visibilityAnim);
-    }
-
-    public void setVisibility(boolean isVisible) {
-        mVisibilityMultiplier.cancelAnimation();
-        mRecentsView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
-        mVisibilityMultiplier.updateValue(isVisible ? 1 : 0);
-    }
-
-    public ObjectAnimator animateVisibility(boolean isVisible) {
-        ObjectAnimator anim = mVisibilityMultiplier.animateToValue(isVisible ? 1 : 0);
-        if (isVisible) {
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mRecentsView.setVisibility(View.VISIBLE);
-                }
+        if (toState.overviewUi) {
+            ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1);
+            updateAnim.addUpdateListener(valueAnimator -> {
+                // While animating into recents, update the visible task data as needed
+                mRecentsView.loadVisibleTaskData();
             });
-        } else {
-            anim.addListener(new AnimationSuccessListener() {
-                @Override
-                public void onAnimationSuccess(Animator animator) {
-                    mRecentsView.setVisibility(View.GONE);
-                }
-            });
+            updateAnim.setDuration(config.duration);
+            builder.play(updateAnim);
+            mRecentsView.updateEmptyMessage();
         }
-        return anim;
-    }
-
-    public void setTransitionProgress(float progress) {
-        mTransitionProgress.cancelAnimation();
-        mTransitionProgress.updateValue(progress);
-    }
-
-    private void onTransitionProgress() {
-        applyProgress();
-        if (mIsRecentsScrollingToFirstTask) {
-            int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
-            int scrollForPage0 = mRecentsView.getScrollForPage(0);
-            mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
-                    + (1 - mTransitionProgress.value) * scrollForPage0));
-        }
-    }
-
-    private void onVisibilityProgress() {
-        applyProgress();
-    }
-
-    private void applyProgress() {
-        mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java b/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
deleted file mode 100644
index 651a753..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/TaggedAnimatorSetBuilder.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import android.animation.Animator;
-import android.util.SparseArray;
-
-import com.android.launcher3.anim.AnimatorSetBuilder;
-
-import java.util.Collections;
-import java.util.List;
-
-public class TaggedAnimatorSetBuilder extends AnimatorSetBuilder {
-
-    /**
-     * Map of the index in {@link #mAnims} to tag. All the animations in {@link #mAnims} starting
-     * from this index correspond to the tag (until a new tag is specified for an index)
-     */
-    private final SparseArray<Object> mTags = new SparseArray<>();
-
-    @Override
-    public void startTag(Object obj) {
-        mTags.put(mAnims.size(), obj);
-    }
-
-    public List<Animator> getAnimationsForTag(Object tag) {
-        int startIndex = mTags.indexOfValue(tag);
-        if (startIndex < 0) {
-            return Collections.emptyList();
-        }
-        int startPos = mTags.keyAt(startIndex);
-
-        int endIndex = startIndex + 1;
-        int endPos = endIndex >= mTags.size() ? mAnims.size() : mTags.keyAt(endIndex);
-
-        return mAnims.subList(startPos, endPos);
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
new file mode 100644
index 0000000..9a920c8
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.FlingBlockCheck;
+import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+
+/**
+ * Touch controller for handling task view card swipes
+ */
+public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
+        extends AnimatorListenerAdapter implements TouchController, SwipeDetector.Listener {
+
+    private static final String TAG = "OverviewSwipeController";
+
+    // Progress after which the transition is assumed to be a success in case user does not fling
+    private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
+
+    protected final T mActivity;
+    private final SwipeDetector mDetector;
+    private final RecentsView mRecentsView;
+    private final int[] mTempCords = new int[2];
+
+    private PendingAnimation mPendingAnimation;
+    private AnimatorPlaybackController mCurrentAnimation;
+    private boolean mCurrentAnimationIsGoingUp;
+
+    private boolean mNoIntercept;
+
+    private float mDisplacementShift;
+    private float mProgressMultiplier;
+    private float mEndDisplacement;
+    private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
+
+    private TaskView mTaskBeingDragged;
+
+    public TaskViewTouchController(T activity) {
+        mActivity = activity;
+        mRecentsView = activity.getOverviewPanel();
+        mDetector = new SwipeDetector(activity, this, SwipeDetector.VERTICAL);
+    }
+
+    private boolean canInterceptTouch() {
+        if (mCurrentAnimation != null) {
+            // If we are already animating from a previous state, we can intercept.
+            return true;
+        }
+        if (AbstractFloatingView.getTopOpenViewWithType(mActivity, TYPE_ACCESSIBLE) != null) {
+            return false;
+        }
+        return isRecentsInteractive();
+    }
+
+    protected abstract boolean isRecentsInteractive();
+
+    protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animation) {
+        if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
+            clearState();
+        }
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mNoIntercept = !canInterceptTouch();
+            if (mNoIntercept) {
+                return false;
+            }
+
+            // Now figure out which direction scroll events the controller will start
+            // calling the callbacks.
+            int directionsToDetectScroll = 0;
+            boolean ignoreSlopWhenSettling = false;
+            if (mCurrentAnimation != null) {
+                directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+                ignoreSlopWhenSettling = true;
+            } else {
+                mTaskBeingDragged = null;
+
+                for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) {
+                    TaskView view = mRecentsView.getTaskViewAt(i);
+                    if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
+                            .isEventOverView(view, ev)) {
+                        mTaskBeingDragged = view;
+                        if (!OverviewInteractionState.getInstance(mActivity)
+                                .isSwipeUpGestureEnabled()) {
+                            // Don't allow swipe down to open if we don't support swipe up
+                            // to enter overview.
+                            directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+                        } else {
+                            // The task can be dragged up to dismiss it,
+                            // and down to open if it's the current page.
+                            directionsToDetectScroll = i == mRecentsView.getCurrentPage()
+                                    ? SwipeDetector.DIRECTION_BOTH : SwipeDetector.DIRECTION_POSITIVE;
+                        }
+                        break;
+                    }
+                }
+                if (mTaskBeingDragged == null) {
+                    mNoIntercept = true;
+                    return false;
+                }
+            }
+
+            mDetector.setDetectableScrollConditions(
+                    directionsToDetectScroll, ignoreSlopWhenSettling);
+        }
+
+        if (mNoIntercept) {
+            return false;
+        }
+
+        onControllerTouchEvent(ev);
+        return mDetector.isDraggingOrSettling();
+    }
+
+    @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        return mDetector.onTouchEvent(ev);
+    }
+
+    private void reInitAnimationController(boolean goingUp) {
+        if (mCurrentAnimation != null && mCurrentAnimationIsGoingUp == goingUp) {
+            // No need to init
+            return;
+        }
+        int scrollDirections = mDetector.getScrollDirections();
+        if (goingUp && ((scrollDirections & SwipeDetector.DIRECTION_POSITIVE) == 0)
+                || !goingUp && ((scrollDirections & SwipeDetector.DIRECTION_NEGATIVE) == 0)) {
+            // Trying to re-init in an unsupported direction.
+            return;
+        }
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.setPlayFraction(0);
+        }
+        if (mPendingAnimation != null) {
+            mPendingAnimation.finish(false, Touch.SWIPE);
+            mPendingAnimation = null;
+        }
+
+        mCurrentAnimationIsGoingUp = goingUp;
+        BaseDragLayer dl = mActivity.getDragLayer();
+        long maxDuration = (long) (2 * dl.getHeight());
+
+        if (goingUp) {
+            mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
+                    true /* animateTaskView */, true /* removeTask */, maxDuration);
+
+            mEndDisplacement = -mTaskBeingDragged.getHeight();
+        } else {
+            mPendingAnimation = mRecentsView.createTaskLauncherAnimation(
+                    mTaskBeingDragged, maxDuration);
+            mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
+
+            mTempCords[1] = mTaskBeingDragged.getHeight();
+            dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
+            mEndDisplacement = dl.getHeight() - mTempCords[1];
+        }
+
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.setOnCancelRunnable(null);
+        }
+        mCurrentAnimation = AnimatorPlaybackController
+                .wrap(mPendingAnimation.anim, maxDuration, this::clearState);
+        onUserControlledAnimationCreated(mCurrentAnimation);
+        mCurrentAnimation.getTarget().addListener(this);
+        mCurrentAnimation.dispatchOnStart();
+        mProgressMultiplier = 1 / mEndDisplacement;
+    }
+
+    @Override
+    public void onDragStart(boolean start) {
+        if (mCurrentAnimation == null) {
+            reInitAnimationController(mDetector.wasInitialTouchPositive());
+            mDisplacementShift = 0;
+        } else {
+            mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
+            mCurrentAnimation.pause();
+        }
+        mFlingBlockCheck.unblockFling();
+    }
+
+    @Override
+    public boolean onDrag(float displacement, float velocity) {
+        float totalDisplacement = displacement + mDisplacementShift;
+        boolean isGoingUp =
+                totalDisplacement == 0 ? mCurrentAnimationIsGoingUp : totalDisplacement < 0;
+        if (isGoingUp != mCurrentAnimationIsGoingUp) {
+            reInitAnimationController(isGoingUp);
+            mFlingBlockCheck.blockFling();
+        } else {
+            mFlingBlockCheck.onEvent();
+        }
+        mCurrentAnimation.setPlayFraction(totalDisplacement * mProgressMultiplier);
+        return true;
+    }
+
+    @Override
+    public void onDragEnd(float velocity, boolean fling) {
+        final boolean goingToEnd;
+        final int logAction;
+        boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
+        if (blockedFling) {
+            fling = false;
+        }
+        float progress = mCurrentAnimation.getProgressFraction();
+        float interpolatedProgress = mCurrentAnimation.getInterpolator().getInterpolation(progress);
+        if (fling) {
+            logAction = Touch.FLING;
+            boolean goingUp = velocity < 0;
+            goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
+        } else {
+            logAction = Touch.SWIPE;
+            goingToEnd = interpolatedProgress > SUCCESS_TRANSITION_PROGRESS;
+        }
+        long animationDuration = SwipeDetector.calculateDuration(
+                velocity, goingToEnd ? (1 - progress) : progress);
+        if (blockedFling && !goingToEnd) {
+            animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
+        }
+
+        float nextFrameProgress = Utilities.boundToRange(
+                progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f);
+
+        mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction));
+
+        ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+        anim.setFloatValues(nextFrameProgress, goingToEnd ? 1f : 0f);
+        anim.setDuration(animationDuration);
+        anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
+        anim.start();
+    }
+
+    private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
+        if (mPendingAnimation != null) {
+            mPendingAnimation.finish(wasSuccess, logAction);
+            mPendingAnimation = null;
+        }
+        clearState();
+    }
+
+    private void clearState() {
+        mDetector.finishedScrolling();
+        mDetector.setDetectableScrollConditions(0, false);
+        mTaskBeingDragged = null;
+        mCurrentAnimation = null;
+        if (mPendingAnimation != null) {
+            mPendingAnimation.finish(false, Touch.SWIPE);
+            mPendingAnimation = null;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
deleted file mode 100644
index fb59946..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
-import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.support.animation.SpringAnimation;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
-import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.FloatRange;
-import com.android.launcher3.util.TouchController;
-import com.android.quickstep.RecentsModel;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.TouchInteractionService;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-
-import java.util.ArrayList;
-
-/**
- * Handles vertical touch gesture on the DragLayer
- */
-public class TwoStepSwipeController extends AnimatorListenerAdapter
-        implements TouchController, SwipeDetector.Listener {
-
-    private static final String TAG = "TwoStepSwipeController";
-
-    private static final float RECATCH_REJECTION_FRACTION = .0875f;
-    private static final int SINGLE_FRAME_MS = 16;
-    private static final long QUICK_SNAP_TO_OVERVIEW_DURATION = 250;
-
-    // Progress after which the transition is assumed to be a success in case user does not fling
-    private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
-    /**
-     * Index of the vertical swipe handles in {@link LauncherStateManager#getStateHandlers()}.
-     */
-    private static final int SWIPE_HANDLER_INDEX = 0;
-
-    /**
-     * Index of various UI handlers in {@link LauncherStateManager#getStateHandlers()} not related
-     * to vertical swipe.
-     */
-    private static final int OTHER_HANDLERS_START_INDEX = SWIPE_HANDLER_INDEX + 1;
-
-    // Swipe progress range (when starting from NORMAL state) where OVERVIEW state is allowed
-    private static final float MIN_PROGRESS_TO_OVERVIEW = 0.1f;
-    private static final float MAX_PROGRESS_TO_OVERVIEW = 0.4f;
-
-    private static final int FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE = 1 << 0;
-    private static final int FLAG_OVERVIEW_DISABLED_FLING = 1 << 1;
-    private static final int FLAG_OVERVIEW_DISABLED_CANCEL_STATE = 1 << 2;
-    private static final int FLAG_OVERVIEW_DISABLED = 1 << 4;
-    private static final int FLAG_DISABLED_TWO_TARGETS = 1 << 5;
-    private static final int FLAG_DISABLED_BACK_TARGET = 1 << 6;
-
-    private final Launcher mLauncher;
-    private final SwipeDetector mDetector;
-
-    private boolean mNoIntercept;
-    private int mStartContainerType;
-
-    private DragPauseDetector mDragPauseDetector;
-    private FloatRange mOverviewProgressRange;
-    private TaggedAnimatorSetBuilder mTaggedAnimatorSetBuilder;
-    private AnimatorSet mQuickOverviewAnimation;
-    private boolean mAnimatingToOverview;
-    private CroppedAnimationController mCroppedAnimationController;
-
-    private AnimatorPlaybackController mCurrentAnimation;
-    private LauncherState mFromState;
-    private LauncherState mToState;
-
-    private float mStartProgress;
-    // Ratio of transition process [0, 1] to drag displacement (px)
-    private float mProgressMultiplier;
-
-    private SpringAnimationHandler[] mSpringHandlers;
-
-    public TwoStepSwipeController(Launcher l) {
-        mLauncher = l;
-        mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
-    }
-
-    private boolean canInterceptTouch(MotionEvent ev) {
-        if (mCurrentAnimation != null) {
-            // If we are already animating from a previous state, we can intercept.
-            return true;
-        }
-        if (mLauncher.isInState(NORMAL)) {
-            if ((ev.getEdgeFlags() & EDGE_NAV_BAR) != 0 &&
-                    !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-                // On normal swipes ignore edge swipes
-                return false;
-            }
-        } else if (mLauncher.isInState(ALL_APPS)) {
-            if (!mLauncher.getAppsView().shouldContainerScroll(ev)) {
-                return false;
-            }
-        } else {
-            // Don't listen for the swipe gesture if we are already in some other state.
-            return false;
-        }
-        if (mAnimatingToOverview) {
-            return false;
-        }
-        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public void onAnimationCancel(Animator animation) {
-        if (mCurrentAnimation != null && animation == mCurrentAnimation.getOriginalTarget()) {
-            Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
-            clearState();
-        }
-    }
-
-    private void initSprings() {
-        AllAppsContainerView appsView = mLauncher.getAppsView();
-
-        SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
-        if (handler == null) {
-            mSpringHandlers = new SpringAnimationHandler[0];
-            return;
-        }
-
-        ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
-        handlers.add(handler);
-
-        SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
-        if (searchSpring != null) {
-            SpringAnimationHandler searchHandler =
-                    new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
-            searchHandler.add(searchSpring, true /* setDefaultValues */);
-            handlers.add(searchHandler);
-        }
-
-        mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mNoIntercept = !canInterceptTouch(ev);
-            if (mNoIntercept) {
-                return false;
-            }
-
-            // Now figure out which direction scroll events the controller will start
-            // calling the callbacks.
-            final int directionsToDetectScroll;
-            boolean ignoreSlopWhenSettling = false;
-
-            if (mCurrentAnimation != null) {
-                if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
-                } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
-                } else {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
-                    ignoreSlopWhenSettling = true;
-                }
-            } else {
-                if (mLauncher.isInState(ALL_APPS)) {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
-                    mStartContainerType = ContainerType.ALLAPPS;
-                } else {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
-                    mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
-                            ContainerType.HOTSEAT : ContainerType.WORKSPACE;
-                }
-            }
-
-            mDetector.setDetectableScrollConditions(
-                    directionsToDetectScroll, ignoreSlopWhenSettling);
-
-            if (mSpringHandlers == null) {
-                initSprings();
-            }
-        }
-
-        if (mNoIntercept) {
-            return false;
-        }
-
-        onControllerTouchEvent(ev);
-        return mDetector.isDraggingOrSettling();
-    }
-
-    @Override
-    public boolean onControllerTouchEvent(MotionEvent ev) {
-        for (SpringAnimationHandler h : mSpringHandlers) {
-            h.addMovement(ev);
-        }
-        return mDetector.onTouchEvent(ev);
-    }
-
-    @Override
-    public void onDragStart(boolean start) {
-        if (mCurrentAnimation == null) {
-            float range = getShiftRange();
-            long maxAccuracy = (long) (2 * range);
-
-            mDragPauseDetector = new DragPauseDetector(this::onDragPauseDetected);
-            mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
-            if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
-                mDragPauseDetector.addDisabledFlags(FLAG_DISABLED_TWO_TARGETS);
-            }
-
-            mOverviewProgressRange = new FloatRange();
-            mOverviewProgressRange.start = mLauncher.isInState(NORMAL)
-                    ? MIN_PROGRESS_TO_OVERVIEW
-                    : 1 - MAX_PROGRESS_TO_OVERVIEW;
-            mOverviewProgressRange.end = mOverviewProgressRange.start
-                    + MAX_PROGRESS_TO_OVERVIEW - MIN_PROGRESS_TO_OVERVIEW;
-
-            // Build current animation
-            mFromState = mLauncher.getStateManager().getState();
-            mToState = mLauncher.isInState(ALL_APPS) ? NORMAL : ALL_APPS;
-
-            if (mToState == NORMAL && mLauncher.getStateManager().getLastState() == OVERVIEW) {
-                mToState = OVERVIEW;
-                mDragPauseDetector.addDisabledFlags(FLAG_DISABLED_BACK_TARGET);
-            }
-
-            mTaggedAnimatorSetBuilder = new TaggedAnimatorSetBuilder();
-            mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(
-                    mToState, mTaggedAnimatorSetBuilder, maxAccuracy);
-
-            if (!TouchInteractionService.isConnected()) {
-                mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED);
-            }
-
-            mCurrentAnimation.getTarget().addListener(this);
-            mStartProgress = 0;
-            mProgressMultiplier = (mLauncher.isInState(ALL_APPS) ? 1 : -1) / range;
-            mCurrentAnimation.dispatchOnStart();
-        } else {
-            mCurrentAnimation.pause();
-            mStartProgress = mCurrentAnimation.getProgressFraction();
-
-            mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
-            updatePauseDetectorRangeFlag();
-        }
-
-        for (SpringAnimationHandler h : mSpringHandlers) {
-            h.skipToEnd();
-        }
-    }
-
-    private float getShiftRange() {
-        return mLauncher.getAllAppsController().getShiftRange();
-    }
-
-    @Override
-    public boolean onDrag(float displacement, float velocity) {
-        float deltaProgress = mProgressMultiplier * displacement;
-        mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
-
-        updatePauseDetectorRangeFlag();
-        mDragPauseDetector.onDrag(velocity);
-
-        return true;
-    }
-
-    private void updatePauseDetectorRangeFlag() {
-        if (mOverviewProgressRange.contains(mCurrentAnimation.getProgressFraction())) {
-            mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
-        } else {
-            mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_OUT_OF_RANGE);
-        }
-    }
-
-    @Override
-    public void onDragEnd(float velocity, boolean fling) {
-        mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
-
-        final int logAction;
-        LauncherState targetState;
-        final float progress = mCurrentAnimation.getProgressFraction();
-
-        if (fling) {
-            logAction = Touch.FLING;
-            targetState = velocity < 0 ? ALL_APPS : mLauncher.getStateManager().getLastState();
-            // snap to top or bottom using the release velocity
-        } else {
-            logAction = Touch.SWIPE;
-            targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
-        }
-
-        if (fling && targetState == ALL_APPS) {
-            for (SpringAnimationHandler h : mSpringHandlers) {
-                // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
-                h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
-            }
-        }
-
-        float endProgress;
-
-        if (mDragPauseDetector.isTriggered() && targetState == NORMAL) {
-            targetState = OVERVIEW;
-            endProgress = OVERVIEW.getVerticalProgress(mLauncher);
-            if (mFromState == NORMAL) {
-                endProgress = 1 - endProgress;
-            }
-        } else if (targetState == mToState) {
-            endProgress = 1;
-        } else {
-            endProgress = 0;
-        }
-
-        LauncherState targetStateFinal = targetState;
-        mCurrentAnimation.setEndAction(() ->
-                onSwipeInteractionCompleted(targetStateFinal, logAction));
-
-        float nextFrameProgress = Utilities.boundToRange(
-                progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
-
-        ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
-        anim.setFloatValues(nextFrameProgress, endProgress);
-        anim.setDuration(
-                SwipeDetector.calculateDuration(velocity, Math.abs(endProgress - progress)));
-        anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
-        anim.start();
-    }
-
-    private void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
-        if (targetState != mFromState) {
-            // Transition complete. log the action
-            mLauncher.getUserEventDispatcher().logActionOnContainer(logAction,
-                    mToState == ALL_APPS ? Direction.UP : Direction.DOWN,
-                    mStartContainerType, mLauncher.getWorkspace().getCurrentPage());
-        }
-        clearState();
-
-        // TODO: mQuickOverviewAnimation might still be running in which changing a state instantly
-        // may cause a jump. Animate the state change with a short duration in this case?
-        mLauncher.getStateManager().goToState(targetState, false /* animated */);
-    }
-
-    private void onDragPauseDetected() {
-        final ValueAnimator twoStepAnimator = ValueAnimator.ofFloat(0, 1);
-        twoStepAnimator.setDuration(mCurrentAnimation.getDuration());
-        StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
-
-        // Change the current animation to only play the vertical handle
-        AnimatorSet anim = new AnimatorSet();
-        anim.playTogether(mTaggedAnimatorSetBuilder.getAnimationsForTag(
-                handlers[SWIPE_HANDLER_INDEX]));
-        anim.play(twoStepAnimator);
-        mCurrentAnimation = mCurrentAnimation.cloneFor(anim);
-
-        AnimatorSetBuilder builder = new AnimatorSetBuilder();
-        AnimationConfig config = new AnimationConfig();
-        config.duration = QUICK_SNAP_TO_OVERVIEW_DURATION;
-        for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
-            handlers[i].setStateWithAnimation(OVERVIEW, builder, config);
-        }
-        mQuickOverviewAnimation = builder.build();
-        mQuickOverviewAnimation.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                onQuickOverviewAnimationComplete(twoStepAnimator);
-            }
-        });
-        mQuickOverviewAnimation.start();
-    }
-
-    private void onQuickOverviewAnimationComplete(ValueAnimator animator) {
-        if (mAnimatingToOverview) {
-            return;
-        }
-
-        // For the remainder to the interaction, the user can either go to the ALL_APPS state or
-        // the OVERVIEW state.
-        // The remaining state handlers are on the OVERVIEW state. Create one animation towards the
-        // ALL_APPS state and only call it when the user moved above the current range.
-        AnimationConfig config = new AnimationConfig();
-        config.duration = (long) (2 * getShiftRange());
-        config.userControlled = true;
-
-        AnimatorSetBuilder builderToAllAppsState = new AnimatorSetBuilder();
-        StateHandler[] handlers = mLauncher.getStateManager().getStateHandlers();
-        for (int i = OTHER_HANDLERS_START_INDEX; i < handlers.length; i++) {
-            handlers[i].setStateWithAnimation(ALL_APPS, builderToAllAppsState, config);
-        }
-
-        mCroppedAnimationController = new CroppedAnimationController(
-                AnimatorPlaybackController.wrap(builderToAllAppsState.build(), config.duration),
-                new FloatRange(animator.getAnimatedFraction(), mToState == ALL_APPS ? 1 : 0));
-        animator.addUpdateListener(mCroppedAnimationController);
-    }
-
-    private void clearState() {
-        mCurrentAnimation = null;
-        mTaggedAnimatorSetBuilder = null;
-        if (mDragPauseDetector != null) {
-            mDragPauseDetector.addDisabledFlags(FLAG_OVERVIEW_DISABLED_CANCEL_STATE);
-        }
-        mDragPauseDetector = null;
-
-        if (mQuickOverviewAnimation != null) {
-            mQuickOverviewAnimation.cancel();
-            mQuickOverviewAnimation = null;
-        }
-        mCroppedAnimationController = null;
-        mAnimatingToOverview = false;
-
-        mDetector.finishedScrolling();
-    }
-
-    /**
-     * {@link AnimatorUpdateListener} which controls another animation for a fraction of range
-     */
-    private static class CroppedAnimationController implements AnimatorUpdateListener {
-
-        private final AnimatorPlaybackController mTarget;
-        private final FloatRange mRange;
-
-        CroppedAnimationController(AnimatorPlaybackController target, FloatRange range) {
-            mTarget = target;
-            mRange = range;
-        }
-
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator valueAnimator) {
-            float fraction = valueAnimator.getAnimatedFraction();
-
-            if (mRange.start < mRange.end) {
-                if (fraction <= mRange.start) {
-                    mTarget.setPlayFraction(0);
-                } else if (fraction >= mRange.end) {
-                    mTarget.setPlayFraction(1);
-                } else {
-                    mTarget.setPlayFraction((fraction - mRange.start) / (mRange.end - mRange.start));
-                }
-            } else if (mRange.start > mRange.end) {
-                if (fraction >= mRange.start) {
-                    mTarget.setPlayFraction(0);
-                } else if (fraction <= mRange.end) {
-                    mTarget.setPlayFraction(1);
-                } else {
-                    mTarget.setPlayFraction((fraction - mRange.start) / (mRange.end - mRange.start));
-                }
-            } else {
-                // mRange.start == mRange.end
-                mTarget.setPlayFraction(0);
-            }
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 7bd4366..2d0946b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,76 +16,247 @@
 
 package com.android.launcher3.uioverrides;
 
+import static android.view.View.VISIBLE;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
+import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN;
 
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PointF;
-import android.view.View.AccessibilityDelegate;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.os.CancellationSignal;
+import android.util.Base64;
 
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppTransitionManagerImpl;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.BitmapRenderer;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.OverviewInteractionState;
-import com.android.quickstep.RecentsView;
-import com.android.systemui.shared.recents.view.RecentsTransition;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.util.RemoteFadeOutAnimationListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.ActivityCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+import java.util.zip.Deflater;
 
 public class UiFactory {
 
-    private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
-            "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
-
-    public static final boolean USE_HARDWARE_BITMAP = false; // FeatureFlags.IS_DOGFOOD_BUILD;
-
     public static TouchController[] createTouchControllers(Launcher launcher) {
-        if (FeatureFlags.ENABLE_TWO_SWIPE_TARGETS) {
+        boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+                .isSwipeUpGestureEnabled();
+        if (!swipeUpEnabled) {
             return new TouchController[] {
-                    new IgnoreTouchesInQuickScrub(),
-                    new EdgeSwipeController(launcher),
-                    new TwoStepSwipeController(launcher),
-                    new OverviewSwipeController(launcher)};
+                    launcher.getDragController(),
+                    new OverviewToAllAppsTouchController(launcher),
+                    new LauncherTaskViewController(launcher)};
+        }
+        if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+            return new TouchController[] {
+                    launcher.getDragController(),
+                    new OverviewToAllAppsTouchController(launcher),
+                    new LandscapeEdgeSwipeController(launcher),
+                    new LauncherTaskViewController(launcher)};
         } else {
             return new TouchController[] {
-                    new IgnoreTouchesInQuickScrub(),
-                    new TwoStepSwipeController(launcher),
-                    new OverviewSwipeController(launcher)};
+                    launcher.getDragController(),
+                    new PortraitStatesTouchController(launcher),
+                    new LauncherTaskViewController(launcher)};
         }
     }
 
-    public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
-        return null;
+    public static void setOnTouchControllersChangedListener(Context context, Runnable listener) {
+        OverviewInteractionState.getInstance(context).setOnSwipeUpSettingChangedListener(listener);
     }
 
     public static StateHandler[] getStateHandler(Launcher launcher) {
-        return new StateHandler[] {
-                launcher.getAllAppsController(), launcher.getWorkspace(),
-                new RecentsViewStateController(launcher)};
+        return new StateHandler[] {launcher.getAllAppsController(), launcher.getWorkspace(),
+                new RecentsViewStateController(launcher), new BackButtonAlphaHandler(launcher)};
     }
 
-    public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
-        OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y);
-    }
-
+    /**
+     * Sets the back button visibility based on the current state/window focus.
+     */
     public static void onLauncherStateOrFocusChanged(Launcher launcher) {
-        OverviewInteractionState.setBackButtonVisible(launcher, launcher == null
-                || !launcher.isInState(NORMAL) || !launcher.hasWindowFocus());
-    }
-
-    public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
-            BitmapRenderer renderer) {
-        if (USE_HARDWARE_BITMAP && !forceSoftwareRenderer) {
-            return RecentsTransition.createHardwareBitmap(width, height, renderer::render);
-        } else {
-            Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-            renderer.render(new Canvas(result));
-            return result;
+        boolean shouldBackButtonBeHidden = launcher != null
+                && launcher.getStateManager().getState().hideBackButton
+                && launcher.hasWindowFocus();
+        if (shouldBackButtonBeHidden) {
+            // Show the back button if there is a floating view visible.
+            shouldBackButtonBeHidden = AbstractFloatingView.getTopOpenViewWithType(launcher,
+                    TYPE_ALL & ~TYPE_HIDE_BACK_BUTTON) == null;
         }
+        OverviewInteractionState.getInstance(launcher)
+                .setBackButtonAlpha(shouldBackButtonBeHidden ? 0 : 1, true /* animate */);
     }
 
     public static void resetOverview(Launcher launcher) {
         RecentsView recents = launcher.getOverviewPanel();
         recents.reset();
     }
+
+    public static void onCreate(Launcher launcher) {
+        if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
+            launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
+                @Override
+                public void onStateSetImmediately(LauncherState state) {
+                }
+
+                @Override
+                public void onStateTransitionStart(LauncherState toState) {
+                }
+
+                @Override
+                public void onStateTransitionComplete(LauncherState finalState) {
+                    boolean swipeUpEnabled = OverviewInteractionState.getInstance(launcher)
+                            .isSwipeUpGestureEnabled();
+                    LauncherState prevState = launcher.getStateManager().getLastState();
+
+                    if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
+                            && finalState == ALL_APPS && prevState == NORMAL))) {
+                        launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
+                        launcher.getStateManager().removeStateListener(this);
+                    }
+                }
+            });
+        }
+
+        if (!launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)) {
+            launcher.getStateManager().addStateListener(new LauncherStateManager.StateListener() {
+                @Override
+                public void onStateSetImmediately(LauncherState state) {
+                }
+
+                @Override
+                public void onStateTransitionStart(LauncherState toState) {
+                }
+
+                @Override
+                public void onStateTransitionComplete(LauncherState finalState) {
+                    LauncherState prevState = launcher.getStateManager().getLastState();
+
+                    if (finalState == ALL_APPS && prevState == OVERVIEW) {
+                        launcher.getSharedPrefs().edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
+                        launcher.getStateManager().removeStateListener(this);
+                    }
+                }
+            });
+        }
+    }
+
+    public static void onStart(Context context) {
+        RecentsModel model = RecentsModel.getInstance(context);
+        if (model != null) {
+            model.onStart();
+        }
+    }
+
+    public static void onEnterAnimationComplete(Context context) {
+        // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
+        // as a part of quickstep/scrub, so that high-res thumbnails can load the next time we
+        // enter overview
+        RecentsModel.getInstance(context).getRecentsTaskLoader()
+                .getHighResThumbnailLoader().setVisible(true);
+    }
+
+    public static void onLauncherStateOrResumeChanged(Launcher launcher) {
+        LauncherState state = launcher.getStateManager().getState();
+        DeviceProfile profile = launcher.getDeviceProfile();
+        WindowManagerWrapper.getInstance().setShelfHeight(
+                (state == NORMAL || state == OVERVIEW) && launcher.isUserActive()
+                        && !profile.isVerticalBarLayout(),
+                profile.hotseatBarSizePx);
+
+        if (state == NORMAL) {
+            launcher.<RecentsView>getOverviewPanel().setSwipeDownShouldLaunchApp(false);
+        }
+    }
+
+    public static void onTrimMemory(Context context, int level) {
+        RecentsModel model = RecentsModel.getInstance(context);
+        if (model != null) {
+            model.onTrimMemory(level);
+        }
+    }
+
+    public static void useFadeOutAnimationForLauncherStart(Launcher launcher,
+            CancellationSignal cancellationSignal) {
+        LauncherAppTransitionManagerImpl appTransitionManager =
+                (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager();
+        appTransitionManager.setRemoteAnimationProvider((targets) -> {
+
+            // On the first call clear the reference.
+            cancellationSignal.cancel();
+
+            ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
+            fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(targets));
+            AnimatorSet anim = new AnimatorSet();
+            anim.play(fadeAnimation);
+            return anim;
+        }, cancellationSignal);
+    }
+
+    public static boolean dumpActivity(Activity activity, PrintWriter writer) {
+        if (!Utilities.IS_DEBUG_DEVICE) {
+            return false;
+        }
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        if (!(new ActivityCompat(activity).encodeViewHierarchy(out))) {
+            return false;
+        }
+
+        Deflater deflater = new Deflater();
+        deflater.setInput(out.toByteArray());
+        deflater.finish();
+
+        out.reset();
+        byte[] buffer = new byte[1024];
+        while (!deflater.finished()) {
+            int count = deflater.deflate(buffer); // returns the generated code... index
+            out.write(buffer, 0, count);
+        }
+
+        writer.println("--encoded-view-dump-v0--");
+        writer.println(Base64.encodeToString(
+                out.toByteArray(), Base64.NO_WRAP | Base64.NO_PADDING));
+        return true;
+    }
+
+    public static void prepareToShowOverview(Launcher launcher) {
+        RecentsView overview = launcher.getOverviewPanel();
+        if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
+            SCALE_PROPERTY.set(overview, 1.33f);
+        }
+    }
+
+    private static class LauncherTaskViewController extends TaskViewTouchController<Launcher> {
+
+        public LauncherTaskViewController(Launcher activity) {
+            super(activity);
+        }
+
+        @Override
+        protected boolean isRecentsInteractive() {
+            return mActivity.isInState(OVERVIEW);
+        }
+
+        @Override
+        protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
+            mActivity.getStateManager().setCurrentUserControlledAnimation(animController);
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
new file mode 100644
index 0000000..8218517
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+import android.annotation.TargetApi;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
+import android.app.WallpaperManager.OnColorsChangedListener;
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.systemui.shared.system.TonalCompat;
+import com.android.systemui.shared.system.TonalCompat.ExtractionInfo;
+
+import java.util.ArrayList;
+
+@TargetApi(Build.VERSION_CODES.P)
+public class WallpaperColorInfo implements OnColorsChangedListener {
+
+    private static final Object sInstanceLock = new Object();
+    private static WallpaperColorInfo sInstance;
+
+    public static WallpaperColorInfo getInstance(Context context) {
+        synchronized (sInstanceLock) {
+            if (sInstance == null) {
+                sInstance = new WallpaperColorInfo(context.getApplicationContext());
+            }
+            return sInstance;
+        }
+    }
+
+    private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
+    private final WallpaperManager mWallpaperManager;
+    private final TonalCompat mTonalCompat;
+
+    private ExtractionInfo mExtractionInfo;
+
+    private OnChangeListener[] mTempListeners = new OnChangeListener[0];
+
+    private WallpaperColorInfo(Context context) {
+        mWallpaperManager = context.getSystemService(WallpaperManager.class);
+        mTonalCompat = new TonalCompat(context);
+
+        mWallpaperManager.addOnColorsChangedListener(this, new Handler(Looper.getMainLooper()));
+        update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
+    }
+
+    public int getMainColor() {
+        return mExtractionInfo.mainColor;
+    }
+
+    public int getSecondaryColor() {
+        return mExtractionInfo.secondaryColor;
+    }
+
+    public boolean isDark() {
+        return mExtractionInfo.supportsDarkTheme;
+    }
+
+    public boolean supportsDarkText() {
+        return mExtractionInfo.supportsDarkText;
+    }
+
+    @Override
+    public void onColorsChanged(WallpaperColors colors, int which) {
+        if ((which & FLAG_SYSTEM) != 0) {
+            update(colors);
+            notifyChange();
+        }
+    }
+
+    private void update(WallpaperColors wallpaperColors) {
+        mExtractionInfo = mTonalCompat.extractDarkColors(wallpaperColors);
+    }
+
+    public void addOnChangeListener(OnChangeListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeOnChangeListener(OnChangeListener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void notifyChange() {
+        // Create a new array to avoid concurrent modification when the activity destroys itself.
+        mTempListeners = mListeners.toArray(mTempListeners);
+        for (OnChangeListener listener : mTempListeners) {
+            if (listener != null) {
+                listener.onExtractedColorsChanged(this);
+            }
+        }
+    }
+
+    public interface OnChangeListener {
+        void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
deleted file mode 100644
index 8533502..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
-
-public class WorkspaceCard extends View implements PageCallbacks, OnClickListener {
-
-    private final Rect mTempRect = new Rect();
-
-    private Launcher mLauncher;
-    private Workspace mWorkspace;
-
-    private float mLinearInterpolationForPage2 = 1;
-    private float mTranslateXPage0, mTranslateXPage1;
-    private float mExtraScrollShift;
-
-    private boolean mIsWorkspaceScrollingEnabled;
-
-    public WorkspaceCard(Context context) {
-        this(context, null);
-    }
-
-    public WorkspaceCard(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public WorkspaceCard(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setOnClickListener(this);
-    }
-
-    /**
-     * Draw nothing.
-     */
-    @Override
-    public void draw(Canvas canvas) { }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        // Initiate data
-        mLinearInterpolationForPage2 = RecentsView.getScaledDownPageRect(
-                mLauncher.getDeviceProfile(), mLauncher, mTempRect);
-
-        float[] scale = OverviewState.getScaleAndTranslationForPageRect(mLauncher, 0, mTempRect);
-        mTranslateXPage0 = scale[1];
-        mTranslateXPage1 = OverviewState
-                .getScaleAndTranslationForPageRect(mLauncher,
-                        getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
-                        mTempRect)[1];
-
-        mExtraScrollShift = 0;
-        if (mWorkspace != null && getWidth() > 0) {
-            float workspaceWidth = mWorkspace.getNormalChildWidth() * scale[0];
-            mExtraScrollShift = (workspaceWidth - getWidth()) / 2;
-            setScaleX(workspaceWidth / getWidth());
-        }
-    }
-
-    @Override
-    public void onClick(View view) {
-        mLauncher.getStateManager().goToState(NORMAL);
-    }
-
-    public void setup(Launcher launcher) {
-        mLauncher = launcher;
-        mWorkspace = mLauncher.getWorkspace();
-    }
-
-    public void setWorkspaceScrollingEnabled(boolean isEnabled) {
-        mIsWorkspaceScrollingEnabled = isEnabled;
-    }
-
-    @Override
-    public int onPageScroll(ScrollState scrollState) {
-        float factor = scrollState.linearInterpolation;
-        float translateX = scrollState.distanceFromScreenCenter;
-        if (mIsWorkspaceScrollingEnabled) {
-            float shift = factor * (mTranslateXPage1 - mTranslateXPage0);
-            mWorkspace.setTranslationX(shift + mTranslateXPage0);
-            translateX += shift;
-        }
-
-        setTranslationX(translateX);
-
-        // If the workspace card is still the first page, shift all the other pages.
-        if (scrollState.linearInterpolation > mLinearInterpolationForPage2) {
-            scrollState.prevPageExtraWidth = 0;
-        } else if (mLinearInterpolationForPage2 > 0) {
-            scrollState.prevPageExtraWidth = mExtraScrollShift *
-                    (1 - scrollState.linearInterpolation / mLinearInterpolationForPage2);
-        } else {
-            scrollState.prevPageExtraWidth = mExtraScrollShift;
-        }
-        return SCROLL_TYPE_WORKSPACE;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
new file mode 100644
index 0000000..bb5bf6e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static android.view.View.TRANSLATION_Y;
+
+import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
+import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
+import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.view.View;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherInitListener;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.FastOverviewState;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.quickstep.TouchConsumer.InteractionType;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.TransformedRect;
+import com.android.quickstep.views.LauncherLayoutListener;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.util.Objects;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+/**
+ * Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public interface ActivityControlHelper<T extends BaseDraggingActivity> {
+
+    LayoutListener createLayoutListener(T activity);
+
+    /**
+     * Updates the UI to indicate quick interaction.
+     */
+    void onQuickInteractionStart(T activity, @Nullable RunningTaskInfo taskInfo,
+            boolean activityVisible);
+
+    float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+            Context context);
+
+    void executeOnWindowAvailable(T activity, Runnable action);
+
+    void onTransitionCancelled(T activity, boolean activityVisible);
+
+    int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
+            @InteractionType int interactionType, TransformedRect outRect);
+
+    void onSwipeUpComplete(T activity);
+
+    AnimationFactory prepareRecentsUI(T activity, boolean activityVisible,
+            Consumer<AnimatorPlaybackController> callback);
+
+    ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);
+
+    @Nullable
+    T getCreatedActivity();
+
+    @UiThread
+    @Nullable
+    RecentsView getVisibleRecentsView();
+
+    @UiThread
+    boolean switchToRecentsIfVisible(boolean fromRecentsButton);
+
+    Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target);
+
+    boolean shouldMinimizeSplitScreen();
+
+    /**
+     * @return {@code true} if recents activity should be started immediately on touchDown,
+     *         {@code false} if it should deferred until some threshold is crossed.
+     */
+    boolean deferStartingActivity(int downHitTarget);
+
+    boolean supportsLongSwipe(T activity);
+
+    AlphaProperty getAlphaProperty(T activity);
+
+    /**
+     * Must return a non-null controller is supportsLongSwipe was true.
+     */
+    LongSwipeHelper getLongSwipeController(T activity, int runningTaskId);
+
+    /**
+     * Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
+     */
+    int getContainerType();
+
+    class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> {
+
+        @Override
+        public LayoutListener createLayoutListener(Launcher activity) {
+            return new LauncherLayoutListener(activity);
+        }
+
+        @Override
+        public void onQuickInteractionStart(Launcher activity, RunningTaskInfo taskInfo,
+                boolean activityVisible) {
+            LauncherState fromState = activity.getStateManager().getState();
+            activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
+
+            QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
+                    .getQuickScrubController();
+            controller.onQuickScrubStart(activityVisible && !fromState.overviewUi, this);
+
+            // For the duration of the gesture, lock the screen orientation to ensure that we do not
+            // rotate mid-quickscrub
+            activity.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+        }
+
+        @Override
+        public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+                Context context) {
+            // The padding calculations are exactly same as that of RecentsView.setInsets
+            int topMargin = context.getResources()
+                    .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+            int paddingTop = targetRect.rect.top - topMargin - dp.getInsets().top;
+            int paddingBottom = dp.availableHeightPx + dp.getInsets().top - targetRect.rect.bottom;
+
+            return FastOverviewState.OVERVIEW_TRANSLATION_FACTOR * (paddingBottom - paddingTop);
+        }
+
+        @Override
+        public void executeOnWindowAvailable(Launcher activity, Runnable action) {
+            activity.getWorkspace().runOnOverlayHidden(action);
+        }
+
+        @Override
+        public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
+                @InteractionType int interactionType, TransformedRect outRect) {
+            LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect);
+            if (interactionType == INTERACTION_QUICK_SCRUB) {
+                outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context);
+            }
+            if (dp.isVerticalBarLayout()) {
+                Rect targetInsets = dp.getInsets();
+                int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+                return dp.hotseatBarSizePx + hotseatInset;
+            } else {
+                int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
+                // Track slightly below the top of the shelf (between top and content).
+                return shelfHeight - dp.edgeMarginPx * 2;
+            }
+        }
+
+        @Override
+        public void onTransitionCancelled(Launcher activity, boolean activityVisible) {
+            LauncherState startState = activity.getStateManager().getRestState();
+            activity.getStateManager().goToState(startState, activityVisible);
+        }
+
+        @Override
+        public void onSwipeUpComplete(Launcher activity) {
+            // Re apply state in case we did something funky during the transition.
+            activity.getStateManager().reapplyState();
+            DiscoveryBounce.showForOverviewIfNeeded(activity);
+        }
+
+        @Override
+        public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
+                Consumer<AnimatorPlaybackController> callback) {
+            final LauncherState startState = activity.getStateManager().getState();
+
+            LauncherState resetState = startState;
+            if (startState.disableRestore) {
+                resetState = activity.getStateManager().getRestState();
+            }
+            activity.getStateManager().setRestState(resetState);
+
+            if (!activityVisible) {
+                // Since the launcher is not visible, we can safely reset the scroll position.
+                // This ensures then the next swipe up to all-apps starts from scroll 0.
+                activity.getAppsView().reset(false /* animate */);
+                activity.getStateManager().goToState(OVERVIEW, false);
+
+                // Optimization, hide the all apps view to prevent layout while initializing
+                activity.getAppsView().getContentView().setVisibility(View.GONE);
+
+                AccessibilityManagerCompat.sendEventToTest(activity, "TAPL_WENT_TO_STATE");
+            }
+
+            return new AnimationFactory() {
+                @Override
+                public void createActivityController(long transitionLength,
+                        @InteractionType int interactionType) {
+                    createActivityControllerInternal(activity, activityVisible, startState,
+                            transitionLength, interactionType, callback);
+                }
+
+                @Override
+                public void onTransitionCancelled() {
+                    activity.getStateManager().goToState(startState, false /* animate */);
+                }
+            };
+        }
+
+        private void createActivityControllerInternal(Launcher activity, boolean wasVisible,
+                LauncherState startState, long transitionLength,
+                @InteractionType int interactionType,
+                Consumer<AnimatorPlaybackController> callback) {
+            LauncherState endState = interactionType == INTERACTION_QUICK_SCRUB
+                    ? FAST_OVERVIEW : OVERVIEW;
+            if (wasVisible) {
+                DeviceProfile dp = activity.getDeviceProfile();
+                long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
+                callback.accept(activity.getStateManager()
+                        .createAnimationToNewWorkspace(startState, endState, accuracy));
+                return;
+            }
+
+            AnimatorSet anim = new AnimatorSet();
+
+            if (!activity.getDeviceProfile().isVerticalBarLayout()) {
+                AllAppsTransitionController controller = activity.getAllAppsController();
+                float scrollRange = Math.max(controller.getShiftRange(), 1);
+                float progressDelta = (transitionLength / scrollRange);
+
+                float endProgress = endState.getVerticalProgress(activity);
+                float startProgress = endProgress + progressDelta;
+                ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(
+                        controller, ALL_APPS_PROGRESS, startProgress, endProgress);
+                shiftAnim.setInterpolator(LINEAR);
+                anim.play(shiftAnim);
+
+                // Since we are changing the start position of the UI, reapply the state, at the end
+                anim.addListener(new AnimationSuccessListener() {
+                    @Override
+                    public void onAnimationSuccess(Animator animator) {
+                        activity.getStateManager().reapplyState();
+                    }
+                });
+            }
+
+            if (interactionType == INTERACTION_NORMAL) {
+                playScaleDownAnim(anim, activity);
+            }
+
+            anim.setDuration(transitionLength * 2);
+            activity.getStateManager().setCurrentAnimation(anim);
+            callback.accept(AnimatorPlaybackController.wrap(anim, transitionLength * 2));
+        }
+
+        /**
+         * Scale down recents from the center task being full screen to being in overview.
+         */
+        private void playScaleDownAnim(AnimatorSet anim, Launcher launcher) {
+            RecentsView recentsView = launcher.getOverviewPanel();
+            TaskView v = recentsView.getTaskViewAt(recentsView.getCurrentPage());
+            if (v == null) {
+                return;
+            }
+            ClipAnimationHelper clipHelper = new ClipAnimationHelper();
+            clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
+            if (!clipHelper.getSourceRect().isEmpty() && !clipHelper.getTargetRect().isEmpty()) {
+                float fromScale = clipHelper.getSourceRect().width()
+                        / clipHelper.getTargetRect().width();
+                float fromTranslationY = clipHelper.getSourceRect().centerY()
+                        - clipHelper.getTargetRect().centerY();
+                Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, 1);
+                Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y,
+                        fromTranslationY, 0);
+                scale.setInterpolator(LINEAR);
+                translateY.setInterpolator(LINEAR);
+                anim.playTogether(scale, translateY);
+            }
+        }
+
+        @Override
+        public ActivityInitListener createActivityInitListener(
+                BiPredicate<Launcher, Boolean> onInitListener) {
+            return new LauncherInitListener(onInitListener);
+        }
+
+        @Nullable
+        @Override
+        public Launcher getCreatedActivity() {
+            LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+            if (app == null) {
+                return null;
+            }
+            return (Launcher) app.getModel().getCallback();
+        }
+
+        @Nullable
+        @UiThread
+        private Launcher getVisibleLaucher() {
+            Launcher launcher = getCreatedActivity();
+            return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
+                    launcher : null;
+        }
+
+        @Nullable
+        @Override
+        public RecentsView getVisibleRecentsView() {
+            Launcher launcher = getVisibleLaucher();
+            return launcher != null && launcher.getStateManager().getState().overviewUi
+                    ? launcher.getOverviewPanel() : null;
+        }
+
+        @Override
+        public boolean switchToRecentsIfVisible(boolean fromRecentsButton) {
+            Launcher launcher = getVisibleLaucher();
+            if (launcher != null) {
+                if (fromRecentsButton) {
+                    launcher.getUserEventDispatcher().logActionCommand(
+                            LauncherLogProto.Action.Command.RECENTS_BUTTON,
+                            getContainerType(),
+                            LauncherLogProto.ContainerType.TASKSWITCHER);
+                }
+                launcher.getStateManager().goToState(OVERVIEW);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean deferStartingActivity(int downHitTarget) {
+            return downHitTarget == HIT_TARGET_BACK || downHitTarget == HIT_TARGET_ROTATION;
+        }
+
+        @Override
+        public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
+            return homeBounds;
+        }
+
+        @Override
+        public boolean shouldMinimizeSplitScreen() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsLongSwipe(Launcher activity) {
+            return !activity.getDeviceProfile().isVerticalBarLayout();
+        }
+
+        @Override
+        public LongSwipeHelper getLongSwipeController(Launcher activity, int runningTaskId) {
+            if (activity.getDeviceProfile().isVerticalBarLayout()) {
+                return null;
+            }
+            return new LongSwipeHelper(activity, runningTaskId);
+        }
+
+        @Override
+        public AlphaProperty getAlphaProperty(Launcher activity) {
+            return activity.getDragLayer().getAlphaProperty(DragLayer.ALPHA_INDEX_SWIPE_UP);
+        }
+
+        @Override
+        public int getContainerType() {
+            final Launcher launcher = getVisibleLaucher();
+            return launcher != null ? launcher.getStateManager().getState().containerType
+                    : LauncherLogProto.ContainerType.APP;
+        }
+    }
+
+    class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> {
+
+        private final ComponentName mHomeComponent;
+        private final Handler mUiHandler = new Handler(Looper.getMainLooper());
+
+        public FallbackActivityControllerHelper(ComponentName homeComponent) {
+            mHomeComponent = homeComponent;
+        }
+
+        @Override
+        public void onQuickInteractionStart(RecentsActivity activity, RunningTaskInfo taskInfo,
+                boolean activityVisible) {
+            QuickScrubController controller = activity.<RecentsView>getOverviewPanel()
+                    .getQuickScrubController();
+
+            // TODO: match user is as well
+            boolean startingFromHome = !activityVisible &&
+                    (taskInfo == null || Objects.equals(taskInfo.topActivity, mHomeComponent));
+            controller.onQuickScrubStart(startingFromHome, this);
+            if (activityVisible) {
+                mUiHandler.postDelayed(controller::onFinishedTransitionToQuickScrub,
+                        OVERVIEW_TRANSITION_MS);
+            }
+        }
+
+        @Override
+        public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp,
+                Context context) {
+            return 0;
+        }
+
+        @Override
+        public void executeOnWindowAvailable(RecentsActivity activity, Runnable action) {
+            action.run();
+        }
+
+        @Override
+        public void onTransitionCancelled(RecentsActivity activity, boolean activityVisible) {
+            // TODO:
+        }
+
+        @Override
+        public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context,
+                @InteractionType int interactionType, TransformedRect outRect) {
+            LayoutUtils.calculateFallbackTaskSize(context, dp, outRect.rect);
+            if (dp.isVerticalBarLayout()) {
+                Rect targetInsets = dp.getInsets();
+                int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
+                return dp.hotseatBarSizePx + hotseatInset;
+            } else {
+                return dp.heightPx - outRect.rect.bottom;
+            }
+        }
+
+        @Override
+        public void onSwipeUpComplete(RecentsActivity activity) {
+            // TODO:
+        }
+
+        @Override
+        public AnimationFactory prepareRecentsUI(RecentsActivity activity, boolean activityVisible,
+                Consumer<AnimatorPlaybackController> callback) {
+            if (activityVisible) {
+                return (transitionLength, interactionType) -> { };
+            }
+
+            RecentsView rv = activity.getOverviewPanel();
+            rv.setContentAlpha(0);
+
+            return new AnimationFactory() {
+
+                boolean isAnimatingHome = false;
+
+                @Override
+                public void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) {
+                    isAnimatingHome = targets != null && targets.isAnimatingHome();
+                    if (!isAnimatingHome) {
+                        rv.setContentAlpha(1);
+                    }
+                    createActivityController(getSwipeUpDestinationAndLength(
+                            activity.getDeviceProfile(), activity, INTERACTION_NORMAL,
+                            new TransformedRect()), INTERACTION_NORMAL);
+                }
+
+                @Override
+                public void createActivityController(long transitionLength, int interactionType) {
+                    if (!isAnimatingHome) {
+                        return;
+                    }
+
+                    ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
+                    anim.setDuration(transitionLength).setInterpolator(LINEAR);
+                    AnimatorSet animatorSet = new AnimatorSet();
+                    animatorSet.play(anim);
+                    callback.accept(AnimatorPlaybackController.wrap(animatorSet, transitionLength));
+                }
+            };
+        }
+
+        @Override
+        public LayoutListener createLayoutListener(RecentsActivity activity) {
+            // We do not change anything as part of layout changes in fallback activity. Return a
+            // default layout listener.
+            return new LayoutListener() {
+                @Override
+                public void open() { }
+
+                @Override
+                public void setHandler(WindowTransformSwipeHandler handler) { }
+
+                @Override
+                public void finish() { }
+            };
+        }
+
+        @Override
+        public ActivityInitListener createActivityInitListener(
+                BiPredicate<RecentsActivity, Boolean> onInitListener) {
+            return new RecentsActivityTracker(onInitListener);
+        }
+
+        @Nullable
+        @Override
+        public RecentsActivity getCreatedActivity() {
+            return RecentsActivityTracker.getCurrentActivity();
+        }
+
+        @Nullable
+        @Override
+        public RecentsView getVisibleRecentsView() {
+            RecentsActivity activity = getCreatedActivity();
+            if (activity != null && activity.hasWindowFocus()) {
+                return activity.getOverviewPanel();
+            }
+            return null;
+        }
+
+        @Override
+        public boolean switchToRecentsIfVisible(boolean fromRecentsButton) {
+            return false;
+        }
+
+        @Override
+        public boolean deferStartingActivity(int downHitTarget) {
+            // Always defer starting the activity when using fallback
+            return true;
+        }
+
+        @Override
+        public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
+            // TODO: Remove this once b/77875376 is fixed
+            return target.sourceContainerBounds;
+        }
+
+        @Override
+        public boolean shouldMinimizeSplitScreen() {
+            // TODO: Remove this once b/77875376 is fixed
+            return false;
+        }
+
+        @Override
+        public boolean supportsLongSwipe(RecentsActivity activity) {
+            return false;
+        }
+
+        @Override
+        public LongSwipeHelper getLongSwipeController(RecentsActivity activity, int runningTaskId) {
+            return null;
+        }
+
+        @Override
+        public AlphaProperty getAlphaProperty(RecentsActivity activity) {
+            return activity.getDragLayer().getAlphaProperty(0);
+        }
+
+        @Override
+        public int getContainerType() {
+            return LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER;
+        }
+    }
+
+    interface LayoutListener {
+
+        void open();
+
+        void setHandler(WindowTransformSwipeHandler handler);
+
+        void finish();
+    }
+
+    interface ActivityInitListener {
+
+        void register();
+
+        void unregister();
+
+        void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+                Context context, Handler handler, long duration);
+    }
+
+    interface AnimationFactory {
+
+        default void onRemoteAnimationReceived(RemoteAnimationTargetSet targets) { }
+
+        void createActivityController(long transitionLength, @InteractionType int interactionType);
+
+        default void onTransitionCancelled() { }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 214b3f3..84dfdbd 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -46,9 +46,9 @@
         mUpdateCallback = updateCallback;
     }
 
-    public ObjectAnimator animateToValue(float v) {
+    public ObjectAnimator animateToValue(float start, float end) {
         cancelAnimation();
-        mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v);
+        mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end);
         mValueAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animator) {
@@ -77,6 +77,12 @@
         }
     }
 
+    public void finishAnimation() {
+        if (mValueAnimator != null && mValueAnimator.isRunning()) {
+            mValueAnimator.end();
+        }
+    }
+
     public ObjectAnimator getCurrentAnimation() {
         return mValueAnimator;
     }
diff --git a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
deleted file mode 100644
index 5bf7e4e..0000000
--- a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.support.annotation.WorkerThread;
-
-import com.android.launcher3.states.InternalStateHandler;
-import com.android.quickstep.TouchConsumer.InteractionType;
-
-import java.util.function.Consumer;
-
-public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
-
-    protected Consumer<BaseSwipeInteractionHandler> mGestureEndCallback;
-
-    public void setGestureEndCallback(Consumer<BaseSwipeInteractionHandler> gestureEndCallback) {
-        mGestureEndCallback = gestureEndCallback;
-    }
-
-    public void reset() {}
-
-    @WorkerThread
-    public abstract void onGestureStarted();
-
-    @WorkerThread
-    public abstract void onGestureEnded(float endVelocity);
-
-    public abstract void updateInteractionType(@InteractionType int interactionType);
-
-    @WorkerThread
-    public abstract void onQuickScrubEnd();
-
-    @WorkerThread
-    public abstract void onQuickScrubProgress(float progress);
-
-    @WorkerThread
-    public abstract void updateDisplacement(float displacement);
-}
diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
new file mode 100644
index 0000000..8e83bd0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.Choreographer;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * A TouchConsumer which defers all events on the UIThread until the consumer is created.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class DeferredTouchConsumer implements TouchConsumer {
+
+    private final VelocityTracker mVelocityTracker;
+    private final DeferredTouchProvider mTouchProvider;
+
+    private MotionEventQueue mMyQueue;
+    private TouchConsumer mTarget;
+
+    public DeferredTouchConsumer(DeferredTouchProvider touchProvider) {
+        mVelocityTracker = VelocityTracker.obtain();
+        mTouchProvider = touchProvider;
+    }
+
+    @Override
+    public void accept(MotionEvent event) {
+        mTarget.accept(event);
+    }
+
+    @Override
+    public void reset() {
+        mTarget.reset();
+    }
+
+    @Override
+    public void updateTouchTracking(int interactionType) {
+        mTarget.updateTouchTracking(interactionType);
+    }
+
+    @Override
+    public void onQuickScrubEnd() {
+        mTarget.onQuickScrubEnd();
+    }
+
+    @Override
+    public void onQuickScrubProgress(float progress) {
+        mTarget.onQuickScrubProgress(progress);
+    }
+
+    @Override
+    public void onQuickStep(MotionEvent ev) {
+        mTarget.onQuickStep(ev);
+    }
+
+    @Override
+    public void onCommand(int command) {
+        mTarget.onCommand(command);
+    }
+
+    @Override
+    public void preProcessMotionEvent(MotionEvent ev) {
+        mVelocityTracker.addMovement(ev);
+    }
+
+    @Override
+    public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+        mMyQueue = queue;
+        return null;
+    }
+
+    @Override
+    public void deferInit() {
+        mTarget = mTouchProvider.createTouchConsumer(mVelocityTracker);
+        mTarget.getIntrimChoreographer(mMyQueue);
+    }
+
+    @Override
+    public boolean forceToLauncherConsumer() {
+        return mTarget.forceToLauncherConsumer();
+    }
+
+    @Override
+    public boolean deferNextEventToMainThread() {
+        // If our target is still null, defer the next target as well
+        TouchConsumer target = mTarget;
+        return target == null ? true : target.deferNextEventToMainThread();
+    }
+
+    @Override
+    public void onShowOverviewFromAltTab() {
+        mTarget.onShowOverviewFromAltTab();
+    }
+
+    public interface DeferredTouchProvider {
+
+        TouchConsumer createTouchConsumer(VelocityTracker tracker);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
new file mode 100644
index 0000000..12757c0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstantAppInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.util.InstantAppResolver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of InstantAppResolver using platform APIs
+ */
+@SuppressWarnings("unused")
+public class InstantAppResolverImpl extends InstantAppResolver {
+
+    private static final String TAG = "InstantAppResolverImpl";
+    public static final String COMPONENT_CLASS_MARKER = "@instantapp";
+
+    private final PackageManager mPM;
+
+    public InstantAppResolverImpl(Context context)
+            throws NoSuchMethodException, ClassNotFoundException {
+        mPM = context.getPackageManager();
+    }
+
+    @Override
+    public boolean isInstantApp(ApplicationInfo info) {
+        return info.isInstantApp();
+    }
+
+    @Override
+    public boolean isInstantApp(AppInfo info) {
+        ComponentName cn = info.getTargetComponent();
+        return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
+    }
+
+    @Override
+    public List<ApplicationInfo> getInstantApps() {
+        try {
+            List<ApplicationInfo> result = new ArrayList<>();
+            for (InstantAppInfo iai : mPM.getInstantApps()) {
+                ApplicationInfo info = iai.getApplicationInfo();
+                if (info != null) {
+                    result.add(info);
+                }
+            }
+            return result;
+        } catch (SecurityException se) {
+            Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
+        } catch (Exception e) {
+            Log.e(TAG, "Error calling API: getInstantApps", e);
+        }
+        return super.getInstantApps();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
new file mode 100644
index 0000000..f5e1f6e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/LauncherSearchIndexablesProvider.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ResolveInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.os.Build;
+import android.provider.SearchIndexablesContract.XmlResource;
+import android.provider.SearchIndexablesProvider;
+import android.util.Xml;
+
+import com.android.launcher3.R;
+import com.android.launcher3.graphics.IconShapeOverride;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
+import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
+import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
+
+@TargetApi(Build.VERSION_CODES.O)
+public class LauncherSearchIndexablesProvider extends SearchIndexablesProvider {
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor queryXmlResources(String[] strings) {
+        MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
+        ResolveInfo settingsActivity = getContext().getPackageManager().resolveActivity(
+                new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+                        .setPackage(getContext().getPackageName()), 0);
+        cursor.newRow()
+                .add(XmlResource.COLUMN_XML_RESID, R.xml.indexable_launcher_prefs)
+                .add(XmlResource.COLUMN_INTENT_ACTION, Intent.ACTION_APPLICATION_PREFERENCES)
+                .add(XmlResource.COLUMN_INTENT_TARGET_PACKAGE, getContext().getPackageName())
+                .add(XmlResource.COLUMN_INTENT_TARGET_CLASS, settingsActivity.activityInfo.name);
+        return cursor;
+    }
+
+    @Override
+    public Cursor queryRawData(String[] projection) {
+        return new MatrixCursor(INDEXABLES_RAW_COLUMNS);
+    }
+
+    @Override
+    public Cursor queryNonIndexableKeys(String[] projection) {
+        MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
+        if (!getContext().getSystemService(LauncherApps.class).hasShortcutHostPermission()) {
+            // We are not the current launcher. Hide all preferences
+            try (XmlResourceParser parser = getContext().getResources()
+                    .getXml(R.xml.indexable_launcher_prefs)) {
+                final int depth = parser.getDepth();
+                final int[] attrs = new int[] { android.R.attr.key };
+                int type;
+                while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                        parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+                    if (type == XmlPullParser.START_TAG) {
+                        TypedArray a = getContext().obtainStyledAttributes(
+                                Xml.asAttributeSet(parser), attrs);
+                        cursor.addRow(new String[] {a.getString(0)});
+                        a.recycle();
+                    }
+                }
+            } catch (IOException |XmlPullParserException e) {
+                throw new RuntimeException(e);
+            }
+        } else if (!IconShapeOverride.isSupported(getContext())) {
+            cursor.addRow(new String[] {IconShapeOverride.KEY_PREFERENCE});
+        }
+        return cursor;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/LongSwipeHelper.java b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
new file mode 100644
index 0000000..16214dd
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/LongSwipeHelper.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_OVERSHOOT_DURATION;
+
+import android.animation.ValueAnimator;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.Interpolators.OvershootParams;
+import com.android.launcher3.uioverrides.PortraitStatesTouchController;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.FlingBlockCheck;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+/**
+ * Utility class to handle long swipe from an app.
+ * This assumes the presence of Launcher activity as long swipe is not supported on the
+ * fallback activity.
+ */
+public class LongSwipeHelper {
+
+    private static final float SWIPE_DURATION_MULTIPLIER =
+            Math.min(1 / MIN_PROGRESS_TO_ALL_APPS, 1 / (1 - MIN_PROGRESS_TO_ALL_APPS));
+
+    private final Launcher mLauncher;
+    private final int mRunningTaskId;
+
+    private float mMaxSwipeDistance = 1;
+    private AnimatorPlaybackController mAnimator;
+    private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
+
+    LongSwipeHelper(Launcher launcher, int runningTaskId) {
+        mLauncher = launcher;
+        mRunningTaskId = runningTaskId;
+        init();
+    }
+
+    private void init() {
+        mFlingBlockCheck.blockFling();
+
+        // Init animations
+        AllAppsTransitionController controller = mLauncher.getAllAppsController();
+        // TODO: Scale it down so that we can reach all-apps in screen space
+        mMaxSwipeDistance = Math.max(1, controller.getProgress() * controller.getShiftRange());
+
+        AnimatorSetBuilder builder = PortraitStatesTouchController.getOverviewToAllAppsAnimation();
+        mAnimator = mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, builder,
+                Math.round(2 * mMaxSwipeDistance), null, LauncherStateManager.ANIM_ALL);
+        mAnimator.dispatchOnStart();
+    }
+
+    public void onMove(float displacement) {
+        mAnimator.setPlayFraction(displacement / mMaxSwipeDistance);
+        mFlingBlockCheck.onEvent();
+    }
+
+    public void destroy() {
+        // TODO: We can probably also show the task view
+
+        mLauncher.getStateManager().goToState(OVERVIEW, false);
+    }
+
+    public void end(float velocity, boolean isFling, Runnable callback) {
+        float velocityPxPerMs = velocity / 1000;
+        long duration = MAX_SWIPE_DURATION;
+        Interpolator interpolator = DEACCEL;
+
+        final float currentFraction = mAnimator.getProgressFraction();
+        final boolean toAllApps;
+        float endProgress;
+
+        boolean blockedFling = isFling && mFlingBlockCheck.isBlocked();
+        if (blockedFling) {
+            isFling = false;
+        }
+
+        if (!isFling) {
+            toAllApps = currentFraction > MIN_PROGRESS_TO_ALL_APPS;
+            endProgress = toAllApps ? 1 : 0;
+
+            long expectedDuration = Math.abs(Math.round((endProgress - currentFraction)
+                    * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
+            duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
+
+            if (blockedFling && !toAllApps) {
+                Interpolators.OvershootParams overshoot = new OvershootParams(currentFraction,
+                        currentFraction, endProgress, velocityPxPerMs, (int) mMaxSwipeDistance);
+                duration = (overshoot.duration + duration);
+                duration = Utilities.boundToRange(duration, MIN_OVERSHOOT_DURATION,
+                        MAX_SWIPE_DURATION);
+                interpolator = overshoot.interpolator;
+                endProgress = overshoot.end;
+            }
+        } else {
+            toAllApps = velocity < 0;
+            endProgress = toAllApps ? 1 : 0;
+
+            float minFlingVelocity = mLauncher.getResources()
+                    .getDimension(R.dimen.quickstep_fling_min_velocity);
+            if (Math.abs(velocity) > minFlingVelocity && mMaxSwipeDistance > 0) {
+                float distanceToTravel = (endProgress - currentFraction) * mMaxSwipeDistance;
+
+                // we want the page's snap velocity to approximately match the velocity at
+                // which the user flings, so we scale the duration by a value near to the
+                // derivative of the scroll interpolator at zero, ie. 2.
+                long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
+                duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+            }
+        }
+
+        final boolean finalIsFling = isFling;
+        mAnimator.setEndAction(() -> onSwipeAnimationComplete(toAllApps, finalIsFling, callback));
+
+        ValueAnimator animator = mAnimator.getAnimationPlayer();
+        animator.setDuration(duration).setInterpolator(interpolator);
+        animator.setFloatValues(currentFraction, endProgress);
+        animator.start();
+    }
+
+    private void onSwipeAnimationComplete(boolean toAllApps, boolean isFling, Runnable callback) {
+        RecentsView rv = mLauncher.getOverviewPanel();
+        if (!toAllApps) {
+            rv.setIgnoreResetTask(mRunningTaskId);
+        }
+
+        mLauncher.getStateManager().goToState(toAllApps ? ALL_APPS : OVERVIEW, false);
+        if (!toAllApps) {
+            DiscoveryBounce.showForOverviewIfNeeded(mLauncher);
+            rv.animateUpRunningTaskIconScale();
+            rv.setSwipeDownShouldLaunchApp(true);
+        }
+
+        mLauncher.getUserEventDispatcher().logStateChangeAction(
+                isFling ? Touch.FLING : Touch.SWIPE, Direction.UP,
+                ContainerType.NAVBAR, ContainerType.APP,
+                toAllApps ? ContainerType.ALLAPPS : ContainerType.TASKSWITCHER,
+                0);
+
+        callback.run();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index 6e92d83..f73be6c 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -19,9 +19,7 @@
 import static android.view.MotionEvent.ACTION_MASK;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
-
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
 
 import android.annotation.TargetApi;
 import android.os.Build;
@@ -43,16 +41,22 @@
 
     private static final int ACTION_VIRTUAL = ACTION_MASK - 1;
 
-    private static final int ACTION_QUICK_SWITCH =
-            ACTION_VIRTUAL | (1 << ACTION_POINTER_INDEX_SHIFT);
     private static final int ACTION_QUICK_SCRUB_START =
-            ACTION_VIRTUAL | (2 << ACTION_POINTER_INDEX_SHIFT);
+            ACTION_VIRTUAL | (1 << ACTION_POINTER_INDEX_SHIFT);
     private static final int ACTION_QUICK_SCRUB_PROGRESS =
-            ACTION_VIRTUAL | (3 << ACTION_POINTER_INDEX_SHIFT);
+            ACTION_VIRTUAL | (2 << ACTION_POINTER_INDEX_SHIFT);
     private static final int ACTION_QUICK_SCRUB_END =
-            ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
+            ACTION_VIRTUAL | (3 << ACTION_POINTER_INDEX_SHIFT);
     private static final int ACTION_RESET =
+            ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_DEFER_INIT =
             ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_SHOW_OVERVIEW_FROM_ALT_TAB =
+            ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_QUICK_STEP =
+            ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_COMMAND =
+            ACTION_VIRTUAL | (8 << ACTION_POINTER_INDEX_SHIFT);
 
     private final EventArray mEmptyArray = new EventArray();
     private final Object mExecutionLock = new Object();
@@ -76,10 +80,10 @@
     public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
         mMainChoreographer = choreographer;
         mConsumer = consumer;
-
         mCurrentChoreographer = mMainChoreographer;
         mCurrentRunnable = mMainFrameCallback;
-        setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
+
+        setInterimChoreographer(consumer.getIntrimChoreographer(this));
     }
 
     public void setInterimChoreographer(Choreographer choreographer) {
@@ -141,9 +145,6 @@
                 MotionEvent event = array.get(i);
                 if (event.getActionMasked() == ACTION_VIRTUAL) {
                     switch (event.getAction()) {
-                        case ACTION_QUICK_SWITCH:
-                            mConsumer.updateTouchTracking(INTERACTION_QUICK_SWITCH);
-                            break;
                         case ACTION_QUICK_SCRUB_START:
                             mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
                             break;
@@ -156,6 +157,19 @@
                         case ACTION_RESET:
                             mConsumer.reset();
                             break;
+                        case ACTION_DEFER_INIT:
+                            mConsumer.deferInit();
+                            break;
+                        case ACTION_SHOW_OVERVIEW_FROM_ALT_TAB:
+                            mConsumer.onShowOverviewFromAltTab();
+                            mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
+                            break;
+                        case ACTION_QUICK_STEP:
+                            mConsumer.onQuickStep(event);
+                            break;
+                        case ACTION_COMMAND:
+                            mConsumer.onCommand(event.getSource());
+                            break;
                         default:
                             Log.e(TAG, "Invalid virtual event: " + event.getAction());
                     }
@@ -184,14 +198,14 @@
         queueNoPreProcess(MotionEvent.obtain(0, 0, action, progress, 0, 0));
     }
 
-    public void onQuickSwitch() {
-        queueVirtualAction(ACTION_QUICK_SWITCH, 0);
-    }
-
     public void onQuickScrubStart() {
         queueVirtualAction(ACTION_QUICK_SCRUB_START, 0);
     }
 
+    public void onOverviewShownFromAltTab() {
+        queueVirtualAction(ACTION_SHOW_OVERVIEW_FROM_ALT_TAB, 0);
+    }
+
     public void onQuickScrubProgress(float progress) {
         queueVirtualAction(ACTION_QUICK_SCRUB_PROGRESS, progress);
     }
@@ -200,10 +214,29 @@
         queueVirtualAction(ACTION_QUICK_SCRUB_END, 0);
     }
 
+    public void onQuickStep(MotionEvent event) {
+        event.setAction(ACTION_QUICK_STEP);
+        queueNoPreProcess(event);
+    }
+
     public void reset() {
         queueVirtualAction(ACTION_RESET, 0);
     }
 
+    public void deferInit() {
+        queueVirtualAction(ACTION_DEFER_INIT, 0);
+    }
+
+    public void onCommand(int command) {
+        MotionEvent ev = MotionEvent.obtain(0, 0, ACTION_COMMAND, 0, 0, 0);
+        ev.setSource(command);
+        queueNoPreProcess(ev);
+    }
+
+    public TouchConsumer getConsumer() {
+        return mConsumer;
+    }
+
     private static class EventArray extends ArrayList<MotionEvent> {
 
         public int lastEventAction = ACTION_CANCEL;
diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java
index 7a74176..bda3d06 100644
--- a/quickstep/src/com/android/quickstep/MultiStateCallback.java
+++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java
@@ -59,4 +59,8 @@
     public int getState() {
         return mState;
     }
+
+    public boolean hasStates(int stateMask) {
+        return (mState & stateMask) == stateMask;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
deleted file mode 100644
index ae70474..0000000
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-
-import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
-import static com.android.quickstep.TouchConsumer.isInteractionQuick;
-
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.animation.RectEvaluator;
-import android.annotation.TargetApi;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.os.Build;
-import android.support.annotation.UiThread;
-import android.view.View;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.Launcher.OnResumeCallback;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.TraceHelper;
-import com.android.quickstep.TouchConsumer.InteractionType;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-@TargetApi(Build.VERSION_CODES.O)
-public class NavBarSwipeInteractionHandler extends BaseSwipeInteractionHandler implements
-        OnResumeCallback {
-
-    private static final int STATE_LAUNCHER_READY = 1 << 0;
-    private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 4;
-    private static final int STATE_SCALED_SNAPSHOT_RECENTS = 1 << 5;
-    private static final int STATE_SCALED_SNAPSHOT_APP = 1 << 6;
-
-    private static final long MAX_SWIPE_DURATION = 200;
-    private static final long MIN_SWIPE_DURATION = 80;
-
-    // Ideal velocity for a smooth transition
-    private static final float PIXEL_PER_MS = 2f;
-
-    private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
-
-    private final Rect mStableInsets = new Rect();
-    private final Rect mSourceRect = new Rect();
-    private final Rect mTargetRect = new Rect();
-    private final Rect mCurrentRect = new Rect();
-    private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
-
-    // Shift in the range of [0, 1].
-    // 0 => preview snapShot is completely visible, and hotseat is completely translated down
-    // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
-    // visible.
-    private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
-
-    // Activity multiplier in the range of [0, 1]. When the activity becomes visible, this is
-    // animated to 1, so allow for a smooth transition.
-    private final AnimatedFloat mActivityMultiplier = new AnimatedFloat(this::updateFinalShift);
-
-    private final int mRunningTaskId;
-    private final Context mContext;
-
-    private final MultiStateCallback mStateCallback;
-
-    private Launcher mLauncher;
-    private SnapshotDragView mDragView;
-    private RecentsView mRecentsView;
-    private QuickScrubController mQuickScrubController;
-    private Hotseat mHotseat;
-
-    private boolean mWasLauncherAlreadyVisible;
-
-    private boolean mLauncherReady;
-    private boolean mTouchEndHandled;
-    private float mCurrentDisplacement;
-
-    private @InteractionType int mInteractionType;
-    private boolean mStartedQuickScrubFromHome;
-
-    private Bitmap mTaskSnapshot;
-
-    NavBarSwipeInteractionHandler(RunningTaskInfo runningTaskInfo, Context context,
-            @InteractionType int interactionType) {
-        mContext = context;
-        mInteractionType = interactionType;
-        mRunningTaskId = runningTaskInfo.id;
-        WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
-
-        DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
-        // TODO: If in multi window mode, dp = dp.getMultiWindowProfile()
-        dp = dp.copy(mContext);
-        // TODO: Use different insets for multi-window mode
-        dp.updateInsets(mStableInsets);
-        RecentsView.getPageRect(dp, mContext, mTargetRect);
-        mSourceRect.set(0, 0, dp.widthPx - mStableInsets.left - mStableInsets.right,
-                dp.heightPx - mStableInsets.top - mStableInsets.bottom);
-
-        // Build the state callback
-        mStateCallback = new MultiStateCallback();
-        mStateCallback.addCallback(STATE_LAUNCHER_READY, this::onLauncherReady);
-        mStateCallback.addCallback(STATE_SCALED_SNAPSHOT_APP, this::resumeLastTask);
-        mStateCallback.addCallback(
-                STATE_SCALED_SNAPSHOT_RECENTS | STATE_ACTIVITY_MULTIPLIER_COMPLETE,
-                this::onAnimationToLauncherComplete);
-        mStateCallback.addCallback(STATE_LAUNCHER_READY | STATE_SCALED_SNAPSHOT_APP,
-                this::cleanupLauncher);
-    }
-
-    private void onLauncherReady() {
-        mLauncherReady = true;
-        executeFrameUpdate();
-
-        long duration = Math.min(MAX_SWIPE_DURATION,
-                Math.max((long) (-mCurrentDisplacement / PIXEL_PER_MS), MIN_SWIPE_DURATION));
-        if (mCurrentShift.getCurrentAnimation() != null) {
-            ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
-            long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();
-
-            // TODO: Find a better heuristic
-            duration = (duration + theirDuration) / 2;
-        }
-        ObjectAnimator anim = mActivityMultiplier.animateToValue(1)
-                .setDuration(duration);
-        anim.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
-            }
-        });
-        anim.start();
-    }
-
-    public void setTaskSnapshot(Bitmap taskSnapshot) {
-        mTaskSnapshot = taskSnapshot;
-    }
-
-    @Override
-    public void onLauncherResume() {
-        TraceHelper.partitionSection("TouchInt", "Launcher On resume");
-        mDragView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
-            @Override
-            public boolean onPreDraw() {
-                mDragView.getViewTreeObserver().removeOnPreDrawListener(this);
-                mStateCallback.setState(STATE_LAUNCHER_READY);
-                TraceHelper.partitionSection("TouchInt", "Launcher drawn");
-                return true;
-            }
-        });
-    }
-
-    @Override
-    protected boolean init(Launcher launcher, boolean alreadyOnHome) {
-        launcher.setOnResumeCallback(this);
-        mLauncher = launcher;
-        mRecentsView = launcher.getOverviewPanel();
-        mRecentsView.showTask(mRunningTaskId);
-        mHotseat = mLauncher.getHotseat();
-        mWasLauncherAlreadyVisible = alreadyOnHome;
-
-        AbstractFloatingView.closeAllOpenViews(mLauncher, alreadyOnHome);
-        mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, alreadyOnHome);
-
-        mDragView = new SnapshotDragView(mLauncher, mTaskSnapshot);
-        mLauncher.getDragLayer().addView(mDragView);
-        mDragView.setPivotX(0);
-        mDragView.setPivotY(0);
-
-        if (isInteractionQuick(mInteractionType)) {
-            updateUiForQuickScrub();
-        }
-
-        // Optimization
-        if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-            // All-apps search box is visible in vertical bar layout.
-            mLauncher.getAppsView().setVisibility(View.GONE);
-        }
-        TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
-        return false;
-    }
-
-    public void updateInteractionType(@InteractionType int interactionType) {
-        Preconditions.assertUIThread();
-        if (mInteractionType != INTERACTION_NORMAL) {
-            throw new IllegalArgumentException(
-                    "Can't change interaction type from " + mInteractionType);
-        }
-        if (!isInteractionQuick(interactionType)) {
-            throw new IllegalArgumentException(
-                    "Can't change interaction type to " + interactionType);
-        }
-        mInteractionType = interactionType;
-
-        if (mLauncher != null) {
-            updateUiForQuickScrub();
-        }
-    }
-
-    private void updateUiForQuickScrub() {
-        mStartedQuickScrubFromHome = mWasLauncherAlreadyVisible;
-        mQuickScrubController = mRecentsView.getQuickScrubController();
-        mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
-        animateToProgress(1f, MAX_SWIPE_DURATION);
-        if (mStartedQuickScrubFromHome) {
-            mDragView.setVisibility(View.INVISIBLE);
-        }
-    }
-
-    @UiThread
-    public void updateDisplacement(float displacement) {
-        mCurrentDisplacement = displacement;
-        executeFrameUpdate();
-    }
-
-    private void executeFrameUpdate() {
-        if (mLauncherReady) {
-            final float displacement = -mCurrentDisplacement;
-            int hotseatSize = getHotseatSize();
-            float translation = Utilities.boundToRange(displacement, 0, hotseatSize);
-            float shift = hotseatSize == 0 ? 0 : translation / hotseatSize;
-            mCurrentShift.updateValue(shift);
-        }
-    }
-
-    @UiThread
-    private void updateFinalShift() {
-        if (!mLauncherReady || mStartedQuickScrubFromHome) {
-            return;
-        }
-
-        float shift = mCurrentShift.value * mActivityMultiplier.value;
-
-        AllAppsTransitionController controller = mLauncher.getAllAppsController();
-        float range = getHotseatSize() / controller.getShiftRange();
-        controller.setProgress(1 + (1 - shift) * range);
-
-        mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
-
-        float scale = (float) mCurrentRect.width() / mSourceRect.width();
-        mDragView.setTranslationX(mCurrentRect.left - mStableInsets.left * scale * shift);
-        mDragView.setTranslationY(mCurrentRect.top - mStableInsets.top * scale * shift);
-        mDragView.setScaleX(scale);
-        mDragView.setScaleY(scale);
-        //  TODO: mDragView.getViewBounds().setClipLeft((int) (mStableInsets.left * shift));
-        mDragView.getViewBounds().setClipTop((int) (mStableInsets.top * shift));
-        // TODO: mDragView.getViewBounds().setClipRight((int) (mStableInsets.right * shift));
-        mDragView.getViewBounds().setClipBottom((int) (mStableInsets.bottom * shift));
-    }
-
-    private int getHotseatSize() {
-        return mLauncher.getDeviceProfile().isVerticalBarLayout()
-                ? mHotseat.getWidth() : mHotseat.getHeight();
-    }
-
-    @Override
-    public void onGestureStarted() { }
-
-    @UiThread
-    public void onGestureEnded(float endVelocity) {
-        if (mTouchEndHandled) {
-            return;
-        }
-        mTouchEndHandled = true;
-
-        Resources res = mContext.getResources();
-        float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
-        boolean isFling = Math.abs(endVelocity) > flingThreshold;
-
-        long duration = MAX_SWIPE_DURATION;
-        final float endShift;
-        if (!isFling) {
-            endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
-        } else {
-            endShift = endVelocity < 0 ? 1 : 0;
-            float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
-            if (Math.abs(endVelocity) > minFlingVelocity && mLauncherReady) {
-                float distanceToTravel = (endShift - mCurrentShift.value) * getHotseatSize();
-
-                // we want the page's snap velocity to approximately match the velocity at
-                // which the user flings, so we scale the duration by a value near to the
-                // derivative of the scroll interpolator at zero, ie. 5.
-                duration = 5 * Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
-            }
-        }
-
-        animateToProgress(endShift, duration);
-    }
-
-    /** Animates to the given progress, where 0 is the current app and 1 is overview. */
-    private void animateToProgress(float progress, long duration) {
-        ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
-        anim.setInterpolator(Interpolators.SCROLL);
-        anim.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
-                        ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
-            }
-        });
-        anim.start();
-    }
-
-    @UiThread
-    private void resumeLastTask() {
-        RecentsTaskLoadPlan loadPlan = RecentsModel.getInstance(mContext).getLastLoadPlan();
-        if (loadPlan != null) {
-            Task task = loadPlan.getTaskStack().findTaskWithId(mRunningTaskId);
-            if (task != null) {
-                ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
-                ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(task.key, opts,
-                        null, null);
-            }
-        }
-    }
-
-    public void reset() {
-        mCurrentShift.cancelAnimation();
-        if (mGestureEndCallback != null) {
-            mGestureEndCallback.accept(this);
-        }
-    }
-
-    private void cleanupLauncher() {
-        reset();
-
-        // TODO: These should be done as part of ActivityOptions#OnAnimationStarted
-        mLauncher.getStateManager().reapplyState();
-        mLauncher.setOnResumeCallback(() -> mDragView.close(false));
-    }
-
-    private void onAnimationToLauncherComplete() {
-        reset();
-
-        mDragView.close(false);
-        View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
-        if (currentRecentsPage instanceof TaskView) {
-            ((TaskView) currentRecentsPage).animateIconToScale(1f);
-        }
-        if (mInteractionType == INTERACTION_QUICK_SWITCH) {
-            if (mQuickScrubController != null) {
-                mQuickScrubController.onQuickSwitch();
-            }
-        }
-    }
-
-    public void onQuickScrubEnd() {
-        if (mQuickScrubController != null) {
-            mQuickScrubController.onQuickScrubEnd();
-        } else {
-            // TODO:
-        }
-    }
-
-    public void onQuickScrubProgress(float progress) {
-        if (mQuickScrubController != null) {
-            mQuickScrubController.onQuickScrubProgress(progress);
-        } else {
-            // TODO:
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
new file mode 100644
index 0000000..f875bb7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.UserHandle;
+import android.util.LruCache;
+import android.util.SparseArray;
+
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.systemui.shared.recents.model.IconLoader;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
+
+/**
+ * Extension of {@link IconLoader} with icon normalization support
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class NormalizedIconLoader extends IconLoader {
+
+    private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
+    private final DrawableFactory mDrawableFactory;
+    private LauncherIcons mLauncherIcons;
+
+    public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
+            LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+        super(context, iconCache, activityInfoCache);
+        mDrawableFactory = DrawableFactory.get(context);
+    }
+
+    @Override
+    public Drawable getDefaultIcon(int userId) {
+        synchronized (mDefaultIcons) {
+            BitmapInfo info = mDefaultIcons.get(userId);
+            if (info == null) {
+                info = getBitmapInfo(Resources.getSystem()
+                        .getDrawable(android.R.drawable.sym_def_app_icon), userId, 0, false);
+                mDefaultIcons.put(userId, info);
+            }
+
+            return new FastBitmapDrawable(info);
+        }
+    }
+
+    @Override
+    protected Drawable createBadgedDrawable(Drawable drawable, int userId, TaskDescription desc) {
+        return new FastBitmapDrawable(getBitmapInfo(drawable, userId, desc.getPrimaryColor(),
+                false));
+    }
+
+    private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId,
+            int primaryColor, boolean isInstantApp) {
+        if (mLauncherIcons == null) {
+            mLauncherIcons = LauncherIcons.obtain(mContext);
+        }
+
+        mLauncherIcons.setWrapperBackgroundColor(primaryColor);
+        // User version code O, so that the icon is always wrapped in an adaptive icon container.
+        return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId),
+                Build.VERSION_CODES.O, isInstantApp);
+    }
+
+    @Override
+    protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId,
+            TaskDescription desc) {
+        BitmapInfo bitmapInfo = getBitmapInfo(
+                activityInfo.loadUnbadgedIcon(mContext.getPackageManager()),
+                userId,
+                desc.getPrimaryColor(),
+                activityInfo.applicationInfo.isInstantApp());
+        return mDrawableFactory.newIcon(bitmapInfo, activityInfo);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 1e48a53..0e811f7 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -21,25 +21,23 @@
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.INVALID_POINTER_ID;
-import static com.android.quickstep.RemoteRunnable.executeSafely;
-import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
 
+import static com.android.systemui.shared.system.ActivityManagerWrapper
+        .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.metrics.LogMaker;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.SystemClock;
-import android.util.Log;
+import android.util.SparseArray;
 import android.view.Choreographer;
 import android.view.Display;
 import android.view.MotionEvent;
@@ -49,12 +47,12 @@
 import android.view.WindowManager;
 
 import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.TraceHelper;
-import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.AssistDataReceiver;
 import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.NavigationBarCompat;
 import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RecentsAnimationListener;
@@ -64,87 +62,62 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-class EventLogTags {
-    private EventLogTags() {
-    }  // don't instantiate
-
-    /** 524292 sysui_multi_action (content|4) */
-    public static final int SYSUI_MULTI_ACTION = 524292;
-
-    public static void writeSysuiMultiAction(Object[] content) {
-        android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content);
-    }
-}
-
-class MetricsLogger {
-    private static MetricsLogger sMetricsLogger;
-
-    private static MetricsLogger getLogger() {
-        if (sMetricsLogger == null) {
-            sMetricsLogger = new MetricsLogger();
-        }
-        return sMetricsLogger;
-    }
-
-    protected void saveLog(Object[] rep) {
-        EventLogTags.writeSysuiMultiAction(rep);
-    }
-
-    public void write(LogMaker content) {
-        if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) {
-            content.setType(4/*MetricsEvent.TYPE_ACTION*/);
-        }
-        saveLog(content.serialize());
-    }
-}
-
 /**
  * Touch consumer for handling events originating from an activity other than Launcher
  */
+@TargetApi(Build.VERSION_CODES.P)
 public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
-    private static final String TAG = "ActivityTouchConsumer";
 
     private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
 
+    private final SparseArray<RecentsAnimationState> mAnimationStates = new SparseArray<>();
     private final RunningTaskInfo mRunningTask;
     private final RecentsModel mRecentsModel;
     private final Intent mHomeIntent;
-    private final ISystemUiProxy mISystemUiProxy;
+    private final ActivityControlHelper mActivityControlHelper;
     private final MainThreadExecutor mMainThreadExecutor;
     private final Choreographer mBackgroundThreadChoreographer;
+    private final OverviewCallbacks mOverviewCallbacks;
+    private final TaskOverlayFactory mTaskOverlayFactory;
 
+    private final boolean mIsDeferredDownTarget;
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
     private int mActivePointerId = INVALID_POINTER_ID;
-    private boolean mTouchThresholdCrossed;
-    private int mTouchSlop;
+    private boolean mPassedInitialSlop;
+    // Used for non-deferred gestures to determine when to start dragging
+    private int mQuickStepDragSlop;
     private float mStartDisplacement;
-    private BaseSwipeInteractionHandler mInteractionHandler;
+    private WindowTransformSwipeHandler mInteractionHandler;
     private int mDisplayRotation;
     private Rect mStableInsets = new Rect();
-    private @HitTarget int mDownHitTarget = HIT_TARGET_NONE;
 
     private VelocityTracker mVelocityTracker;
     private MotionEventQueue mEventQueue;
-
-    private final MetricsLogger mMetricsLogger = new MetricsLogger();
+    private boolean mIsGoingToHome;
 
     public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
-            RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
-            MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer) {
+            RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
+            MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
+            @HitTarget int downHitTarget, OverviewCallbacks overviewCallbacks,
+            TaskOverlayFactory taskOverlayFactory, VelocityTracker velocityTracker) {
         super(base);
+
         mRunningTask = runningTaskInfo;
         mRecentsModel = recentsModel;
         mHomeIntent = homeIntent;
-        mVelocityTracker = VelocityTracker.obtain();
-        mISystemUiProxy = systemUiProxy;
+        mVelocityTracker = velocityTracker;
+        mActivityControlHelper = activityControl;
         mMainThreadExecutor = mainThreadExecutor;
         mBackgroundThreadChoreographer = backgroundThreadChoreographer;
+        mIsDeferredDownTarget = activityControl.deferStartingActivity(downHitTarget);
+        mOverviewCallbacks = overviewCallbacks;
+        mTaskOverlayFactory = taskOverlayFactory;
     }
 
     @Override
-    public void setDownHitTarget(@HitTarget int downHitTarget) {
-        mDownHitTarget = downHitTarget;
+    public void onShowOverviewFromAltTab() {
+        startTouchTrackingForWindowAnimation(SystemClock.uptimeMillis());
     }
 
     @Override
@@ -158,12 +131,12 @@
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
-                mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
-                mTouchThresholdCrossed = false;
+                mPassedInitialSlop = false;
+                mQuickStepDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
 
                 // Start the window animation on down to give more time for launcher to draw if the
                 // user didn't start the gesture over the back button
-                if (!isUsingScreenShot()) {
+                if (!mIsDeferredDownTarget) {
                     startTouchTrackingForWindowAnimation(ev.getEventTime());
                 }
 
@@ -191,25 +164,19 @@
                     break;
                 }
                 mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
-
-                float displacement = ev.getY(pointerIndex) - mDownPos.y;
-                if (isNavBarOnRight()) {
-                    displacement = ev.getX(pointerIndex) - mDownPos.x;
-                } else if (isNavBarOnLeft()) {
-                    displacement = mDownPos.x - ev.getX(pointerIndex);
-                }
-                if (!mTouchThresholdCrossed) {
-                    mTouchThresholdCrossed = Math.abs(displacement) >= mTouchSlop;
-                    if (mTouchThresholdCrossed) {
-                        mStartDisplacement = Math.signum(displacement) * mTouchSlop;
-
-                        if (isUsingScreenShot()) {
-                            startTouchTrackingForScreenshotAnimation();
+                float displacement = getDisplacement(ev);
+                if (!mPassedInitialSlop) {
+                    if (!mIsDeferredDownTarget) {
+                        // Normal gesture, ensure we pass the drag slop before we start tracking
+                        // the gesture
+                        if (Math.abs(displacement) > mQuickStepDragSlop) {
+                            mPassedInitialSlop = true;
+                            mStartDisplacement = displacement;
                         }
-
-                        notifyGestureStarted();
                     }
-                } else {
+                }
+
+                if (mPassedInitialSlop && mInteractionHandler != null) {
                     // Move
                     mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
                 }
@@ -220,20 +187,23 @@
             case ACTION_UP: {
                 TraceHelper.endSection("TouchInt");
 
-                finishTouchTracking();
+                finishTouchTracking(ev);
                 break;
             }
         }
     }
 
     private void notifyGestureStarted() {
+        if (mInteractionHandler == null) {
+            return;
+        }
+
+        mOverviewCallbacks.closeAllWindows();
+        ActivityManagerWrapper.getInstance().closeSystemWindows(
+                CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+
         // Notify the handler that the gesture has actually started
         mInteractionHandler.onGestureStarted();
-
-        // Notify the system that we have started tracking the event
-        if (mISystemUiProxy != null) {
-            executeSafely(mISystemUiProxy::onRecentsAnimationStarted);
-        }
     }
 
     private boolean isNavBarOnRight() {
@@ -244,74 +214,16 @@
         return mDisplayRotation == Surface.ROTATION_270 && mStableInsets.left > 0;
     }
 
-    private boolean isUsingScreenShot() {
-        return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_for_swipe_up", false);
-    }
-
-    /**
-     * Called when the gesture has started.
-     */
-    private void startTouchTrackingForScreenshotAnimation() {
-        // Create the shared handler
-        final NavBarSwipeInteractionHandler handler =
-                new NavBarSwipeInteractionHandler(mRunningTask, this, INTERACTION_NORMAL);
-
-        TraceHelper.partitionSection("TouchInt", "Thershold crossed ");
-
-        // Start the recents activity on a background thread
-        BackgroundExecutor.get().submit(() -> {
-            // Get the snap shot before
-            handler.setTaskSnapshot(getCurrentTaskSnapshot());
-
-            // Start the launcher activity with our custom handler
-            Intent homeIntent = handler.addToIntent(new Intent(mHomeIntent));
-            startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, 0).toBundle());
-            TraceHelper.partitionSection("TouchInt", "Home started");
-        });
-
-        // Preload the plan
-        mRecentsModel.loadTasks(mRunningTask.id, null);
-        mInteractionHandler = handler;
-        mInteractionHandler.setGestureEndCallback(this::onFinish);
-    }
-
-    private Bitmap getCurrentTaskSnapshot() {
-        TraceHelper.beginSection("TaskSnapshot");
-        // TODO: We are using some hardcoded layers for now, to best approximate the activity layers
-        Point displaySize = new Point();
-        Display display = getSystemService(WindowManager.class).getDefaultDisplay();
-        display.getRealSize(displaySize);
-        int rotation = display.getRotation();
-        // The rotation is backwards in landscape, so flip it.
-        if (rotation == Surface.ROTATION_270) {
-            rotation = Surface.ROTATION_90;
-        } else if (rotation == Surface.ROTATION_90) {
-            rotation = Surface.ROTATION_270;
-        }
-        try {
-            return mISystemUiProxy.screenshot(new Rect(), displaySize.x, displaySize.y, 0, 100000,
-                    false, rotation).toBitmap();
-        } catch (Exception e) {
-            Log.e(TAG, "Error capturing snapshot", e);
-
-            // Return a dummy bitmap
-            Bitmap bitmap = Bitmap.createBitmap(displaySize.x, displaySize.y, Config.RGB_565);
-            bitmap.eraseColor(Color.WHITE);
-            return bitmap;
-        } finally {
-            TraceHelper.endSection("TaskSnapshot");
-        }
-    }
-
     private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
         // Create the shared handler
-        final WindowTransformSwipeHandler handler =
-                new WindowTransformSwipeHandler(mRunningTask, this);
+        RecentsAnimationState animationState = new RecentsAnimationState();
+        final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
+                animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper);
 
         // Preload the plan
         mRecentsModel.loadTasks(mRunningTask.id, null);
         mInteractionHandler = handler;
-        handler.setGestureEndCallback(this::onFinish);
+        handler.setGestureEndCallback(mEventQueue::reset);
 
         CountDownLatch drawWaitLock = new CountDownLatch(1);
         handler.setLauncherOnDrawCallback(() -> {
@@ -320,45 +232,25 @@
                 switchToMainChoreographer();
             }
         });
-        handler.initWhenReady(mMainThreadExecutor);
+        handler.initWhenReady();
 
-        Runnable startActivity = () -> ActivityManagerWrapper.getInstance()
-                .startRecentsActivity(mHomeIntent,
+        TraceHelper.beginSection("RecentsController");
+
+        AssistDataReceiver assistDataReceiver = !mTaskOverlayFactory.needAssist() ? null :
                 new AssistDataReceiver() {
                     @Override
                     public void onHandleAssistData(Bundle bundle) {
-                        // Pass to AIAI
-                    }
-                },
-                new RecentsAnimationListener() {
-                    public void onAnimationStart(
-                            RecentsAnimationControllerCompat controller,
-                            RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
-                            Rect minimizedHomeBounds) {
-                        if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(controller, apps, homeContentInsets,
-                                    minimizedHomeBounds);
-                        } else {
-                            controller.finish(false /* toHome */);
-                        }
-
-                        // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
-                        // "Recents" activity for app transition tests.
-                        final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
-                        builder.setPackageName("com.android.systemui");
-                        builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
-                                "com.android.systemui.recents.RecentsActivity");
-                        builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
-                                SystemClock.uptimeMillis() - touchTimeMs);
-                        mMetricsLogger.write(builder);
-                    }
-
-                    public void onAnimationCanceled() {
-                        if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(null, null, null, null);
+                        if (mInteractionHandler == null) {
+                            // Interaction is probably complete
+                            mRecentsModel.preloadAssistData(mRunningTask.id, bundle);
+                        } else if (handler == mInteractionHandler) {
+                            handler.onAssistDataReceived(bundle);
                         }
                     }
-                }, null, null);
+                };
+
+        Runnable startActivity = () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+                mHomeIntent, assistDataReceiver, animationState, null, null);
 
         if (Looper.myLooper() != Looper.getMainLooper()) {
             startActivity.run();
@@ -374,12 +266,22 @@
         }
     }
 
+    @Override
+    public void onCommand(int command) {
+        RecentsAnimationState state = mAnimationStates.get(command);
+        if (state != null) {
+            state.execute();
+        }
+    }
+
     /**
      * Called when the gesture has ended. Does not correlate to the completion of the interaction as
      * the animation can still be running.
      */
-    private void finishTouchTracking() {
-        if (mTouchThresholdCrossed) {
+    private void finishTouchTracking(MotionEvent ev) {
+        if (mPassedInitialSlop && mInteractionHandler != null) {
+            mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement);
+
             mVelocityTracker.computeCurrentVelocity(1000,
                     ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
 
@@ -387,14 +289,15 @@
                     : isNavBarOnLeft() ? -mVelocityTracker.getXVelocity(mActivePointerId)
                             : mVelocityTracker.getYVelocity(mActivePointerId);
             mInteractionHandler.onGestureEnded(velocity);
-        } else if (!isUsingScreenShot()) {
+        } else {
             // Since we start touch tracking on DOWN, we may reach this state without actually
             // starting the gesture. In that case, just cleanup immediately.
             reset();
 
             // Also clean up in case the system has handled the UP and canceled the animation before
             // we had a chance to start the recents animation. In such a case, we will not receive
-            ActivityManagerWrapper.getInstance().cancelRecentsAnimation();
+            ActivityManagerWrapper.getInstance().cancelRecentsAnimation(
+                    true /* restoreHomeStackPosition */);
         }
         mVelocityTracker.recycle();
         mVelocityTracker = null;
@@ -404,33 +307,32 @@
     public void reset() {
         // Clean up the old interaction handler
         if (mInteractionHandler != null) {
-            final BaseSwipeInteractionHandler handler = mInteractionHandler;
-            mMainThreadExecutor.execute(handler::reset);
+            final WindowTransformSwipeHandler handler = mInteractionHandler;
             mInteractionHandler = null;
+            mIsGoingToHome = handler.mIsGoingToHome;
+            mMainThreadExecutor.execute(handler::reset);
         }
     }
 
     @Override
     public void updateTouchTracking(int interactionType) {
-        notifyGestureStarted();
-
-        if (isUsingScreenShot()) {
-            mMainThreadExecutor.execute(() -> {
-                if (mInteractionHandler != null) {
-                    mInteractionHandler.updateInteractionType(interactionType);
-                }
-            });
-        } else {
-            if (mInteractionHandler != null) {
-                mInteractionHandler.updateInteractionType(interactionType);
-            }
+        if (!mPassedInitialSlop && mIsDeferredDownTarget && mInteractionHandler == null) {
+            // If we deferred starting the window animation on touch down, then
+            // start tracking now
+            startTouchTrackingForWindowAnimation(SystemClock.uptimeMillis());
+            mPassedInitialSlop = true;
         }
+
+        if (mInteractionHandler != null) {
+            mInteractionHandler.updateInteractionType(interactionType);
+        }
+        notifyGestureStarted();
     }
 
     @Override
     public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
         mEventQueue = queue;
-        return isUsingScreenShot() ? null : mBackgroundThreadChoreographer;
+        return mBackgroundThreadChoreographer;
     }
 
     @Override
@@ -447,10 +349,28 @@
         }
     }
 
-    private void onFinish(BaseSwipeInteractionHandler handler) {
-        if (mInteractionHandler == handler) {
-            mInteractionHandler = null;
+    @Override
+    public void onQuickStep(MotionEvent ev) {
+        if (mIsDeferredDownTarget) {
+            // Deferred gesture, start the animation and gesture tracking once we pass the actual
+            // touch slop
+            startTouchTrackingForWindowAnimation(ev.getEventTime());
+            mPassedInitialSlop = true;
+            mStartDisplacement = getDisplacement(ev);
         }
+        notifyGestureStarted();
+    }
+
+    private float getDisplacement(MotionEvent ev) {
+        float eventX = ev.getX();
+        float eventY = ev.getY();
+        float displacement = eventY - mDownPos.y;
+        if (isNavBarOnRight()) {
+            displacement = eventX - mDownPos.x;
+        } else if (isNavBarOnLeft()) {
+            displacement = mDownPos.x - eventX;
+        }
+        return displacement;
     }
 
     public void switchToMainChoreographer() {
@@ -466,4 +386,66 @@
            }
         }
     }
+
+    @Override
+    public boolean forceToLauncherConsumer() {
+        return mIsGoingToHome;
+    }
+
+    @Override
+    public boolean deferNextEventToMainThread() {
+        // TODO: Consider also check if the eventQueue is using mainThread of not.
+        return mInteractionHandler != null;
+    }
+
+    private class RecentsAnimationState implements RecentsAnimationListener {
+
+        private final int id;
+
+        private RecentsAnimationControllerCompat mController;
+        private RemoteAnimationTargetSet mTargets;
+        private Rect mHomeContentInsets;
+        private Rect mMinimizedHomeBounds;
+        private boolean mCancelled;
+
+        public RecentsAnimationState() {
+            id = mAnimationStates.size();
+            mAnimationStates.put(id, this);
+        }
+
+        @Override
+        public void onAnimationStart(
+                RecentsAnimationControllerCompat controller,
+                RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
+                Rect minimizedHomeBounds) {
+            mController = controller;
+            mTargets = new RemoteAnimationTargetSet(apps, MODE_CLOSING);
+            mHomeContentInsets = homeContentInsets;
+            mMinimizedHomeBounds = minimizedHomeBounds;
+            mEventQueue.onCommand(id);
+        }
+
+        @Override
+        public void onAnimationCanceled() {
+            mCancelled = true;
+            mEventQueue.onCommand(id);
+        }
+
+        public void execute() {
+            if (mInteractionHandler == null || mInteractionHandler.id != id) {
+                if (!mCancelled && mController != null) {
+                    TraceHelper.endSection("RecentsController", "Finishing no handler");
+                    mController.finish(false /* toHome */);
+                }
+            } else if (mCancelled) {
+                TraceHelper.endSection("RecentsController",
+                        "Cancelled: " + mInteractionHandler);
+                mInteractionHandler.onRecentsAnimationCanceled();
+            } else {
+                TraceHelper.partitionSection("RecentsController", "Received");
+                mInteractionHandler.onRecentsAnimationStart(mController, mTargets,
+                        mHomeContentInsets, mMinimizedHomeBounds);
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/OverviewCallbacks.java b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
new file mode 100644
index 0000000..ef9c5c0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCallbacks.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.content.Context;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+/**
+ * Callbacks related to overview/quicksteps.
+ */
+public class OverviewCallbacks implements ResourceBasedOverride {
+
+    private static OverviewCallbacks sInstance;
+
+    public static OverviewCallbacks get(Context context) {
+        Preconditions.assertUIThread();
+        if (sInstance == null) {
+            sInstance = Overrides.getObject(OverviewCallbacks.class,
+                    context.getApplicationContext(), R.string.overview_callbacks_class);
+        }
+        return sInstance;
+    }
+
+    public void onInitOverviewTransition() { }
+
+    public void onResetOverview() { }
+
+    public void closeAllWindows() { }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
new file mode 100644
index 0000000..7c6eb32
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_CHANGED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
+import static com.android.systemui.shared.system.ActivityManagerWrapper
+        .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.systemui.shared.system.PackageManagerWrapper
+        .ACTION_PREFERRED_ACTIVITY_CHANGED;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.PatternMatcher;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.ActivityControlHelper.AnimationFactory;
+import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper;
+import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.TransformedRect;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.LatencyTrackerCompat;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.TransactionCompat;
+
+import java.util.ArrayList;
+
+/**
+ * Helper class to handle various atomic commands for switching between Overview.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class OverviewCommandHelper {
+
+    private static final long RECENTS_LAUNCH_DURATION = 250;
+
+    private static final String TAG = "OverviewCommandHelper";
+
+    private final Context mContext;
+    private final ActivityManagerWrapper mAM;
+    private final RecentsModel mRecentsModel;
+    private final MainThreadExecutor mMainThreadExecutor;
+    private final ComponentName mMyHomeComponent;
+
+    private final BroadcastReceiver mUserPreferenceChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            initOverviewTargets();
+        }
+    };
+    private final BroadcastReceiver mOtherHomeAppUpdateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            initOverviewTargets();
+        }
+    };
+    private String mUpdateRegisteredPackage;
+
+    public Intent overviewIntent;
+    public ComponentName overviewComponent;
+    private ActivityControlHelper mActivityControlHelper;
+
+    private long mLastToggleTime;
+
+    public OverviewCommandHelper(Context context) {
+        mContext = context;
+        mAM = ActivityManagerWrapper.getInstance();
+        mMainThreadExecutor = new MainThreadExecutor();
+        mRecentsModel = RecentsModel.getInstance(mContext);
+
+        Intent myHomeIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setPackage(mContext.getPackageName());
+        ResolveInfo info = context.getPackageManager().resolveActivity(myHomeIntent, 0);
+        mMyHomeComponent = new ComponentName(context.getPackageName(), info.activityInfo.name);
+
+        mContext.registerReceiver(mUserPreferenceChangeReceiver,
+                new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED));
+        initOverviewTargets();
+    }
+
+    private void initOverviewTargets() {
+        ComponentName defaultHome = PackageManagerWrapper.getInstance()
+                .getHomeActivities(new ArrayList<>());
+
+        final String overviewIntentCategory;
+        if (defaultHome == null || mMyHomeComponent.equals(defaultHome)) {
+            // User default home is same as out home app. Use Overview integrated in Launcher.
+            overviewComponent = mMyHomeComponent;
+            mActivityControlHelper = new LauncherActivityControllerHelper();
+            overviewIntentCategory = Intent.CATEGORY_HOME;
+
+            if (mUpdateRegisteredPackage != null) {
+                // Remove any update listener as we don't care about other packages.
+                mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
+                mUpdateRegisteredPackage = null;
+            }
+        } else {
+            // The default home app is a different launcher. Use the fallback Overview instead.
+            overviewComponent = new ComponentName(mContext, RecentsActivity.class);
+            mActivityControlHelper = new FallbackActivityControllerHelper(defaultHome);
+            overviewIntentCategory = Intent.CATEGORY_DEFAULT;
+
+            // User's default home app can change as a result of package updates of this app (such
+            // as uninstalling the app or removing the "Launcher" feature in an update).
+            // Listen for package updates of this app (and remove any previously attached
+            // package listener).
+            if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) {
+                if (mUpdateRegisteredPackage != null) {
+                    mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
+                }
+
+                mUpdateRegisteredPackage = defaultHome.getPackageName();
+                IntentFilter updateReceiver = new IntentFilter(ACTION_PACKAGE_ADDED);
+                updateReceiver.addAction(ACTION_PACKAGE_CHANGED);
+                updateReceiver.addAction(ACTION_PACKAGE_REMOVED);
+                updateReceiver.addDataScheme("package");
+                updateReceiver.addDataSchemeSpecificPart(mUpdateRegisteredPackage,
+                        PatternMatcher.PATTERN_LITERAL);
+                mContext.registerReceiver(mOtherHomeAppUpdateReceiver, updateReceiver);
+            }
+        }
+
+        overviewIntent = new Intent(Intent.ACTION_MAIN)
+                .addCategory(overviewIntentCategory)
+                .setComponent(overviewComponent)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    public void onDestroy() {
+        mContext.unregisterReceiver(mUserPreferenceChangeReceiver);
+
+        if (mUpdateRegisteredPackage != null) {
+            mContext.unregisterReceiver(mOtherHomeAppUpdateReceiver);
+            mUpdateRegisteredPackage = null;
+        }
+    }
+
+    public void onOverviewToggle() {
+        // If currently screen pinning, do not enter overview
+        if (mAM.isScreenPinningActive()) {
+            return;
+        }
+
+        mAM.closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+        mMainThreadExecutor.execute(new RecentsActivityCommand<>());
+    }
+
+    public void onOverviewShown() {
+        mMainThreadExecutor.execute(new ShowRecentsCommand());
+    }
+
+    public void onTip(int actionType, int viewType) {
+        mMainThreadExecutor.execute(() ->
+                UserEventDispatcher.newInstance(mContext).logActionTip(actionType, viewType));
+    }
+
+    public ActivityControlHelper getActivityControlHelper() {
+        return mActivityControlHelper;
+    }
+
+    private class ShowRecentsCommand extends RecentsActivityCommand {
+
+        @Override
+        protected boolean handleCommand(long elapsedTime) {
+            return mHelper.getVisibleRecentsView() != null;
+        }
+    }
+
+    private class RecentsActivityCommand<T extends BaseDraggingActivity> implements Runnable {
+
+        protected final ActivityControlHelper<T> mHelper;
+        private final long mCreateTime;
+        private final int mRunningTaskId;
+
+        private ActivityInitListener mListener;
+        private T mActivity;
+        private RecentsView mRecentsView;
+        private final long mToggleClickedTime = SystemClock.uptimeMillis();
+        private boolean mUserEventLogged;
+
+        public RecentsActivityCommand() {
+            mHelper = getActivityControlHelper();
+            mCreateTime = SystemClock.elapsedRealtime();
+            mRunningTaskId = mAM.getRunningTask().id;
+
+            // Preload the plan
+            mRecentsModel.loadTasks(mRunningTaskId, null);
+        }
+
+        @Override
+        public void run() {
+            long elapsedTime = mCreateTime - mLastToggleTime;
+            mLastToggleTime = mCreateTime;
+
+            if (!handleCommand(elapsedTime)) {
+                // Start overview
+                if (!mHelper.switchToRecentsIfVisible(true)) {
+                    mListener = mHelper.createActivityInitListener(this::onActivityReady);
+                    mListener.registerAndStartActivity(overviewIntent, this::createWindowAnimation,
+                            mContext, mMainThreadExecutor.getHandler(), RECENTS_LAUNCH_DURATION);
+                }
+            }
+        }
+
+        protected boolean handleCommand(long elapsedTime) {
+            // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
+            //       the menu activity which takes window focus, preventing the right condition from
+            //       being run below
+            RecentsView recents = mHelper.getVisibleRecentsView();
+            if (recents != null) {
+                // Launch the next task
+                recents.showNextTask();
+                return true;
+            } else if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+                // The user tried to launch back into overview too quickly, either after
+                // launching an app, or before overview has actually shown, just ignore for now
+                return true;
+            }
+            return false;
+        }
+
+        private boolean onActivityReady(T activity, Boolean wasVisible) {
+            activity.<RecentsView>getOverviewPanel().setCurrentTask(mRunningTaskId);
+            AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
+            AnimationFactory factory = mHelper.prepareRecentsUI(activity, wasVisible,
+                    (controller) -> {
+                        controller.dispatchOnStart();
+                        ValueAnimator anim = controller.getAnimationPlayer()
+                                .setDuration(RECENTS_LAUNCH_DURATION);
+                        anim.setInterpolator(FAST_OUT_SLOW_IN);
+                        anim.start();
+                });
+            factory.onRemoteAnimationReceived(null);
+            if (wasVisible) {
+                factory.createActivityController(RECENTS_LAUNCH_DURATION, INTERACTION_NORMAL);
+            }
+            mActivity = activity;
+            mRecentsView = mActivity.getOverviewPanel();
+            mRecentsView.setRunningTaskIconScaledDown(true);
+            if (!mUserEventLogged) {
+                activity.getUserEventDispatcher().logActionCommand(Action.Command.RECENTS_BUTTON,
+                        mHelper.getContainerType(), ContainerType.TASKSWITCHER);
+                mUserEventLogged = true;
+            }
+            return false;
+        }
+
+        private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) {
+            if (LatencyTrackerCompat.isEnabled(mContext)) {
+                LatencyTrackerCompat.logToggleRecents(
+                        (int) (SystemClock.uptimeMillis() - mToggleClickedTime));
+            }
+
+            if (mListener != null) {
+                mListener.unregister();
+            }
+            AnimatorSet anim = new AnimatorSet();
+            anim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    if (mRecentsView != null) {
+                        mRecentsView.animateUpRunningTaskIconScale();
+                    }
+                }
+            });
+            if (mActivity == null) {
+                Log.e(TAG, "Animation created, before activity");
+                anim.play(ValueAnimator.ofInt(0, 1).setDuration(100));
+                return anim;
+            }
+
+            RemoteAnimationTargetSet targetSet =
+                    new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING);
+
+            // Use the top closing app to determine the insets for the animation
+            RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
+            if (runningTaskTarget == null) {
+                Log.e(TAG, "No closing app");
+                anim.play(ValueAnimator.ofInt(0, 1).setDuration(100));
+                return anim;
+            }
+
+            final ClipAnimationHelper clipHelper = new ClipAnimationHelper();
+
+            // At this point, the activity is already started and laid-out. Get the home-bounds
+            // relative to the screen using the rootView of the activity.
+            int loc[] = new int[2];
+            View rootView = mActivity.getRootView();
+            rootView.getLocationOnScreen(loc);
+            Rect homeBounds = new Rect(loc[0], loc[1],
+                    loc[0] + rootView.getWidth(), loc[1] + rootView.getHeight());
+            clipHelper.updateSource(homeBounds, runningTaskTarget);
+
+            TransformedRect targetRect = new TransformedRect();
+            mHelper.getSwipeUpDestinationAndLength(mActivity.getDeviceProfile(), mActivity,
+                    INTERACTION_NORMAL, targetRect);
+            clipHelper.updateTargetRect(targetRect);
+            clipHelper.prepareAnimation(false /* isOpening */);
+
+            SyncRtSurfaceTransactionApplier syncTransactionApplier =
+                    new SyncRtSurfaceTransactionApplier(rootView);
+            ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
+            valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
+            valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+            valueAnimator.addUpdateListener((v) ->
+                    clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue(),
+                            syncTransactionApplier));
+
+            if (targetSet.isAnimatingHome()) {
+                // If we are animating home, fade in the opening targets
+                RemoteAnimationTargetSet openingSet =
+                        new RemoteAnimationTargetSet(targetCompats, MODE_OPENING);
+
+                TransactionCompat transaction = new TransactionCompat();
+                valueAnimator.addUpdateListener((v) -> {
+                    for (RemoteAnimationTargetCompat app : openingSet.apps) {
+                        transaction.setAlpha(app.leash, (float) v.getAnimatedValue());
+                    }
+                    transaction.apply();
+                });
+            }
+            anim.play(valueAnimator);
+            return anim;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 3c68281..922a7ff 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,24 +15,36 @@
  */
 package com.android.quickstep;
 
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
+import static com.android.systemui.shared.system.SettingsCompat.SWIPE_UP_SETTING_NAME;
 
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.provider.Settings;
+import android.support.annotation.WorkerThread;
 import android.util.Log;
 
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 
+import java.util.concurrent.ExecutionException;
+
 /**
  * Sets overview interaction flags, such as:
  *
  *   - FLAG_DISABLE_QUICK_SCRUB
  *   - FLAG_DISABLE_SWIPE_UP
- *   - FLAG_HIDE_BACK_BUTTON
  *   - FLAG_SHOW_OVERVIEW_BUTTON
  *
  * @see com.android.systemui.shared.system.NavigationBarCompat.InteractionType and associated flags.
@@ -40,52 +52,201 @@
 public class OverviewInteractionState {
 
     private static final String TAG = "OverviewFlags";
-    private static final Handler sUiHandler = new Handler(Looper.getMainLooper()) {
-        @Override
-        public void handleMessage(Message msg) {
-            updateOverviewInteractionFlag((Context) msg.obj, msg.what, msg.arg1 == 1);
-        }
-    };
-    private static final Handler sBackgroundHandler = new Handler(
-            UiThreadHelper.getBackgroundLooper()) {
-        @Override
-        public void handleMessage(Message msg) {
-            ISystemUiProxy systemUiProxy = (ISystemUiProxy) msg.obj;
-            int flags = msg.what;
-            try {
-                systemUiProxy.setInteractionState(flags);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Unable to update overview interaction flags", e);
+
+    private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
+    private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
+            "config_swipe_up_gesture_setting_available";
+    private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
+            "config_swipe_up_gesture_default";
+
+    // We do not need any synchronization for this variable as its only written on UI thread.
+    private static OverviewInteractionState INSTANCE;
+
+    public static OverviewInteractionState getInstance(final Context context) {
+        if (INSTANCE == null) {
+            if (Looper.myLooper() == Looper.getMainLooper()) {
+                INSTANCE = new OverviewInteractionState(context.getApplicationContext());
+            } else {
+                try {
+                    return new MainThreadExecutor().submit(
+                            () -> OverviewInteractionState.getInstance(context)).get();
+                } catch (InterruptedException|ExecutionException e) {
+                    throw new RuntimeException(e);
+                }
             }
         }
-    };
-
-    private static int sFlags;
-
-    public static void setBackButtonVisible(Context context, boolean visible) {
-        updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
+        return INSTANCE;
     }
 
-    private static void updateFlagOnUi(Context context, int flag, boolean enabled) {
-        sUiHandler.removeMessages(flag);
-        sUiHandler.sendMessage(sUiHandler.obtainMessage(flag, enabled ? 1 : 0, 0, context));
-    }
+    private static final int MSG_SET_PROXY = 200;
+    private static final int MSG_SET_BACK_BUTTON_ALPHA = 201;
+    private static final int MSG_SET_SWIPE_UP_ENABLED = 202;
 
-    private static void updateOverviewInteractionFlag(Context context, int flag, boolean enabled) {
-        if (enabled) {
-            sFlags |= flag;
+    private final SwipeUpGestureEnabledSettingObserver mSwipeUpSettingObserver;
+
+    private final Context mContext;
+    private final Handler mUiHandler;
+    private final Handler mBgHandler;
+
+    // These are updated on the background thread
+    private ISystemUiProxy mISystemUiProxy;
+    private boolean mSwipeUpEnabled = true;
+    private float mBackButtonAlpha = 1;
+
+    private Runnable mOnSwipeUpSettingChangedListener;
+
+    private OverviewInteractionState(Context context) {
+        mContext = context;
+
+        // Data posted to the uihandler will be sent to the bghandler. Data is sent to uihandler
+        // because of its high send frequency and data may be very different than the previous value
+        // For example, send back alpha on uihandler to avoid flickering when setting its visibility
+        mUiHandler = new Handler(this::handleUiMessage);
+        mBgHandler = new Handler(UiThreadHelper.getBackgroundLooper(), this::handleBgMessage);
+
+        if (getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME)) {
+            mSwipeUpSettingObserver = new SwipeUpGestureEnabledSettingObserver(mUiHandler,
+                    context.getContentResolver());
+            mSwipeUpSettingObserver.register();
         } else {
-            sFlags &= ~flag;
+            mSwipeUpSettingObserver = null;
+            mSwipeUpEnabled = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
         }
+    }
 
-        ISystemUiProxy systemUiProxy = RecentsModel.getInstance(context).getSystemUiProxy();
-        if (systemUiProxy == null) {
-            Log.w(TAG, "Unable to update overview interaction flags; not bound to service");
+    public boolean isSwipeUpGestureEnabled() {
+        return mSwipeUpEnabled;
+    }
+
+    public float getBackButtonAlpha() {
+        return mBackButtonAlpha;
+    }
+
+    public void setBackButtonAlpha(float alpha, boolean animate) {
+        if (!mSwipeUpEnabled) {
+            alpha = 1;
+        }
+        mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_ALPHA);
+        mUiHandler.obtainMessage(MSG_SET_BACK_BUTTON_ALPHA, animate ? 1 : 0, 0, alpha)
+                .sendToTarget();
+    }
+
+    public void setSystemUiProxy(ISystemUiProxy proxy) {
+        mBgHandler.obtainMessage(MSG_SET_PROXY, proxy).sendToTarget();
+    }
+
+    private boolean handleUiMessage(Message msg) {
+        if (msg.what == MSG_SET_BACK_BUTTON_ALPHA) {
+            mBackButtonAlpha = (float) msg.obj;
+        }
+        mBgHandler.obtainMessage(msg.what, msg.arg1, msg.arg2, msg.obj).sendToTarget();
+        return true;
+    }
+
+    private boolean handleBgMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_SET_PROXY:
+                mISystemUiProxy = (ISystemUiProxy) msg.obj;
+                break;
+            case MSG_SET_BACK_BUTTON_ALPHA:
+                applyBackButtonAlpha((float) msg.obj, msg.arg1 == 1);
+                return true;
+            case MSG_SET_SWIPE_UP_ENABLED:
+                mSwipeUpEnabled = msg.arg1 != 0;
+                resetHomeBounceSeenOnQuickstepEnabledFirstTime();
+
+                if (mOnSwipeUpSettingChangedListener != null) {
+                    mOnSwipeUpSettingChangedListener.run();
+                }
+                break;
+        }
+        applyFlags();
+        return true;
+    }
+
+    public void setOnSwipeUpSettingChangedListener(Runnable listener) {
+        mOnSwipeUpSettingChangedListener = listener;
+    }
+
+    @WorkerThread
+    private void applyFlags() {
+        if (mISystemUiProxy == null) {
             return;
         }
-        // If we aren't already setting these flags, do so now on the background thread.
-        if (!sBackgroundHandler.hasMessages(sFlags)) {
-            sBackgroundHandler.sendMessage(sBackgroundHandler.obtainMessage(sFlags, systemUiProxy));
+
+        int flags = 0;
+        if (!mSwipeUpEnabled) {
+            flags = FLAG_DISABLE_SWIPE_UP | FLAG_DISABLE_QUICK_SCRUB | FLAG_SHOW_OVERVIEW_BUTTON;
+        }
+        try {
+            mISystemUiProxy.setInteractionState(flags);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Unable to update overview interaction flags", e);
+        }
+    }
+
+    @WorkerThread
+    private void applyBackButtonAlpha(float alpha, boolean animate) {
+        if (mISystemUiProxy == null) {
+            return;
+        }
+        try {
+            mISystemUiProxy.setBackButtonAlpha(alpha, animate);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Unable to update overview back button alpha", e);
+        }
+    }
+
+    private class SwipeUpGestureEnabledSettingObserver extends ContentObserver {
+        private Handler mHandler;
+        private ContentResolver mResolver;
+        private final int defaultValue;
+
+        SwipeUpGestureEnabledSettingObserver(Handler handler, ContentResolver resolver) {
+            super(handler);
+            mHandler = handler;
+            mResolver = resolver;
+            defaultValue = getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME) ? 1 : 0;
+        }
+
+        public void register() {
+            mResolver.registerContentObserver(Settings.Secure.getUriFor(SWIPE_UP_SETTING_NAME),
+                    false, this);
+            mSwipeUpEnabled = getValue();
+            resetHomeBounceSeenOnQuickstepEnabledFirstTime();
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            mHandler.removeMessages(MSG_SET_SWIPE_UP_ENABLED);
+            mHandler.obtainMessage(MSG_SET_SWIPE_UP_ENABLED, getValue() ? 1 : 0, 0).sendToTarget();
+        }
+
+        private boolean getValue() {
+            return Settings.Secure.getInt(mResolver, SWIPE_UP_SETTING_NAME, defaultValue) == 1;
+        }
+    }
+
+    private boolean getSystemBooleanRes(String resName) {
+        Resources res = Resources.getSystem();
+        int resId = res.getIdentifier(resName, "bool", "android");
+
+        if (resId != 0) {
+            return res.getBoolean(resId);
+        } else {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+            return false;
+        }
+    }
+
+    private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
+        if (mSwipeUpEnabled && !Utilities.getPrefs(mContext).getBoolean(
+                HAS_ENABLED_QUICKSTEP_ONCE, true)) {
+            Utilities.getPrefs(mContext).edit()
+                    .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
+                    .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false)
+                    .apply();
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index bc7647a..cbc7a67 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -16,11 +16,20 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.util.Log;
 import android.view.HapticFeedbackConstants;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.Alarm;
+import com.android.launcher3.BaseActivity;
 import com.android.launcher3.OnAlarmListener;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 
 /**
  * Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -30,99 +39,199 @@
  */
 public class QuickScrubController implements OnAlarmListener {
 
-    public static final int QUICK_SWITCH_START_DURATION = 133;
-    public static final int QUICK_SWITCH_SNAP_DURATION = 120;
+    public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240;
+    public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200;
+    // We want the translation y to finish faster than the rest of the animation.
+    public static final float QUICK_SCRUB_TRANSLATION_Y_FACTOR = 5f / 6;
+    public static final Interpolator QUICK_SCRUB_START_INTERPOLATOR = FAST_OUT_SLOW_IN;
 
-    private static final int NUM_QUICK_SCRUB_SECTIONS = 5;
+    /**
+     * Snap to a new page when crossing these thresholds. The first and last auto-advance.
+     */
+    private static final float[] QUICK_SCRUB_THRESHOLDS = new float[] {
+            0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f
+    };
+
+    private static final String TAG = "QuickScrubController";
+    private static final boolean ENABLE_AUTO_ADVANCE = true;
     private static final long AUTO_ADVANCE_DELAY = 500;
     private static final int QUICKSCRUB_SNAP_DURATION_PER_PAGE = 325;
     private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60;
 
     private final Alarm mAutoAdvanceAlarm;
     private final RecentsView mRecentsView;
+    private final BaseActivity mActivity;
 
     private boolean mInQuickScrub;
+    private boolean mWaitingForTaskLaunch;
     private int mQuickScrubSection;
-    private int mStartPage;
+    private boolean mStartedFromHome;
+    private boolean mFinishedTransitionToQuickScrub;
+    private Runnable mOnFinishedTransitionToQuickScrubRunnable;
+    private ActivityControlHelper mActivityControlHelper;
 
-    public QuickScrubController(RecentsView recentsView) {
+    public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
+        mActivity = activity;
         mRecentsView = recentsView;
-        mAutoAdvanceAlarm = new Alarm();
-        mAutoAdvanceAlarm.setOnAlarmListener(this);
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm = new Alarm();
+            mAutoAdvanceAlarm.setOnAlarmListener(this);
+        }
     }
 
-    public void onQuickScrubStart(boolean startingFromHome) {
+    public void onQuickScrubStart(boolean startingFromHome, ActivityControlHelper controlHelper) {
+        prepareQuickScrub(TAG);
         mInQuickScrub = true;
-        mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
+        mStartedFromHome = startingFromHome;
         mQuickScrubSection = 0;
+        mFinishedTransitionToQuickScrub = false;
+        mActivityControlHelper = controlHelper;
+
+        snapToNextTaskIfAvailable();
+        mActivity.getUserEventDispatcher().resetActionDurationMillis();
     }
 
     public void onQuickScrubEnd() {
         mInQuickScrub = false;
-        mAutoAdvanceAlarm.cancelAlarm();
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm.cancelAlarm();
+        }
         int page = mRecentsView.getNextPage();
         Runnable launchTaskRunnable = () -> {
-            if (page < mRecentsView.getFirstTaskIndex()) {
-                mRecentsView.getPageAt(page).performClick();
+            TaskView taskView = mRecentsView.getTaskViewAt(page);
+            if (taskView != null) {
+                mWaitingForTaskLaunch = true;
+                taskView.launchTask(true, (result) -> {
+                    if (!result) {
+                        taskView.notifyTaskLaunchFailed(TAG);
+                        breakOutOfQuickScrub();
+                    } else {
+                        mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(Touch.DRAGDROP,
+                                LauncherLogProto.Action.Direction.NONE, page,
+                                TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key));
+                    }
+                    mWaitingForTaskLaunch = false;
+                }, taskView.getHandler());
             } else {
-                ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
+                breakOutOfQuickScrub();
             }
+            mActivityControlHelper = null;
         };
         int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
                 * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
-        if (mRecentsView.snapToPage(page, snapDuration)) {
+        if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) {
             // Settle on the page then launch it
             mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
         } else {
             // No page move needed, just launch it
-            launchTaskRunnable.run();
+            if (mFinishedTransitionToQuickScrub) {
+                launchTaskRunnable.run();
+            } else {
+                mOnFinishedTransitionToQuickScrubRunnable = launchTaskRunnable;
+            }
+        }
+    }
+
+    public void cancelActiveQuickscrub() {
+        if (!mInQuickScrub) {
+            return;
+        }
+        Log.d(TAG, "Quickscrub was active, cancelling");
+        mInQuickScrub = false;
+        mActivityControlHelper = null;
+        mOnFinishedTransitionToQuickScrubRunnable = null;
+        mRecentsView.setNextPageSwitchRunnable(null);
+    }
+
+    /**
+     * Initializes the UI for quick scrub, returns true if success.
+     */
+    public boolean prepareQuickScrub(String tag) {
+        if (mWaitingForTaskLaunch || mInQuickScrub) {
+            Log.d(tag, "Waiting for last scrub to finish, will skip this interaction");
+            return false;
+        }
+        mOnFinishedTransitionToQuickScrubRunnable = null;
+        mRecentsView.setNextPageSwitchRunnable(null);
+        return true;
+    }
+
+    public boolean isWaitingForTaskLaunch() {
+        return mWaitingForTaskLaunch;
+    }
+
+    /**
+     * Attempts to go to normal overview or back to home, so UI doesn't prevent user interaction.
+     */
+    private void breakOutOfQuickScrub() {
+        if (mRecentsView.getChildCount() == 0 || mActivityControlHelper == null
+                || !mActivityControlHelper.switchToRecentsIfVisible(false)) {
+            mActivity.onBackPressed();
         }
     }
 
     public void onQuickScrubProgress(float progress) {
-        int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
+        int quickScrubSection = 0;
+        for (float threshold : QUICK_SCRUB_THRESHOLDS) {
+            if (progress < threshold) {
+                break;
+            }
+            quickScrubSection++;
+        }
         if (quickScrubSection != mQuickScrubSection) {
+            boolean cameFromAutoAdvance = mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length
+                    || mQuickScrubSection == 0;
             int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
-            goToPageWithHaptic(pageToGoTo);
-            if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
-                mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
-            } else {
-                mAutoAdvanceAlarm.cancelAlarm();
+            if (mFinishedTransitionToQuickScrub && !cameFromAutoAdvance) {
+                goToPageWithHaptic(pageToGoTo);
+            }
+            if (ENABLE_AUTO_ADVANCE) {
+                if (quickScrubSection == QUICK_SCRUB_THRESHOLDS.length || quickScrubSection == 0) {
+                    mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+                } else {
+                    mAutoAdvanceAlarm.cancelAlarm();
+                }
             }
             mQuickScrubSection = quickScrubSection;
         }
     }
 
-    public void onQuickSwitch() {
-        for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
-            TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
-            if (taskView.getTask().key.id != mRecentsView.getRunningTaskId()) {
-                Runnable launchTaskRunnable = () -> taskView.launchTask(true);
-                if (mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION)) {
-                    // Snap to the new page then launch it
-                    mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
-                } else {
-                    // No need to move page, just launch task directly
-                    launchTaskRunnable.run();
-                }
-                break;
-            }
+    public void onFinishedTransitionToQuickScrub() {
+        mFinishedTransitionToQuickScrub = true;
+        Runnable action = mOnFinishedTransitionToQuickScrubRunnable;
+        // Clear the runnable before executing it, to prevent potential recursion.
+        mOnFinishedTransitionToQuickScrubRunnable = null;
+        if (action != null) {
+            action.run();
         }
     }
 
-    public void snapToPageForCurrentQuickScrubSection() {
-        if (mInQuickScrub) {
-            goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+    public void snapToNextTaskIfAvailable() {
+        if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
+            int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION
+                    : QUICK_SCRUB_FROM_APP_START_DURATION;
+            int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
+            goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
+                    QUICK_SCRUB_START_INTERPOLATOR);
         }
     }
 
     private void goToPageWithHaptic(int pageToGoTo) {
-        pageToGoTo = Utilities.boundToRange(pageToGoTo, mStartPage, mRecentsView.getPageCount() - 1);
-        if (pageToGoTo != mRecentsView.getNextPage()) {
-            int duration = Math.abs(pageToGoTo - mRecentsView.getNextPage())
-                    * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
-            mRecentsView.snapToPage(pageToGoTo, duration);
-            mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
+        goToPageWithHaptic(pageToGoTo, -1 /* overrideDuration */, false /* forceHaptic */, null);
+    }
+
+    private void goToPageWithHaptic(int pageToGoTo, int overrideDuration, boolean forceHaptic,
+            Interpolator interpolator) {
+        pageToGoTo = Utilities.boundToRange(pageToGoTo, 0, mRecentsView.getTaskViewCount() - 1);
+        boolean snappingToPage = pageToGoTo != mRecentsView.getNextPage();
+        if (snappingToPage) {
+            int duration = overrideDuration > -1 ? overrideDuration
+                    : Math.abs(pageToGoTo - mRecentsView.getNextPage())
+                            * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
+            mRecentsView.snapToPage(pageToGoTo, duration, interpolator);
+        }
+        if (snappingToPage || forceHaptic) {
+            mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
         }
     }
@@ -130,12 +239,20 @@
     @Override
     public void onAlarm(Alarm alarm) {
         int currPage = mRecentsView.getNextPage();
-        if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
-                && currPage < mRecentsView.getPageCount() - 1) {
+        boolean recentsVisible = mActivityControlHelper != null
+                && mActivityControlHelper.getVisibleRecentsView() != null;
+        if (!recentsVisible) {
+            Log.w(TAG, "Failed to auto advance; recents not visible");
+            return;
+        }
+        if (mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length
+                && currPage < mRecentsView.getTaskViewCount() - 1) {
             goToPageWithHaptic(currPage + 1);
-        } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
+        } else if (mQuickScrubSection == 0 && currPage > 0) {
             goToPageWithHaptic(currPage - 1);
         }
-        mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
new file mode 100644
index 0000000..2c3f77f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.content.Context;
+
+import com.android.launcher3.MainProcessInitializer;
+import com.android.systemui.shared.system.ThreadedRendererCompat;
+
+@SuppressWarnings("unused")
+public class QuickstepProcessInitializer extends MainProcessInitializer {
+
+    public QuickstepProcessInitializer(Context context) { }
+
+    @Override
+    protected void init(Context context) {
+        super.init(context);
+
+        // Elevate GPU priority for Quickstep and Remote animations.
+        ThreadedRendererCompat.setContextPriority(ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index f92d773..32079bf 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -15,34 +15,256 @@
  */
 package com.android.quickstep;
 
-import android.app.ListActivity;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.support.annotation.Nullable;
-import android.widget.ArrayAdapter;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
 
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
+import static com.android.quickstep.TaskUtils.getRecentsWindowAnimator;
+import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAnimationRunner;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.badge.BadgeInfo;
+import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsRootView;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 /**
  * A simple activity to show the recently launched tasks
  */
-public class RecentsActivity extends ListActivity {
+public class RecentsActivity extends BaseDraggingActivity {
 
-    private ArrayAdapter<Task> mAdapter;
+    private Handler mUiHandler = new Handler(Looper.getMainLooper());
+    private RecentsRootView mRecentsRootView;
+    private FallbackRecentsView mFallbackRecentsView;
+
+    private Configuration mOldConfig;
 
     @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(this);
-        plan.preloadPlan(new PreloadOptions(), new RecentsTaskLoader(this, 1, 1, 0), -1,
-                UserHandle.myUserId());
+        mOldConfig = new Configuration(getResources().getConfiguration());
+        initDeviceProfile();
 
-        mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
-        mAdapter.addAll(plan.getTaskStack().getTasks());
-        setListAdapter(mAdapter);
+        setContentView(R.layout.fallback_recents_activity);
+        mRecentsRootView = findViewById(R.id.drag_layer);
+        mFallbackRecentsView = findViewById(R.id.overview_panel);
+
+        mRecentsRootView.setup();
+
+        getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
+                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+        RecentsActivityTracker.onRecentsActivityCreate(this);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        int diff = newConfig.diff(mOldConfig);
+        if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
+            onHandleConfigChanged();
+        }
+        mOldConfig.setTo(newConfig);
+        super.onConfigurationChanged(newConfig);
+    }
+
+    @Override
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
+        onHandleConfigChanged();
+        super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
+    }
+
+    public void onRootViewSizeChanged() {
+        if (isInMultiWindowModeCompat()) {
+            onHandleConfigChanged();
+        }
+    }
+
+    private void onHandleConfigChanged() {
+        mUserEventDispatcher = null;
+        initDeviceProfile();
+
+        AbstractFloatingView.closeOpenViews(this, true,
+                AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+        dispatchDeviceProfileChanged();
+
+        mRecentsRootView.setup();
+        reapplyUi();
+    }
+
+    @Override
+    protected void reapplyUi() {
+        mRecentsRootView.dispatchInsets();
+    }
+
+    private void initDeviceProfile() {
+        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
+
+        // In case we are reusing IDP, create a copy so that we don't conflict with Launcher
+        // activity.
+        mDeviceProfile = (mRecentsRootView != null) && isInMultiWindowModeCompat()
+                ? dp.getMultiWindowProfile(this, mRecentsRootView.getLastKnownSize())
+                : dp.copy(this);
+        onDeviceProfileInitiated();
+    }
+
+    @Override
+    public BaseDragLayer getDragLayer() {
+        return mRecentsRootView;
+    }
+
+    @Override
+    public View getRootView() {
+        return mRecentsRootView;
+    }
+
+    @Override
+    public <T extends View> T getOverviewPanel() {
+        return (T) mFallbackRecentsView;
+    }
+
+    @Override
+    public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
+        return null;
+    }
+
+    @Override
+    public ActivityOptions getActivityLaunchOptions(final View v) {
+        if (!(v instanceof TaskView)) {
+            return null;
+        }
+
+        final TaskView taskView = (TaskView) v;
+        RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
+                true /* startAtFrontOfQueue */) {
+
+            @Override
+            public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
+                    AnimationResult result) {
+                result.setAnimation(composeRecentsLaunchAnimator(taskView, targetCompats));
+            }
+        };
+        return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
+                runner, RECENTS_LAUNCH_DURATION,
+                RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
+                        - STATUS_BAR_TRANSITION_PRE_DELAY));
+    }
+
+    /**
+     * Composes the animations for a launch from the recents list if possible.
+     */
+    private AnimatorSet composeRecentsLaunchAnimator(TaskView taskView,
+            RemoteAnimationTargetCompat[] targets) {
+        AnimatorSet target = new AnimatorSet();
+        boolean activityClosing = taskIsATargetWithMode(targets, getTaskId(), MODE_CLOSING);
+        ClipAnimationHelper helper = new ClipAnimationHelper();
+        target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets, helper)
+                .setDuration(RECENTS_LAUNCH_DURATION));
+
+        // Found a visible recents task that matches the opening app, lets launch the app from there
+        if (activityClosing) {
+            Animator adjacentAnimation = mFallbackRecentsView
+                    .createAdjacentPageAnimForTaskLaunch(taskView, helper);
+            adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+            adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
+            adjacentAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mFallbackRecentsView.resetTaskVisuals();
+                }
+            });
+            target.play(adjacentAnimation);
+        }
+        return target;
+    }
+
+    @Override
+    public void invalidateParent(ItemInfo info) { }
+
+    @Override
+    protected void onStart() {
+        // Set the alpha to 1 before calling super, as it may get set back to 0 due to
+        // onActivityStart callback.
+        mFallbackRecentsView.setContentAlpha(1);
+        super.onStart();
+        UiFactory.onStart(this);
+        mFallbackRecentsView.resetTaskVisuals();
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        // Workaround for b/78520668, explicitly trim memory once UI is hidden
+        onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+        UiFactory.onTrimMemory(this, level);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        RecentsActivityTracker.onRecentsActivityNewIntent(this);
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        RecentsActivityTracker.onRecentsActivityDestroy(this);
+    }
+
+    @Override
+    public void onBackPressed() {
+        // TODO: Launch the task we came from
+        startHome();
+    }
+
+    public void startHome() {
+        startActivity(new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        super.dump(prefix, fd, writer, args);
+        writer.println(prefix + "Misc:");
+        dumpMisc(writer);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
new file mode 100644
index 0000000..fb6090e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+
+import com.android.launcher3.MainThreadExecutor;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.util.RemoteAnimationProvider;
+
+import java.lang.ref.WeakReference;
+import java.util.function.BiPredicate;
+
+/**
+ * Utility class to track create/destroy for RecentsActivity
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class RecentsActivityTracker implements ActivityInitListener {
+
+    private static WeakReference<RecentsActivity> sCurrentActivity = new WeakReference<>(null);
+    private static final Scheduler sScheduler = new Scheduler();
+
+    private final BiPredicate<RecentsActivity, Boolean> mOnInitListener;
+
+    public RecentsActivityTracker(BiPredicate<RecentsActivity, Boolean> onInitListener) {
+        mOnInitListener = onInitListener;
+    }
+
+    @Override
+    public void register() {
+        sScheduler.schedule(this);
+    }
+
+    @Override
+    public void unregister() {
+        sScheduler.clearReference(this);
+    }
+
+    private boolean init(RecentsActivity activity, boolean visible) {
+        return mOnInitListener.test(activity, visible);
+    }
+
+    public static RecentsActivity getCurrentActivity() {
+        return sCurrentActivity.get();
+    }
+
+    @Override
+    public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+            Context context, Handler handler, long duration) {
+        register();
+
+        Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
+        context.startActivity(intent, options);
+    }
+
+    public static void onRecentsActivityCreate(RecentsActivity activity) {
+        sCurrentActivity = new WeakReference<>(activity);
+        sScheduler.initIfPending(activity, false);
+    }
+
+
+    public static void onRecentsActivityNewIntent(RecentsActivity activity) {
+        sScheduler.initIfPending(activity, activity.isStarted());
+    }
+
+    public static void onRecentsActivityDestroy(RecentsActivity activity) {
+        if (sCurrentActivity.get() == activity) {
+            sCurrentActivity.clear();
+        }
+    }
+
+
+    private static class Scheduler implements Runnable {
+
+        private WeakReference<RecentsActivityTracker> mPendingTracker = new WeakReference<>(null);
+        private MainThreadExecutor mMainThreadExecutor;
+
+        public synchronized void schedule(RecentsActivityTracker tracker) {
+            mPendingTracker = new WeakReference<>(tracker);
+            if (mMainThreadExecutor == null) {
+                mMainThreadExecutor = new MainThreadExecutor();
+            }
+            mMainThreadExecutor.execute(this);
+        }
+
+        @Override
+        public void run() {
+            RecentsActivity activity = sCurrentActivity.get();
+            if (activity != null) {
+                initIfPending(activity, activity.isStarted());
+            }
+        }
+
+        public synchronized boolean initIfPending(RecentsActivity activity, boolean alreadyOnHome) {
+            RecentsActivityTracker tracker = mPendingTracker.get();
+            if (tracker != null) {
+                if (!tracker.init(activity, alreadyOnHome)) {
+                    mPendingTracker.clear();
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public synchronized boolean clearReference(RecentsActivityTracker tracker) {
+            if (mPendingTracker.get() == tracker) {
+                mPendingTracker.clear();
+                return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
deleted file mode 100644
index 9cc038f..0000000
--- a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.graphics.Rect;
-
-import com.android.launcher3.Utilities;
-
-/**
- * Helper class to interpolate the animation between a task view representation and an actual
- * window.
- */
-public class RecentsAnimationInterpolator {
-
-    public static class TaskWindowBounds {
-        public float taskScale = 1f;
-        public float taskX = 0f;
-        public float taskY = 0f;
-
-        public float winScale = 1f;
-        public float winX = 0f;
-        public float winY = 0f;
-        public Rect winCrop = new Rect();
-
-        @Override
-        public String toString() {
-            return "taskScale=" + taskScale + " taskX=" + taskX + " taskY=" + taskY
-                    + " winScale=" + winScale + " winX=" + winX + " winY=" + winY
-                    + " winCrop=" + winCrop;
-        }
-    }
-
-    private TaskWindowBounds mTmpTaskWindowBounds = new TaskWindowBounds();
-    private Rect mTmpInsets = new Rect();
-
-    private Rect mWindow;
-    private Rect mInsetWindow;
-    private Rect mInsets;
-    private Rect mTask;
-    private Rect mTaskInsets;
-    private Rect mThumbnail;
-
-    private float mTaskScale;
-    private Rect mScaledTask;
-    private Rect mTargetTask;
-    private Rect mSrcWindow;
-
-    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets) {
-        mWindow = window;
-        mInsets = insets;
-        mTask = task;
-        mTaskInsets = taskInsets;
-        mInsetWindow = new Rect(window);
-        Utilities.insetRect(mInsetWindow, insets);
-
-        mThumbnail = new Rect(task);
-        Utilities.insetRect(mThumbnail, taskInsets);
-        mTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
-        mScaledTask = new Rect(task);
-        Utilities.scaleRectAboutCenter(mScaledTask, mTaskScale);
-        Rect finalScaledTaskInsets = new Rect(taskInsets);
-        Utilities.scaleRect(finalScaledTaskInsets, mTaskScale);
-        mTargetTask = new Rect(mInsetWindow);
-        mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top,
-                window.left + insets.left - finalScaledTaskInsets.left);
-
-        float initialWinScale = 1f / mTaskScale;
-        Rect scaledWindow = new Rect(mInsetWindow);
-        Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale);
-        Rect scaledInsets = new Rect(insets);
-        Utilities.scaleRect(scaledInsets, initialWinScale);
-        mSrcWindow = new Rect(scaledWindow);
-        mSrcWindow.offsetTo(mThumbnail.left - scaledInsets.left,
-                mThumbnail.top - scaledInsets.top);
-    }
-
-    public TaskWindowBounds interpolate(float t) {
-        mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t,
-                1, (float) mInsetWindow.width() / mThumbnail.width());
-        mTmpTaskWindowBounds.taskX = Utilities.mapRange(t,
-                0, mTargetTask.left - mScaledTask.left);
-        mTmpTaskWindowBounds.taskY = Utilities.mapRange(t,
-                0, mTargetTask.top - mScaledTask.top);
-
-        mTmpTaskWindowBounds.winScale = mTmpTaskWindowBounds.taskScale / mTaskScale;
-        mTmpTaskWindowBounds.winX = Utilities.mapRange(t,
-                mSrcWindow.left, 0);
-        mTmpTaskWindowBounds.winY = Utilities.mapRange(t,
-                mSrcWindow.top, 0);
-
-        mTmpInsets.set(mInsets);
-        Utilities.scaleRect(mTmpInsets, (1f - t));
-        mTmpTaskWindowBounds.winCrop.set(mWindow);
-        Utilities.insetRect(mTmpTaskWindowBounds.winCrop, mTmpInsets);
-
-        return mTmpTaskWindowBounds;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 28229f6..eea3971 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -15,28 +15,91 @@
  */
 package com.android.quickstep;
 
-import com.android.systemui.shared.system.BackgroundExecutor;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.UiThreadHelper;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
 
 /**
  * Wrapper around RecentsAnimationController to help with some synchronization
  */
 public class RecentsAnimationWrapper {
 
-    public RecentsAnimationControllerCompat controller;
-    public RemoteAnimationTargetCompat[] targets;
+    // A list of callbacks to run when we receive the recents animation target. There are different
+    // than the state callbacks as these run on the current worker thread.
+    private final ArrayList<Runnable> mCallbacks = new ArrayList<>();
 
-    private boolean mInputConsumerEnabled;
+    public RemoteAnimationTargetSet targetSet;
+
+    private RecentsAnimationControllerCompat mController;
+    private boolean mInputConsumerEnabled = false;
+    private boolean mBehindSystemBars = true;
+    private boolean mSplitScreenMinimized = false;
+
+    private final ExecutorService mExecutorService =
+            new LooperExecutor(UiThreadHelper.getBackgroundLooper());
+
+    private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
+    private InputConsumerController mInputConsumer =
+            InputConsumerController.getRecentsAnimationInputConsumer();
+    private final Supplier<TouchConsumer> mTouchProxySupplier;
+
+    private boolean mInputConsumerUnregistered;
+    private boolean mTouchProxyEnabled;
+
+    private TouchConsumer mTouchConsumer;
+    private boolean mTouchInProgress;
+    private boolean mInputConsumerUnregisterPending;
+
+    private boolean mFinishPending;
+
+    public RecentsAnimationWrapper(Supplier<TouchConsumer> touchProxySupplier) {
+        // Register the input consumer on the UI thread, to ensure that it runs after any pending
+        // unregister calls
+        mTouchProxySupplier = touchProxySupplier;
+        mMainThreadExecutor.execute(mInputConsumer::registerInputConsumer);
+    }
 
     public synchronized void setController(
-            RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
-        this.controller = controller;
-        this.targets = targets;
+            RecentsAnimationControllerCompat controller, RemoteAnimationTargetSet targetSet) {
+        TraceHelper.partitionSection("RecentsController", "Set controller " + controller);
+        this.mController = controller;
+        this.targetSet = targetSet;
 
+        if (controller == null) {
+            return;
+        }
         if (mInputConsumerEnabled) {
             enableInputConsumer();
         }
+
+        if (!mCallbacks.isEmpty()) {
+            for (Runnable action : new ArrayList<>(mCallbacks)) {
+                action.run();
+            }
+            mCallbacks.clear();
+        }
+    }
+
+    public synchronized void runOnInit(Runnable action) {
+        if (targetSet == null) {
+            mCallbacks.add(action);
+        } else {
+            action.run();
+        }
     }
 
     /**
@@ -44,29 +107,147 @@
      *                         on the background thread.
      */
     public void finish(boolean toHome, Runnable onFinishComplete) {
-        BackgroundExecutor.get().submit(() -> {
-            synchronized (this) {
-                if (controller != null) {
-                    controller.setInputConsumerEnabled(false);
-                    controller.finish(toHome);
-                    if (onFinishComplete != null) {
-                        onFinishComplete.run();
-                    }
+        if (!toHome) {
+            mExecutorService.submit(() -> finishBg(false, onFinishComplete));
+        }
+
+        mMainThreadExecutor.execute(() -> {
+            if (mTouchInProgress) {
+                mFinishPending = true;
+                // Execute the callback
+                if (onFinishComplete != null) {
+                    onFinishComplete.run();
                 }
+            } else {
+                mExecutorService.submit(() -> finishBg(true, onFinishComplete));
             }
         });
     }
 
+    protected void finishBg(boolean toHome, Runnable onFinishComplete) {
+        RecentsAnimationControllerCompat controller = mController;
+        mController = null;
+        TraceHelper.endSection("RecentsController", "Finish " + controller + ", toHome=" + toHome);
+        if (controller != null) {
+            controller.setInputConsumerEnabled(false);
+            controller.finish(toHome);
+
+            if (onFinishComplete != null) {
+                onFinishComplete.run();
+            }
+        }
+    }
+
     public void enableInputConsumer() {
         mInputConsumerEnabled = true;
         if (mInputConsumerEnabled) {
-            BackgroundExecutor.get().submit(() -> {
-                synchronized (this) {
-                    if (controller != null) {
-                        controller.setInputConsumerEnabled(true);
-                    }
+            mExecutorService.submit(() -> {
+                RecentsAnimationControllerCompat controller = mController;
+                TraceHelper.partitionSection("RecentsController",
+                        "Enabling consumer on " + controller);
+                if (controller != null) {
+                    controller.setInputConsumerEnabled(true);
                 }
             });
         }
     }
+
+    public void unregisterInputConsumer() {
+        mMainThreadExecutor.execute(this::unregisterInputConsumerUi);
+    }
+
+    private void unregisterInputConsumerUi() {
+        if (mTouchProxyEnabled && mTouchInProgress) {
+            mInputConsumerUnregisterPending = true;
+        } else {
+            mInputConsumerUnregistered = true;
+            mInputConsumer.unregisterInputConsumer();
+        }
+    }
+
+    public void enableTouchProxy() {
+        mMainThreadExecutor.execute(this::enableTouchProxyUi);
+    }
+
+    private void enableTouchProxyUi() {
+        if (!mInputConsumerUnregistered) {
+            mTouchProxyEnabled = true;
+            mInputConsumer.setTouchListener(this::onInputConsumerTouch);
+        }
+    }
+
+    private boolean onInputConsumerTouch(MotionEvent ev) {
+        int action = ev.getAction();
+        if (action == ACTION_DOWN) {
+            mTouchInProgress = true;
+            mTouchConsumer = mTouchProxySupplier.get();
+        } else if (action == ACTION_CANCEL || action == ACTION_UP) {
+            // Finish any pending actions
+            mTouchInProgress = false;
+            if (mInputConsumerUnregisterPending) {
+                mInputConsumerUnregisterPending = false;
+                mInputConsumer.unregisterInputConsumer();
+            }
+            if (mFinishPending) {
+                mFinishPending = false;
+                mExecutorService.submit(() -> finishBg(true, null));
+            }
+        }
+        if (mTouchConsumer != null) {
+            mTouchConsumer.accept(ev);
+        }
+
+        return true;
+    }
+
+    public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
+        if (mBehindSystemBars == behindSystemBars) {
+            return;
+        }
+        mBehindSystemBars = behindSystemBars;
+        mExecutorService.submit(() -> {
+            RecentsAnimationControllerCompat controller = mController;
+            TraceHelper.partitionSection("RecentsController",
+                    "Setting behind system bars on " + controller);
+            if (controller != null) {
+                controller.setAnimationTargetsBehindSystemBars(behindSystemBars);
+            }
+        });
+    }
+
+    /**
+     * NOTE: As a workaround for conflicting animations (Launcher animating the task leash, and
+     * SystemUI resizing the docked stack, which resizes the task), we currently only set the
+     * minimized mode, and not the inverse.
+     * TODO: Synchronize the minimize animation with the launcher animation
+     */
+    public void setSplitScreenMinimizedForTransaction(boolean minimized) {
+        if (mSplitScreenMinimized || !minimized) {
+            return;
+        }
+        mSplitScreenMinimized = minimized;
+        mExecutorService.submit(() -> {
+            RecentsAnimationControllerCompat controller = mController;
+            TraceHelper.partitionSection("RecentsController",
+                    "Setting minimize dock on " + controller);
+            if (controller != null) {
+                controller.setSplitScreenMinimized(minimized);
+            }
+        });
+    }
+
+    public void hideCurrentInputMethod() {
+        mExecutorService.submit(() -> {
+            RecentsAnimationControllerCompat controller = mController;
+            TraceHelper.partitionSection("RecentsController",
+                    "Hiding currentinput method on " + controller);
+            if (controller != null) {
+                controller.hideCurrentInputMethod();
+            }
+        });
+    }
+
+    public RecentsAnimationControllerCompat getController() {
+        return mController;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index d10c5a6..0b97f01 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -15,23 +15,41 @@
  */
 package com.android.quickstep;
 
+import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+
 import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.support.annotation.WorkerThread;
+import android.util.Log;
+import android.util.LruCache;
+import android.util.SparseArray;
+import android.view.accessibility.AccessibilityManager;
 
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
+import com.android.launcher3.util.Preconditions;
 import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.model.IconLoader;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.PreloadOptions;
 import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.BackgroundExecutor;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
+import java.util.ArrayList;
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
 
@@ -40,7 +58,6 @@
  */
 @TargetApi(Build.VERSION_CODES.O)
 public class RecentsModel extends TaskStackChangeListener {
-
     // We do not need any synchronization for this variable as its only written on UI thread.
     private static RecentsModel INSTANCE;
 
@@ -60,6 +77,9 @@
         return INSTANCE;
     }
 
+    private final SparseArray<Bundle> mCachedAssistData = new SparseArray<>(1);
+    private final ArrayList<AssistDataListener> mAssistDataListeners = new ArrayList<>();
+
     private final Context mContext;
     private final RecentsTaskLoader mRecentsTaskLoader;
     private final MainThreadExecutor mMainThreadExecutor;
@@ -68,21 +88,37 @@
     private int mLastLoadPlanId;
     private int mTaskChangeId;
     private ISystemUiProxy mSystemUiProxy;
+    private boolean mClearAssistCacheOnStackChange = true;
+    private final boolean mIsLowRamDevice;
+    private boolean mPreloadTasksInBackground;
+    private final AccessibilityManager mAccessibilityManager;
 
     private RecentsModel(Context context) {
         mContext = context;
 
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        mIsLowRamDevice = activityManager.isLowRamDevice();
+        mMainThreadExecutor = new MainThreadExecutor();
+
         Resources res = context.getResources();
         mRecentsTaskLoader = new RecentsTaskLoader(mContext,
                 res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
-                res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0);
-        mRecentsTaskLoader.startLoader(mContext);
+                res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0) {
 
-        mMainThreadExecutor = new MainThreadExecutor();
+            @Override
+            protected IconLoader createNewIconLoader(Context context,
+                    TaskKeyLruCache<Drawable> iconCache,
+                    LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+                return new NormalizedIconLoader(context, iconCache, activityInfoCache);
+            }
+        };
+        mRecentsTaskLoader.startLoader(mContext);
         ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
 
         mTaskChangeId = 1;
         loadTasks(-1, null);
+        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
     }
 
     public RecentsTaskLoader getRecentsTaskLoader() {
@@ -112,7 +148,7 @@
             // Preload the plan
             RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(mContext);
             PreloadOptions opts = new PreloadOptions();
-            opts.loadTitles = false;
+            opts.loadTitles = mAccessibilityManager.isEnabled();
             loadPlan.preloadPlan(opts, mRecentsTaskLoader, taskId, UserHandle.myUserId());
             // Set the load plan on UI thread
             mMainThreadExecutor.execute(() -> {
@@ -127,9 +163,55 @@
         return requestId;
     }
 
+    public void setPreloadTasksInBackground(boolean preloadTasksInBackground) {
+        mPreloadTasksInBackground = preloadTasksInBackground && !mIsLowRamDevice;
+    }
+
+    @Override
+    public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+        mTaskChangeId++;
+    }
+
+    @Override
+    public void onActivityUnpinned() {
+        mTaskChangeId++;
+    }
+
     @Override
     public void onTaskStackChanged() {
         mTaskChangeId++;
+
+        Preconditions.assertUIThread();
+        if (mClearAssistCacheOnStackChange) {
+            mCachedAssistData.clear();
+        } else {
+            mClearAssistCacheOnStackChange = true;
+        }
+    }
+
+    @Override
+    public void onTaskStackChangedBackground() {
+        int userId = UserHandle.myUserId();
+        if (!mPreloadTasksInBackground || !checkCurrentOrManagedUserId(userId, mContext)) {
+            // TODO: Only register this for the current user
+            return;
+        }
+
+        // Preload a fixed number of task icons/thumbnails in the background
+        ActivityManager.RunningTaskInfo runningTaskInfo =
+                ActivityManagerWrapper.getInstance().getRunningTask();
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
+        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+        launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
+        launchOpts.numVisibleTasks = 2;
+        launchOpts.numVisibleTaskThumbnails = 2;
+        launchOpts.onlyLoadForCache = true;
+        launchOpts.onlyLoadPausedActivities = true;
+        launchOpts.loadThumbnails = true;
+        PreloadOptions preloadOpts = new PreloadOptions();
+        preloadOpts.loadTitles = mAccessibilityManager.isEnabled();
+        plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId);
+        mRecentsTaskLoader.loadTasks(plan, launchOpts);
     }
 
     public boolean isLoadPlanValid(int resultId) {
@@ -147,4 +229,69 @@
     public ISystemUiProxy getSystemUiProxy() {
         return mSystemUiProxy;
     }
+
+    public void onStart() {
+        mRecentsTaskLoader.startLoader(mContext);
+    }
+
+    public void onTrimMemory(int level) {
+        if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
+            // We already stop the loader in UI_HIDDEN, so stop the high res loader as well
+            mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false);
+        }
+        mRecentsTaskLoader.onTrimMemory(level);
+    }
+
+    public void onOverviewShown(boolean fromHome, String tag) {
+        if (mSystemUiProxy == null) {
+            return;
+        }
+        try {
+            mSystemUiProxy.onOverviewShown(fromHome);
+        } catch (RemoteException e) {
+            Log.w(tag,
+                    "Failed to notify SysUI of overview shown from " + (fromHome ? "home" : "app")
+                            + ": ", e);
+        }
+    }
+
+    public void resetAssistCache() {
+        mCachedAssistData.clear();
+    }
+
+    @WorkerThread
+    public void preloadAssistData(int taskId, Bundle data) {
+        mMainThreadExecutor.execute(() -> {
+            mCachedAssistData.put(taskId, data);
+            // We expect a stack change callback after the assist data is set. So ignore the
+            // very next stack change callback.
+            mClearAssistCacheOnStackChange = false;
+
+            int count = mAssistDataListeners.size();
+            for (int i = 0; i < count; i++) {
+                mAssistDataListeners.get(i).onAssistDataReceived(taskId);
+            }
+        });
+    }
+
+    public Bundle getAssistData(int taskId) {
+        Preconditions.assertUIThread();
+        return mCachedAssistData.get(taskId);
+    }
+
+    public void addAssistDataListener(AssistDataListener listener) {
+        mAssistDataListeners.add(listener);
+    }
+
+    public void removeAssistDataListener(AssistDataListener listener) {
+        mAssistDataListeners.remove(listener);
+    }
+
+    /**
+     * Callback for receiving assist data
+     */
+    public interface AssistDataListener {
+
+        void onAssistDataReceived(int taskId);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
deleted file mode 100644
index a9d5e63..0000000
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import android.animation.LayoutTransition;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.Shader.TileMode;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.PagedView;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.OverviewState;
-import com.android.launcher3.uioverrides.RecentsViewStateController;
-import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.shared.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-import java.util.ArrayList;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.quickstep.TaskView.CURVE_FACTOR;
-import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
-
-/**
- * A list of recent tasks.
- */
-public class RecentsView extends PagedView implements Insettable {
-
-    private static final Rect sTempStableInsets = new Rect();
-
-    public static final int SCROLL_TYPE_NONE = 0;
-    public static final int SCROLL_TYPE_TASK = 1;
-    public static final int SCROLL_TYPE_WORKSPACE = 2;
-
-    private final Launcher mLauncher;
-    private QuickScrubController mQuickScrubController;
-    private final ScrollState mScrollState = new ScrollState();
-    private boolean mOverviewStateEnabled;
-    private boolean mTaskStackListenerRegistered;
-    private LayoutTransition mLayoutTransition;
-    private Runnable mNextPageSwitchRunnable;
-
-    /**
-     * TODO: Call reloadIdNeeded in onTaskStackChanged.
-     */
-    private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-        @Override
-        public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
-            for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
-                final TaskView taskView = (TaskView) getChildAt(i);
-                if (taskView.getTask().key.id == taskId) {
-                    taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
-                    return;
-                }
-            }
-        }
-    };
-
-    private RecentsViewStateController mStateController;
-    private int mFirstTaskIndex;
-
-    private final RecentsModel mModel;
-    private int mLoadPlanId = -1;
-
-    // Only valid until the launcher state changes to NORMAL
-    private int mRunningTaskId = -1;
-
-    private Bitmap mScrim;
-    private Paint mFadePaint;
-    private Shader mFadeShader;
-    private Matrix mFadeMatrix;
-    private boolean mScrimOnLeft;
-
-    public RecentsView(Context context) {
-        this(context, null);
-    }
-
-    public RecentsView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
-        enableFreeScroll(true);
-        setupLayoutTransition();
-        setClipToOutline(true);
-
-        mLauncher = Launcher.getLauncher(context);
-        mQuickScrubController = new QuickScrubController(this);
-        mModel = RecentsModel.getInstance(context);
-
-        mScrollState.isRtl = mIsRtl;
-    }
-
-    public void updateThumbnail(int taskId, ThumbnailData thumbnailData) {
-        for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
-            final TaskView taskView = (TaskView) getChildAt(i);
-            if (taskView.getTask().key.id == taskId) {
-                taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
-                taskView.setAlpha(1);
-                return;
-            }
-        }
-    }
-
-    private void setupLayoutTransition() {
-        // We want to show layout transitions when pages are deleted, to close the gap.
-        mLayoutTransition = new LayoutTransition();
-        mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);
-        mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
-
-        mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);
-        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
-        setLayoutTransition(mLayoutTransition);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mFirstTaskIndex = getPageCount();
-    }
-
-    @Override
-    protected void onWindowVisibilityChanged(int visibility) {
-        super.onWindowVisibilityChanged(visibility);
-        updateTaskStackListenerState();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        updateTaskStackListenerState();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        updateTaskStackListenerState();
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        DeviceProfile dp = Launcher.getLauncher(getContext()).getDeviceProfile();
-        Rect padding = getPadding(dp, getContext());
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-        lp.bottomMargin = padding.bottom;
-        setLayoutParams(lp);
-
-        setPadding(padding.left, padding.top, padding.right, 0);
-
-        if (dp.isVerticalBarLayout()) {
-            boolean wasScrimOnLeft = mScrimOnLeft;
-            mScrimOnLeft = dp.isSeascape();
-
-            if (mScrim == null || wasScrimOnLeft != mScrimOnLeft) {
-                Drawable scrim = getContext().getDrawable(mScrimOnLeft
-                        ? R.drawable.recents_horizontal_scrim_left
-                        : R.drawable.recents_horizontal_scrim_right);
-                if (scrim instanceof BitmapDrawable) {
-                    mScrim = ((BitmapDrawable) scrim).getBitmap();
-                    mFadePaint = new Paint();
-                    mFadePaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
-                    mFadeShader = new BitmapShader(mScrim, TileMode.CLAMP, TileMode.REPEAT);
-                    mFadeMatrix = new Matrix();
-                } else {
-                    mScrim = null;
-                }
-            }
-        } else {
-            mScrim = null;
-            mFadePaint = null;
-            mFadeShader = null;
-            mFadeMatrix = null;
-        }
-    }
-
-    public int getFirstTaskIndex() {
-        return mFirstTaskIndex;
-    }
-
-    public boolean isTaskViewVisible(TaskView tv) {
-        // For now, just check if it's the active task
-        return indexOfChild(tv) == getNextPage();
-    }
-
-    public TaskView getTaskView(int taskId) {
-        for (int i = getFirstTaskIndex(); i < getChildCount(); i++) {
-            TaskView tv = (TaskView) getChildAt(i);
-            if (tv.getTask().key.id == taskId) {
-                return tv;
-            }
-        }
-        return null;
-    }
-
-    public void setStateController(RecentsViewStateController stateController) {
-        mStateController = stateController;
-    }
-
-    public RecentsViewStateController getStateController() {
-        return mStateController;
-    }
-
-    public void setOverviewStateEnabled(boolean enabled) {
-        mOverviewStateEnabled = enabled;
-        updateTaskStackListenerState();
-    }
-
-    public void setNextPageSwitchRunnable(Runnable r) {
-        mNextPageSwitchRunnable = r;
-    }
-
-    @Override
-    protected void onPageEndTransition() {
-        super.onPageEndTransition();
-        if (mNextPageSwitchRunnable != null) {
-            mNextPageSwitchRunnable.run();
-            mNextPageSwitchRunnable = null;
-        }
-    }
-
-    private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
-        final RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
-        TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
-        if (stack == null) {
-            removeAllViews();
-            return;
-        }
-
-        int oldChildCount = getChildCount();
-
-        // Ensure there are as many views as there are tasks in the stack (adding and trimming as
-        // necessary)
-        final LayoutInflater inflater = LayoutInflater.from(getContext());
-        final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
-        setLayoutTransition(null);
-
-        final int requiredChildCount = tasks.size() + mFirstTaskIndex;
-        for (int i = getChildCount(); i < requiredChildCount; i++) {
-            final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
-            addView(taskView);
-        }
-        while (getChildCount() > requiredChildCount) {
-            final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1);
-            removeView(taskView);
-            loader.unloadTaskData(taskView.getTask());
-        }
-        setLayoutTransition(mLayoutTransition);
-
-        // Rebind and reset all task views
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            final Task task = tasks.get(i);
-            final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex);
-            taskView.bind(task);
-            taskView.setScaleX(1f);
-            taskView.setScaleY(1f);
-            taskView.setTranslationX(0f);
-            taskView.setTranslationY(0f);
-            taskView.setAlpha(1f);
-            loader.loadTaskData(task);
-        }
-
-        if (oldChildCount != getChildCount()) {
-            mQuickScrubController.snapToPageForCurrentQuickScrubSection();
-        }
-    }
-
-    private void updateTaskStackListenerState() {
-        boolean registerStackListener = mOverviewStateEnabled && isAttachedToWindow()
-                && getWindowVisibility() == VISIBLE;
-        if (registerStackListener != mTaskStackListenerRegistered) {
-            if (registerStackListener) {
-                ActivityManagerWrapper.getInstance()
-                        .registerTaskStackListener(mTaskStackListener);
-                reloadIfNeeded();
-            } else {
-                ActivityManagerWrapper.getInstance()
-                        .unregisterTaskStackListener(mTaskStackListener);
-            }
-            mTaskStackListenerRegistered = registerStackListener;
-        }
-    }
-
-    private static Rect getPadding(DeviceProfile profile, Context context) {
-        WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets);
-        Rect padding = new Rect(profile.workspacePadding);
-
-        float taskWidth = profile.widthPx - sTempStableInsets.left - sTempStableInsets.right;
-        float taskHeight = profile.heightPx - sTempStableInsets.top - sTempStableInsets.bottom;
-
-        float overviewHeight, overviewWidth;
-        if (profile.isVerticalBarLayout()) {
-            // Use the same padding on both sides for symmetry.
-            float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right);
-            float availableHeight = profile.availableHeightPx - padding.top
-                    - sTempStableInsets.top - Math.max(padding.bottom,
-                    profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context)));
-            float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
-            overviewHeight = taskHeight * scaledRatio;
-            overviewWidth = taskWidth * scaledRatio;
-
-        } else {
-            overviewHeight = profile.availableHeightPx - padding.top - padding.bottom
-                    - sTempStableInsets.top;
-            overviewWidth = taskWidth * overviewHeight / taskHeight;
-        }
-
-        padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top
-                - Math.round(overviewHeight);
-        padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
-        return padding;
-    }
-
-    /**
-     * Sets the {@param outRect} to match the position of the first tile such that it is scaled
-     * down to match the 2nd taskView.
-     * @return returns the factor which determines the scaling factor for the second task.
-     */
-    public static float getScaledDownPageRect(DeviceProfile dp, Context context, Rect outRect) {
-        getPageRect(dp, context, outRect);
-
-        int pageSpacing = context.getResources()
-                .getDimensionPixelSize(R.dimen.recents_page_spacing);
-        float halfScreenWidth = dp.widthPx * 0.5f;
-        float halfPageWidth = outRect.width() * 0.5f;
-        float pageCenter = outRect.right + pageSpacing + halfPageWidth;
-        float distanceFromCenter = Math.abs(halfScreenWidth - pageCenter);
-        float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
-        float linearInterpolation = Math.min(1, distanceFromCenter / distanceToReachEdge);
-
-        float scale = 1 - CURVE_INTERPOLATOR.getInterpolation(linearInterpolation) * CURVE_FACTOR;
-
-        int topMargin = context.getResources()
-                .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-        outRect.top -= topMargin;
-        Utilities.scaleRectAboutCenter(outRect, scale);
-        outRect.top += (int) (scale * topMargin);
-        return linearInterpolation;
-    }
-
-    public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
-        Rect targetPadding = getPadding(grid, context);
-        Rect insets = grid.getInsets();
-        outRect.set(
-                targetPadding.left + insets.left,
-                targetPadding.top + insets.top,
-                grid.widthPx - targetPadding.right - insets.right,
-                grid.heightPx - targetPadding.bottom - insets.bottom);
-        outRect.top += context.getResources()
-                .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-    }
-
-    @Override
-    public void computeScroll() {
-        super.computeScroll();
-        updateCurveProperties();
-    }
-
-    /**
-     * Scales and adjusts translation of adjacent pages as if on a curved carousel.
-     */
-    private void updateCurveProperties() {
-        if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
-            return;
-        }
-        final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
-        mScrollState.lastScrollType = SCROLL_TYPE_NONE;
-        final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
-        final int halfScreenWidth = getMeasuredWidth() / 2;
-        final int pageSpacing = mPageSpacing;
-
-        final int pageCount = getPageCount();
-        for (int i = 0; i < pageCount; i++) {
-            View page = getPageAt(i);
-            int pageCenter = page.getLeft() + halfPageWidth;
-            mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
-            float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
-            mScrollState.linearInterpolation = Math.min(1,
-                    Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
-            mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
-        }
-    }
-
-    public void onTaskDismissed(TaskView taskView) {
-        ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
-        removeView(taskView);
-        if (getTaskCount() == 0) {
-            mLauncher.getStateManager().goToState(NORMAL);
-        }
-    }
-
-    public void reset() {
-        mRunningTaskId = -1;
-        setCurrentPage(0);
-    }
-
-    public int getTaskCount() {
-        return getChildCount() - mFirstTaskIndex;
-    }
-
-    public int getRunningTaskId() {
-        return mRunningTaskId;
-    }
-
-    /**
-     * Reloads the view if anything in recents changed.
-     */
-    public void reloadIfNeeded() {
-        if (!mModel.isLoadPlanValid(mLoadPlanId)) {
-            mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
-        }
-    }
-
-    /**
-     * Ensures that the first task in the view represents {@param task} and reloads the view
-     * if needed. This allows the swipe-up gesture to assume that the first tile always
-     * corresponds to the correct task.
-     * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
-     * is called.
-     * Also scrolls the view to this task
-     */
-    public void showTask(int runningTaskId) {
-        boolean needsReload = false;
-        if (getTaskCount() == 0) {
-            needsReload = true;
-            // Add an empty view for now
-            setLayoutTransition(null);
-            final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
-                    .inflate(R.layout.task, this, false);
-            addView(taskView, mFirstTaskIndex);
-            setLayoutTransition(mLayoutTransition);
-        }
-        if (!needsReload) {
-            needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
-        }
-        if (needsReload) {
-            mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
-        }
-        mRunningTaskId = runningTaskId;
-        setCurrentPage(mFirstTaskIndex);
-        if (mCurrentPage >= mFirstTaskIndex) {
-            TaskView currentTask = (TaskView) getPageAt(mCurrentPage);
-            currentTask.setIconScale(0);
-            currentTask.setAlpha(0);
-        }
-    }
-
-    public QuickScrubController getQuickScrubController() {
-        return mQuickScrubController;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        if (mScrim == null) {
-            super.draw(canvas);
-            return;
-        }
-
-        final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-
-        int length = mScrim.getWidth();
-        int height = getHeight();
-        int saveCount = canvas.getSaveCount();
-
-        int scrimLeft;
-        if (mScrimOnLeft) {
-            scrimLeft = getScrollX();
-        } else {
-            scrimLeft = getScrollX() + getWidth() - length;
-        }
-        canvas.saveLayer(scrimLeft, 0, scrimLeft + length, height, null, flags);
-        super.draw(canvas);
-
-        mFadeMatrix.setTranslate(scrimLeft, 0);
-        mFadeShader.setLocalMatrix(mFadeMatrix);
-        mFadePaint.setShader(mFadeShader);
-        canvas.drawRect(scrimLeft, 0, scrimLeft + length, height, mFadePaint);
-        canvas.restoreToCount(saveCount);
-    }
-
-    public interface PageCallbacks {
-
-        /**
-         * Updates the page UI based on scroll params and returns the type of scroll
-         * effect performed.
-         *
-         * @see #SCROLL_TYPE_NONE
-         * @see #SCROLL_TYPE_TASK
-         * @see #SCROLL_TYPE_WORKSPACE
-         */
-        int onPageScroll(ScrollState scrollState);
-    }
-
-    public static class ScrollState {
-
-        public boolean isRtl;
-        public int lastScrollType;
-
-        public int halfPageWidth;
-        public float distanceFromScreenCenter;
-        public float linearInterpolation;
-
-        public float prevPageExtraWidth;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/SimpleTaskView.java b/quickstep/src/com/android/quickstep/SimpleTaskView.java
deleted file mode 100644
index 8425fa3..0000000
--- a/quickstep/src/com/android/quickstep/SimpleTaskView.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.WindowManager;
-
-/**
- * A simple view which keeps its size proportional to the display size
- */
-public class SimpleTaskView extends View {
-
-    private static final Point sTempPoint = new Point();
-
-    public SimpleTaskView(Context context) {
-        super(context);
-    }
-
-    public SimpleTaskView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public SimpleTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-        getContext().getSystemService(WindowManager.class)
-                .getDefaultDisplay().getRealSize(sTempPoint);
-
-        int width = (int) ((float) height * sTempPoint.x / sTempPoint.y);
-        setMeasuredDimension(width, height);
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/SnapshotDragView.java b/quickstep/src/com/android/quickstep/SnapshotDragView.java
deleted file mode 100644
index 2ef3942..0000000
--- a/quickstep/src/com/android/quickstep/SnapshotDragView.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.systemui.shared.recents.view.AnimateableViewBounds;
-
-/**
- * Floating view which shows the task snapshot allowing it to be dragged and placed.
- */
-public class SnapshotDragView extends AbstractFloatingView implements Insettable {
-
-    private final Launcher mLauncher;
-    private final Bitmap mSnapshot;
-    private final AnimateableViewBounds mViewBounds;
-
-    public SnapshotDragView(Launcher launcher, Bitmap snapshot) {
-        super(launcher, null);
-        mLauncher = launcher;
-        mSnapshot = snapshot;
-        mViewBounds = new AnimateableViewBounds(this, 0);
-        setWillNotDraw(false);
-        setClipToOutline(true);
-        setOutlineProvider(mViewBounds);
-    }
-
-    AnimateableViewBounds getViewBounds() {
-        return mViewBounds;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mSnapshot != null) {
-            setMeasuredDimension(mSnapshot.getWidth(), mSnapshot.getHeight());
-        } else {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mSnapshot != null) {
-            canvas.drawBitmap(mSnapshot, 0, 0, null);
-        }
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        return false;
-    }
-
-    @Override
-    protected void handleClose(boolean animate) {
-        // We dont suupport animate.
-        mLauncher.getDragLayer().removeView(this);
-    }
-
-    @Override
-    public void logActionCommand(int command) {
-        // We should probably log the weather
-    }
-
-    @Override
-    protected boolean isOfType(int type) {
-        return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/TaskMenuView.java
deleted file mode 100644
index 52b2400..0000000
--- a/quickstep/src/com/android/quickstep/TaskMenuView.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Outline;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.TextView;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.shortcuts.DeepShortcutView;
-
-/**
- * Contains options for a recent task when long-pressing its icon.
- */
-public class TaskMenuView extends AbstractFloatingView {
-
-    private static final Rect sTempRect = new Rect();
-
-    /** Note that these will be shown in order from top to bottom, if available for the task. */
-    private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
-            new TaskSystemShortcut.AppInfo(),
-            new TaskSystemShortcut.SplitScreen(),
-            new TaskSystemShortcut.Pin(),
-            new TaskSystemShortcut.Install(),
-    };
-
-    private static final long OPEN_CLOSE_DURATION = 220;
-
-    private Launcher mLauncher;
-    private TextView mTaskIconAndName;
-    private AnimatorSet mOpenCloseAnimator;
-    private TaskView mTaskView;
-
-    public TaskMenuView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mLauncher = Launcher.getLauncher(context);
-        setClipToOutline(true);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                float r = getResources().getDimensionPixelSize(R.dimen.task_menu_background_radius);
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), r);
-            }
-        });
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mTaskIconAndName = findViewById(R.id.task_icon_and_name);
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            DragLayer dl = mLauncher.getDragLayer();
-            if (!dl.isEventOverView(this, ev)) {
-                // TODO: log this once we have a new container type for it?
-                close(true);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected void handleClose(boolean animate) {
-        if (animate) {
-            animateClose();
-        } else {
-            closeComplete();
-        }
-    }
-
-    @Override
-    public void logActionCommand(int command) {
-        // TODO
-    }
-
-    @Override
-    protected boolean isOfType(int type) {
-        return (type & TYPE_TASK_MENU) != 0;
-    }
-
-    public static boolean showForTask(TaskView taskView) {
-        Launcher launcher = Launcher.getLauncher(taskView.getContext());
-        final TaskMenuView taskMenuView = (TaskMenuView) launcher.getLayoutInflater().inflate(
-                        R.layout.task_menu, launcher.getDragLayer(), false);
-        return taskMenuView.populateAndShowForTask(taskView);
-    }
-
-    private boolean populateAndShowForTask(TaskView taskView) {
-        if (isAttachedToWindow()) {
-            return false;
-        }
-        mLauncher.getDragLayer().addView(this);
-        mTaskView = taskView;
-        addMenuOptions(mTaskView);
-        orientAroundTaskView(mTaskView);
-        post(this::animateOpen);
-        return true;
-    }
-
-    private void addMenuOptions(TaskView taskView) {
-        Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
-        int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
-        icon.setBounds(0, 0, iconSize, iconSize);
-        mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
-        mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask()));
-
-        for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
-            OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView);
-            if (onClickListener != null) {
-                addMenuOption(menuOption, onClickListener);
-            }
-        }
-    }
-
-    private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
-        DeepShortcutView menuOptionView = (DeepShortcutView) mLauncher.getLayoutInflater().inflate(
-                R.layout.system_shortcut, this, false);
-        menuOptionView.getIconView().setBackgroundResource(menuOption.iconResId);
-        menuOptionView.getBubbleText().setText(menuOption.labelResId);
-        menuOptionView.setOnClickListener(onClickListener);
-        addView(menuOptionView);
-    }
-
-    private void orientAroundTaskView(TaskView taskView) {
-        measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-        mLauncher.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
-        Rect insets = mLauncher.getDragLayer().getInsets();
-        int x = sTempRect.left + (sTempRect.width() - getMeasuredWidth()) / 2 - insets.left;
-        setX(Utilities.isRtl(getResources()) ? -x : x);
-        setY(sTempRect.top - mTaskIconAndName.getPaddingTop() - insets.top);
-    }
-
-    private void animateOpen() {
-        animateOpenOrClosed(false);
-        mIsOpen = true;
-    }
-
-    private void animateClose() {
-        animateOpenOrClosed(true);
-    }
-
-    private void animateOpenOrClosed(boolean closing) {
-        if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
-            return;
-        }
-        mOpenCloseAnimator = LauncherAnimUtils.createAnimatorSet();
-        mOpenCloseAnimator.play(createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, closing));
-        mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                setVisibility(VISIBLE);
-            }
-
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                if (closing) {
-                    closeComplete();
-                }
-            }
-        });
-        mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
-        mOpenCloseAnimator.setDuration(OPEN_CLOSE_DURATION);
-        mOpenCloseAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
-        mOpenCloseAnimator.start();
-    }
-
-    private void closeComplete() {
-        mIsOpen = false;
-        mLauncher.getDragLayer().removeView(this);
-    }
-
-    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
-        int iconSize = getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_size);
-        float fromRadius = iconSize / 2;
-        float toRadius = getResources().getDimensionPixelSize(
-                R.dimen.task_menu_background_radius);
-        Point iconCenter = new Point(getWidth() / 2, mTaskIconAndName.getPaddingTop() + iconSize / 2);
-        Rect fromRect = new Rect(iconCenter.x, iconCenter.y, iconCenter.x, iconCenter.y);
-        Rect toRect = new Rect(0, 0, getWidth(), getHeight());
-        return new RoundedRectRevealOutlineProvider(fromRadius, toRadius, fromRect, toRect) {
-            @Override
-            public boolean shouldRemoveElevationDuringAnimation() {
-                return true;
-            }
-        };
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index c2fb7be..c272b1a 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -18,36 +18,43 @@
 
 import android.content.Context;
 import android.graphics.Matrix;
+import android.support.annotation.AnyThread;
 import android.view.View;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 /**
  * Factory class to create and add an overlays on the TaskView
  */
-public class TaskOverlayFactory {
+public class TaskOverlayFactory implements ResourceBasedOverride {
 
     private static TaskOverlayFactory sInstance;
 
     public static TaskOverlayFactory get(Context context) {
         Preconditions.assertUIThread();
         if (sInstance == null) {
-            sInstance = Utilities.getOverrideObject(TaskOverlayFactory.class,
+            sInstance = Overrides.getObject(TaskOverlayFactory.class,
                     context.getApplicationContext(), R.string.task_overlay_factory_class);
         }
         return sInstance;
     }
 
+    @AnyThread
+    public boolean needAssist() {
+        return false;
+    }
+
     public TaskOverlay createOverlay(View thumbnailView) {
         return new TaskOverlay();
     }
 
     public static class TaskOverlay {
 
-        public void setTaskInfo(ThumbnailData thumbnail, Matrix matrix) { }
+        public void setTaskInfo(Task task, ThumbnailData thumbnail, Matrix matrix) { }
 
         public void reset() { }
 
diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
index d8ba186..24e199b 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -16,28 +16,42 @@
 
 package com.android.quickstep;
 
-import android.app.ActivityOptions;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
+
 import android.content.ComponentName;
 import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.InstantAppResolver;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
+import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
@@ -59,11 +73,12 @@
     }
 
     @Override
-    public View.OnClickListener getOnClickListener(Launcher launcher, ItemInfo itemInfo) {
+    public View.OnClickListener getOnClickListener(
+            BaseDraggingActivity activity, ItemInfo itemInfo) {
         return null;
     }
 
-    public View.OnClickListener getOnClickListener(final Launcher launcher, final TaskView view) {
+    public View.OnClickListener getOnClickListener(BaseDraggingActivity activity, TaskView view) {
         Task task = view.getTask();
 
         ShortcutInfo dummyInfo = new ShortcutInfo();
@@ -71,14 +86,14 @@
         ComponentName component = task.getTopComponent();
         dummyInfo.intent.setComponent(component);
         dummyInfo.user = UserHandle.of(task.key.userId);
-        dummyInfo.title = TaskUtils.getTitle(launcher, task);
+        dummyInfo.title = TaskUtils.getTitle(activity, task);
 
-        return getOnClickListenerForTask(launcher, task, dummyInfo);
+        return getOnClickListenerForTask(activity, task, dummyInfo);
     }
 
-    protected View.OnClickListener getOnClickListenerForTask(final Launcher launcher,
-            final Task task, final ItemInfo dummyInfo) {
-        return mSystemShortcut.getOnClickListener(launcher, dummyInfo);
+    protected View.OnClickListener getOnClickListenerForTask(
+            BaseDraggingActivity activity, Task task, ItemInfo dummyInfo) {
+        return mSystemShortcut.getOnClickListener(activity, dummyInfo);
     }
 
     public static class AppInfo extends TaskSystemShortcut<SystemShortcut.AppInfo> {
@@ -97,31 +112,109 @@
         }
 
         @Override
-        public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
-            if (launcher.getDeviceProfile().inMultiWindowMode()) {
+        public View.OnClickListener getOnClickListener(
+                BaseDraggingActivity activity, TaskView taskView) {
+            if (activity.getDeviceProfile().isMultiWindowMode) {
                 return null;
             }
-            return (v -> {
-                Task task  = taskView.getTask();
-                final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true);
-                final Consumer<Boolean> resultCallback = success -> {
-                    if (success) {
-                        launcher.<RecentsView>getOverviewPanel().removeView(taskView);
-                    }
-                };
-                ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(
-                        task.key, options, resultCallback, mHandler);
+            final Task task  = taskView.getTask();
+            final int taskId = task.key.id;
+            if (!task.isDockable) {
+                return null;
+            }
+            final RecentsView recentsView = activity.getOverviewPanel();
 
-                // TODO improve transition; see:
-                // DockedFirstAnimationFrameEvent
-                // RecentsTransitionHelper#composeDockAnimationSpec
-                // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture
+            final TaskThumbnailView thumbnailView = taskView.getThumbnail();
+            return (v -> {
+                final View.OnLayoutChangeListener onLayoutChangeListener =
+                        new View.OnLayoutChangeListener() {
+                            @Override
+                            public void onLayoutChange(View v, int l, int t, int r, int b,
+                                    int oldL, int oldT, int oldR, int oldB) {
+                                taskView.getRootView().removeOnLayoutChangeListener(this);
+                                recentsView.clearIgnoreResetTask(taskId);
+
+                                // Start animating in the side pages once launcher has been resized
+                                recentsView.dismissTask(taskView, false, false);
+                            }
+                        };
+
+                final DeviceProfile.OnDeviceProfileChangeListener onDeviceProfileChangeListener =
+                        new DeviceProfile.OnDeviceProfileChangeListener() {
+                            @Override
+                            public void onDeviceProfileChanged(DeviceProfile dp) {
+                                activity.removeOnDeviceProfileChangeListener(this);
+                                if (dp.isMultiWindowMode) {
+                                    taskView.getRootView().addOnLayoutChangeListener(
+                                            onLayoutChangeListener);
+                                }
+                            }
+                        };
+
+                dismissTaskMenuView(activity);
+
+                final int navBarPosition = WindowManagerWrapper.getInstance().getNavBarPosition();
+                if (navBarPosition == WindowManagerWrapper.NAV_BAR_POS_INVALID) {
+                    return;
+                }
+                boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT;
+                if (ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId,
+                        ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft))) {
+                    ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+                    try {
+                        sysUiProxy.onSplitScreenInvoked();
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "Failed to notify SysUI of split screen: ", e);
+                        return;
+                    }
+                    activity.getUserEventDispatcher().logActionOnControl(TAP,
+                            LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET);
+                    // Add a device profile change listener to kick off animating the side tasks
+                    // once we enter multiwindow mode and relayout
+                    activity.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener);
+
+                    final Runnable animStartedListener = () -> {
+                        // Hide the task view and wait for the window to be resized
+                        // TODO: Consider animating in launcher and do an in-place start activity
+                        //       afterwards
+                        recentsView.setIgnoreResetTask(taskId);
+                        taskView.setAlpha(0f);
+                    };
+
+                    final int[] position = new int[2];
+                    thumbnailView.getLocationOnScreen(position);
+                    final int width = (int) (thumbnailView.getWidth() * taskView.getScaleX());
+                    final int height = (int) (thumbnailView.getHeight() * taskView.getScaleY());
+                    final Rect taskBounds = new Rect(position[0], position[1],
+                            position[0] + width, position[1] + height);
+
+                    // Take the thumbnail of the task without a scrim and apply it back after
+                    float alpha = thumbnailView.getDimAlpha();
+                    thumbnailView.setDimAlpha(0);
+                    Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap(
+                            taskBounds.width(), taskBounds.height(), thumbnailView, 1f,
+                            Color.BLACK);
+                    thumbnailView.setDimAlpha(alpha);
+
+                    AppTransitionAnimationSpecsFuture future =
+                            new AppTransitionAnimationSpecsFuture(mHandler) {
+                        @Override
+                        public List<AppTransitionAnimationSpecCompat> composeSpecs() {
+                            return Collections.singletonList(new AppTransitionAnimationSpecCompat(
+                                    taskId, thumbnail, taskBounds));
+                        }
+                    };
+                    WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture(
+                            future, animStartedListener, mHandler, true /* scaleUp */);
+                }
             });
         }
     }
 
     public static class Pin extends TaskSystemShortcut {
 
+        private static final String TAG = Pin.class.getSimpleName();
+
         private Handler mHandler;
 
         public Pin() {
@@ -130,12 +223,17 @@
         }
 
         @Override
-        public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
-            ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy();
+        public View.OnClickListener getOnClickListener(
+                BaseDraggingActivity activity, TaskView taskView) {
+            ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
             if (sysUiProxy == null) {
                 return null;
             }
-            if (!ActivityManagerWrapper.getInstance().isLockToAppEnabled()) {
+            if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) {
+                return null;
+            }
+            if (ActivityManagerWrapper.getInstance().isLockToAppActive()) {
+                // We shouldn't be able to pin while an app is locked.
                 return null;
             }
             return view -> {
@@ -146,9 +244,12 @@
                         } catch (RemoteException e) {
                             Log.w(TAG, "Failed to start screen pinning: ", e);
                         }
+                    } else {
+                        taskView.notifyTaskLaunchFailed(TAG);
                     }
                 };
                 taskView.launchTask(true, resultCallback, mHandler);
+                dismissTaskMenuView(activity);
             };
         }
     }
@@ -159,11 +260,11 @@
         }
 
         @Override
-        protected View.OnClickListener getOnClickListenerForTask(Launcher launcher, Task task,
-                ItemInfo itemInfo) {
-            if (InstantAppResolver.newInstance(launcher).isInstantApp(launcher,
+        protected View.OnClickListener getOnClickListenerForTask(
+                BaseDraggingActivity activity, Task task, ItemInfo itemInfo) {
+            if (InstantAppResolver.newInstance(activity).isInstantApp(activity,
                         task.getTopComponent().getPackageName())) {
-                return mSystemShortcut.createOnClickListener(launcher, itemInfo);
+                return mSystemShortcut.createOnClickListener(activity, itemInfo);
             }
             return null;
         }
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
deleted file mode 100644
index 4f93b1c..0000000
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ComposeShader;
-import android.graphics.LightingColorFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-
-/**
- * A task in the Recents view.
- */
-public class TaskThumbnailView extends View {
-
-    private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
-
-    private final float mCornerRadius;
-    private final float mFadeLength;
-
-    private final TaskOverlay mOverlay;
-    private final Paint mPaint = new Paint();
-
-    private final Matrix mMatrix = new Matrix();
-
-    private ThumbnailData mThumbnailData;
-    protected BitmapShader mBitmapShader;
-
-    private float mDimAlpha = 1f;
-
-    public TaskThumbnailView(Context context) {
-        this(context, null);
-    }
-
-    public TaskThumbnailView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
-        mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
-        mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
-    }
-
-    public void bind() {
-        mOverlay.reset();
-    }
-
-    /**
-     * Updates this thumbnail.
-     */
-    public void setThumbnail(Task task, ThumbnailData thumbnailData) {
-        mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000);
-
-        if (thumbnailData != null && thumbnailData.thumbnail != null) {
-            Bitmap bm = thumbnailData.thumbnail;
-            bm.prepareToDraw();
-            mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-            mPaint.setShader(mBitmapShader);
-            mThumbnailData = thumbnailData;
-            updateThumbnailMatrix();
-        } else {
-            mBitmapShader = null;
-            mThumbnailData = null;
-            mPaint.setShader(null);
-            mOverlay.reset();
-        }
-        updateThumbnailPaintFilter();
-    }
-
-    /**
-     * Sets the alpha of the dim layer on top of this view.
-     */
-    public void setDimAlpha(float dimAlpha) {
-        mDimAlpha = dimAlpha;
-        updateThumbnailPaintFilter();
-    }
-
-    public Rect getInsets() {
-        if (mThumbnailData != null) {
-            return mThumbnailData.insets;
-        }
-        return new Rect();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
-                mCornerRadius, mCornerRadius, mPaint);
-    }
-
-    private void updateThumbnailPaintFilter() {
-        int mul = (int) (mDimAlpha * 255);
-        if (mBitmapShader != null) {
-            mPaint.setColorFilter(getLightingColorFilter(mul));
-        } else {
-            mPaint.setColorFilter(null);
-            mPaint.setColor(Color.argb(255, mul, mul, mul));
-        }
-        invalidate();
-    }
-
-    private void updateThumbnailMatrix() {
-        if (mBitmapShader != null && mThumbnailData != null) {
-            float scale = mThumbnailData.scale;
-            float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
-                    (mThumbnailData.insets.left + mThumbnailData.insets.right) * scale;
-            float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
-                    (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale;
-            final float thumbnailScale;
-
-            if (getMeasuredWidth() == 0) {
-                // If we haven't measured , skip the thumbnail drawing and only draw the background
-                // color
-                thumbnailScale = 0f;
-            } else {
-                final Configuration configuration =
-                        getContext().getApplicationContext().getResources().getConfiguration();
-                final DeviceProfile profile = Launcher.getLauncher(getContext()).getDeviceProfile();
-                if (configuration.orientation == mThumbnailData.orientation) {
-                    // If we are in the same orientation as the screenshot, just scale it to the
-                    // width of the task view
-                    thumbnailScale = getMeasuredWidth() / thumbnailWidth;
-                } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
-                    // Scale the landscape thumbnail up to app size, then scale that to the task
-                    // view size to match other portrait screenshots
-                    thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx);
-                } else {
-                    // Otherwise, scale the screenshot to fit 1:1 in the current orientation
-                    thumbnailScale = 1;
-                }
-            }
-            mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
-                    -mThumbnailData.insets.top * scale);
-            mMatrix.postScale(thumbnailScale, thumbnailScale);
-            mBitmapShader.setLocalMatrix(mMatrix);
-
-            float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0);
-            Shader shader = mBitmapShader;
-            if (bitmapHeight < getMeasuredHeight()) {
-                int color = mPaint.getColor();
-                LinearGradient fade = new LinearGradient(
-                        0, bitmapHeight - mFadeLength, 0, bitmapHeight,
-                        color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
-                shader = new ComposeShader(fade, shader, Mode.DST_OVER);
-            }
-
-            float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0);
-            if (bitmapWidth < getMeasuredWidth()) {
-                int color = mPaint.getColor();
-                LinearGradient fade = new LinearGradient(
-                        bitmapWidth - mFadeLength, 0, bitmapWidth, 0,
-                        color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
-                shader = new ComposeShader(fade, shader, Mode.DST_OVER);
-            }
-            mPaint.setShader(shader);
-        }
-
-        mOverlay.setTaskInfo(mThumbnailData, mMatrix);
-        invalidate();
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        updateThumbnailMatrix();
-    }
-
-    private static LightingColorFilter getLightingColorFilter(int dimColor) {
-        if (dimColor < 0) {
-            dimColor = 0;
-        } else if (dimColor > 255) {
-            dimColor = 255;
-        }
-        if (sDimFilterCache[dimColor] == null) {
-            sDimFilterCache[dimColor] =
-                    new LightingColorFilter(Color.argb(255, dimColor, dimColor, dimColor), 0);
-        }
-        return sDimFilterCache[dimColor];
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index b31d42f..f9b5e30 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -16,28 +16,54 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber;
+import static com.android.systemui.shared.recents.utilities.Utilities.getSurface;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
+
+import android.animation.ValueAnimator;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.RectF;
 import android.os.UserHandle;
 import android.util.Log;
+import android.view.Surface;
+import android.view.View;
 
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+
+import java.util.List;
 
 /**
  * Contains helpful methods for retrieving data from {@link Task}s.
- * TODO: remove this once we switch to getting the icon and label from IconCache.
  */
 public class TaskUtils {
 
     private static final String TAG = "TaskUtils";
 
-    public static CharSequence getTitle(Launcher launcher, Task task) {
-        LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(launcher);
-        UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(launcher);
-        PackageManager packageManager = launcher.getPackageManager();
+    /**
+     * TODO: remove this once we switch to getting the icon and label from IconCache.
+     */
+    public static CharSequence getTitle(Context context, Task task) {
+        LauncherAppsCompat launcherAppsCompat = LauncherAppsCompat.getInstance(context);
+        UserManagerCompat userManagerCompat = UserManagerCompat.getInstance(context);
+        PackageManager packageManager = context.getPackageManager();
         UserHandle user = UserHandle.of(task.key.userId);
         ApplicationInfo applicationInfo = launcherAppsCompat.getApplicationInfo(
             task.getTopComponent().getPackageName(), 0, user);
@@ -48,4 +74,144 @@
         return userManagerCompat.getBadgedLabelForUser(
             applicationInfo.loadLabel(packageManager), user);
     }
+
+    public static ComponentKey getLaunchComponentKeyForTask(Task.TaskKey taskKey) {
+        final ComponentName cn = taskKey.sourceComponent != null
+                ? taskKey.sourceComponent
+                : taskKey.getComponent();
+        return new ComponentKey(cn, UserHandle.of(taskKey.userId));
+    }
+
+
+    /**
+     * Try to find a TaskView that corresponds with the component of the launched view.
+     *
+     * If this method returns a non-null TaskView, it will be used in composeRecentsLaunchAnimation.
+     * Otherwise, we will assume we are using a normal app transition, but it's possible that the
+     * opening remote target (which we don't get until onAnimationStart) will resolve to a TaskView.
+     */
+    public static TaskView findTaskViewToLaunch(
+            BaseDraggingActivity activity, View v, RemoteAnimationTargetCompat[] targets) {
+        if (v instanceof TaskView) {
+            return (TaskView) v;
+        }
+        RecentsView recentsView = activity.getOverviewPanel();
+
+        // It's possible that the launched view can still be resolved to a visible task view, check
+        // the task id of the opening task and see if we can find a match.
+        if (v.getTag() instanceof ItemInfo) {
+            ItemInfo itemInfo = (ItemInfo) v.getTag();
+            ComponentName componentName = itemInfo.getTargetComponent();
+            int userId = itemInfo.user.getIdentifier();
+            if (componentName != null) {
+                for (int i = 0; i < recentsView.getTaskViewCount(); i++) {
+                    TaskView taskView = recentsView.getTaskViewAt(i);
+                    if (recentsView.isTaskViewVisible(taskView)) {
+                        Task.TaskKey key = taskView.getTask().key;
+                        if (componentName.equals(key.getComponent()) && userId == key.userId) {
+                            return taskView;
+                        }
+                    }
+                }
+            }
+        }
+
+        if (targets == null) {
+            return null;
+        }
+        // Resolve the opening task id
+        int openingTaskId = -1;
+        for (RemoteAnimationTargetCompat target : targets) {
+            if (target.mode == MODE_OPENING) {
+                openingTaskId = target.taskId;
+                break;
+            }
+        }
+
+        // If there is no opening task id, fall back to the normal app icon launch animation
+        if (openingTaskId == -1) {
+            return null;
+        }
+
+        // If the opening task id is not currently visible in overview, then fall back to normal app
+        // icon launch animation
+        TaskView taskView = recentsView.getTaskView(openingTaskId);
+        if (taskView == null || !recentsView.isTaskViewVisible(taskView)) {
+            return null;
+        }
+        return taskView;
+    }
+
+    /**
+     * @return Animator that controls the window of the opening targets for the recents launch
+     * animation.
+     */
+    public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
+            RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
+        SyncRtSurfaceTransactionApplier syncTransactionApplier =
+                new SyncRtSurfaceTransactionApplier(v);
+        final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
+        appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
+        appAnimator.addUpdateListener(new MultiValueUpdateListener() {
+
+            // Defer fading out the view until after the app window gets faded in
+            final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
+            final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);
+
+            final RemoteAnimationTargetSet mTargetSet;
+
+            final RectF mThumbnailRect;
+
+            {
+                mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING);
+                inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
+
+                inOutHelper.prepareAnimation(true /* isOpening */);
+                inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
+                        mTargetSet.apps.length == 0 ? null : mTargetSet.apps[0]);
+
+                mThumbnailRect = new RectF(inOutHelper.getTargetRect());
+                mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY());
+                Utilities.scaleRectFAboutCenter(mThumbnailRect, 1 / v.getScaleX());
+            }
+
+            @Override
+            public void onUpdate(float percent) {
+                RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent,
+                        syncTransactionApplier);
+                if (!skipViewChanges) {
+                    float scale = taskBounds.width() / mThumbnailRect.width();
+                    v.setScaleX(scale);
+                    v.setScaleY(scale);
+                    v.setTranslationX(taskBounds.centerX() - mThumbnailRect.centerX());
+                    v.setTranslationY(taskBounds.centerY() - mThumbnailRect.centerY());
+                    v.setAlpha(mViewAlpha.value);
+                }
+            }
+        });
+        return appAnimator;
+    }
+
+    public static boolean taskIsATargetWithMode(RemoteAnimationTargetCompat[] targets,
+            int taskId, int mode) {
+        for (RemoteAnimationTargetCompat target : targets) {
+            if (target.mode == mode && target.taskId == taskId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean checkCurrentOrManagedUserId(int currentUserId, Context context) {
+        if (currentUserId == UserHandle.myUserId()) {
+            return true;
+        }
+        List<UserHandle> allUsers = UserManagerCompat.getInstance(context).getUserProfiles();
+        for (int i = allUsers.size() - 1; i >= 0; i--) {
+            if (currentUserId == allUsers.get(i).getIdentifier()) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
deleted file mode 100644
index 8865a42..0000000
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.launcher3.R;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
-import com.android.systemui.shared.recents.view.RecentsTransition;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * A task in the Recents view.
- */
-public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
-
-    /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
-    public static final float CURVE_FACTOR = 0.25f;
-    /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
-    public static final TimeInterpolator CURVE_INTERPOLATOR
-            = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
-
-    /**
-     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
-     * In the resting position of the carousel, the adjacent pages have about half this scrim.
-     */
-    private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
-
-    private static final long SCALE_ICON_DURATION = 120;
-
-    private static final Property<TaskView, Float> SCALE_ICON_PROPERTY =
-            new Property<TaskView, Float>(Float.TYPE, "scale_icon") {
-                @Override
-                public Float get(TaskView taskView) {
-                    return taskView.mIconScale;
-                }
-
-                @Override
-                public void set(TaskView taskView, Float iconScale) {
-                    taskView.setIconScale(iconScale);
-                }
-            };
-
-    private Task mTask;
-    private TaskThumbnailView mSnapshotView;
-    private ImageView mIconView;
-    private float mIconScale = 1f;
-
-    public TaskView(Context context) {
-        this(context, null);
-    }
-
-    public TaskView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setOnClickListener((view) -> launchTask(true /* animate */));
-        setOutlineProvider(new TaskOutlineProvider(getResources()));
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mSnapshotView = findViewById(R.id.snapshot);
-        mIconView = findViewById(R.id.icon);
-    }
-
-    /**
-     * Updates this task view to the given {@param task}.
-     */
-    public void bind(Task task) {
-        if (mTask != null) {
-            mTask.removeCallback(this);
-        }
-        mTask = task;
-        mSnapshotView.bind();
-        task.addCallback(this);
-    }
-
-    public Task getTask() {
-        return mTask;
-    }
-
-    public TaskThumbnailView getThumbnail() {
-        return mSnapshotView;
-    }
-
-    public void launchTask(boolean animate) {
-        launchTask(animate, null, null);
-    }
-
-    public void launchTask(boolean animate, Consumer<Boolean> resultCallback,
-            Handler resultCallbackHandler) {
-        if (mTask != null) {
-            final ActivityOptions opts;
-            if (animate) {
-                // Calculate the bounds of the thumbnail to animate from
-                final Rect bounds = new Rect();
-                final int[] pos = new int[2];
-                mSnapshotView.getLocationInWindow(pos);
-                bounds.set(pos[0], pos[1],
-                        pos[0] + mSnapshotView.getWidth(),
-                        pos[1] + mSnapshotView.getHeight());
-                AppTransitionAnimationSpecsFuture animFuture =
-                        new AppTransitionAnimationSpecsFuture(getHandler()) {
-                            @Override
-                            public List<AppTransitionAnimationSpecCompat> composeSpecs() {
-                                ArrayList<AppTransitionAnimationSpecCompat> specs =
-                                        new ArrayList<>();
-                                specs.add(new AppTransitionAnimationSpecCompat(mTask.key.id, null,
-                                        bounds));
-                                return specs;
-                            }
-                        };
-                opts = RecentsTransition.createAspectScaleAnimation(
-                        getContext(), getHandler(), true /* scaleUp */, animFuture, null);
-            } else {
-                opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
-            }
-            ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
-                    opts, resultCallback, resultCallbackHandler);
-        }
-    }
-
-    @Override
-    public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
-        mSnapshotView.setThumbnail(task, thumbnailData);
-        mIconView.setImageDrawable(task.icon);
-        mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
-        mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this));
-    }
-
-    @Override
-    public void onTaskDataUnloaded() {
-        mSnapshotView.setThumbnail(null, null);
-        mIconView.setImageDrawable(null);
-        mIconView.setOnLongClickListener(null);
-    }
-
-    @Override
-    public void onTaskWindowingModeChanged() {
-        // Do nothing
-    }
-
-    public void animateIconToScale(float scale) {
-        ObjectAnimator.ofFloat(this, SCALE_ICON_PROPERTY, scale)
-                .setDuration(SCALE_ICON_DURATION).start();
-    }
-
-    protected void setIconScale(float iconScale) {
-        mIconScale = iconScale;
-        if (mIconView != null) {
-            mIconView.setScaleX(mIconScale);
-            mIconView.setScaleY(mIconScale);
-        }
-    }
-
-    @Override
-    public int onPageScroll(ScrollState scrollState) {
-        float curveInterpolation =
-                CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
-        float scale = 1 - curveInterpolation * CURVE_FACTOR;
-        setScaleX(scale);
-        setScaleY(scale);
-
-        // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
-        setTranslationZ(scale);
-
-        mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
-
-        float translation =
-                scrollState.distanceFromScreenCenter * curveInterpolation * CURVE_FACTOR;
-
-        if (scrollState.lastScrollType == SCROLL_TYPE_WORKSPACE) {
-            // Make sure that the task cards do not overlap with the workspace card
-            float min = scrollState.halfPageWidth * (1 - scale);
-            if (scrollState.isRtl) {
-                setTranslationX(Math.min(translation, min) - scrollState.prevPageExtraWidth);
-            } else {
-                setTranslationX(Math.max(translation, -min) + scrollState.prevPageExtraWidth);
-            }
-        } else {
-            setTranslationX(translation);
-        }
-        scrollState.prevPageExtraWidth = 0;
-        return SCROLL_TYPE_TASK;
-    }
-
-
-    private static final class TaskOutlineProvider extends ViewOutlineProvider {
-
-        private final int mMarginTop;
-        private final float mRadius;
-
-        TaskOutlineProvider(Resources res) {
-            mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
-            mRadius = res.getDimension(R.dimen.task_corner_radius);
-        }
-
-        @Override
-        public void getOutline(View view, Outline outline) {
-            outline.setRoundRect(0, mMarginTop, view.getWidth(),
-                    view.getHeight(), mRadius);
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index aaea379..42e9aee 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -21,8 +21,6 @@
 import android.view.Choreographer;
 import android.view.MotionEvent;
 
-import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.function.Consumer;
@@ -31,32 +29,29 @@
 @FunctionalInterface
 public interface TouchConsumer extends Consumer<MotionEvent> {
 
-    static boolean isInteractionQuick(@InteractionType int interactionType) {
-        return interactionType == INTERACTION_QUICK_SCRUB ||
-                interactionType == INTERACTION_QUICK_SWITCH;
-    }
+    TouchConsumer NO_OP = (ev) -> {};
 
     @IntDef(flag = true, value = {
             INTERACTION_NORMAL,
-            INTERACTION_QUICK_SWITCH,
             INTERACTION_QUICK_SCRUB
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface InteractionType {}
     int INTERACTION_NORMAL = 0;
-    int INTERACTION_QUICK_SWITCH = 1;
-    int INTERACTION_QUICK_SCRUB = 2;
+    int INTERACTION_QUICK_SCRUB = 1;
 
     default void reset() { }
 
-    default void setDownHitTarget(@HitTarget int downHitTarget) { }
-
     default void updateTouchTracking(@InteractionType int interactionType) { }
 
     default void onQuickScrubEnd() { }
 
     default void onQuickScrubProgress(float progress) { }
 
+    default void onQuickStep(MotionEvent ev) { }
+
+    default void onCommand(int command) { }
+
     /**
      * Called on the binder thread to allow the consumer to process the motion event before it is
      * posted on a handler thread.
@@ -66,4 +61,16 @@
     default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
         return null;
     }
+
+    default void deferInit() { }
+
+    default boolean deferNextEventToMainThread() {
+        return false;
+    }
+
+    default boolean forceToLauncherConsumer() {
+        return false;
+    }
+
+    default void onShowOverviewFromAltTab() {}
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ccc1e12..5a1f523 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,35 +21,36 @@
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
+
+import static com.android.systemui.shared.system.ActivityManagerWrapper
+        .CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
 
 import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.Service;
-import android.content.ComponentName;
 import android.content.Intent;
-import android.content.pm.ResolveInfo;
 import android.graphics.PointF;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.Choreographer;
 import android.view.MotionEvent;
-import android.view.View;
+import android.view.VelocityTracker;
 import android.view.ViewConfiguration;
 
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ChoreographerCompat;
 import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
 
 /**
@@ -58,6 +59,15 @@
 @TargetApi(Build.VERSION_CODES.O)
 public class TouchInteractionService extends Service {
 
+    private static final SparseArray<String> sMotionEventNames;
+
+    static {
+        sMotionEventNames = new SparseArray<>(3);
+        sMotionEventNames.put(ACTION_DOWN, "ACTION_DOWN");
+        sMotionEventNames.put(ACTION_UP, "ACTION_UP");
+        sMotionEventNames.put(ACTION_CANCEL, "ACTION_CANCEL");
+    }
+
     public static final int EDGE_NAV_BAR = 1 << 8;
 
     private static final String TAG = "TouchInteractionService";
@@ -70,35 +80,33 @@
     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
 
         @Override
-        public void onPreMotionEvent(@HitTarget int downHitTarget) throws RemoteException {
-            onBinderPreMotionEvent(downHitTarget);
+        public void onPreMotionEvent(@HitTarget int downHitTarget) {
+            TraceHelper.beginSection("SysUiBinder");
+            setupTouchConsumer(downHitTarget);
+            TraceHelper.partitionSection("SysUiBinder", "Down target " + downHitTarget);
         }
 
         @Override
         public void onMotionEvent(MotionEvent ev) {
             mEventQueue.queue(ev);
+
+            String name = sMotionEventNames.get(ev.getActionMasked());
+            if (name != null){
+                TraceHelper.partitionSection("SysUiBinder", name);
+            }
         }
 
         @Override
         public void onBind(ISystemUiProxy iSystemUiProxy) {
             mISystemUiProxy = iSystemUiProxy;
             mRecentsModel.setSystemUiProxy(mISystemUiProxy);
-            RemoteRunnable.executeSafely(() -> mISystemUiProxy.setRecentsOnboardingText(
-                    getResources().getString(R.string.recents_swipe_up_onboarding)));
-            Launcher launcher = (Launcher) LauncherAppState.getInstance(
-                    TouchInteractionService.this).getModel().getCallback();
-            UiFactory.onLauncherStateOrFocusChanged(launcher);
-        }
-
-        @Override
-        public void onQuickSwitch() {
-            mEventQueue.onQuickSwitch();
+            mOverviewInteractionState.setSystemUiProxy(mISystemUiProxy);
         }
 
         @Override
         public void onQuickScrubStart() {
             mEventQueue.onQuickScrubStart();
-            sQuickScrubEnabled = true;
+            TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
         }
 
         @Override
@@ -109,55 +117,77 @@
         @Override
         public void onQuickScrubEnd() {
             mEventQueue.onQuickScrubEnd();
-            sQuickScrubEnabled = false;
+            TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
+        }
+
+        @Override
+        public void onOverviewToggle() {
+            mOverviewCommandHelper.onOverviewToggle();
+        }
+
+        @Override
+        public void onOverviewShown(boolean triggeredFromAltTab) {
+            if (triggeredFromAltTab) {
+                setupTouchConsumer(HIT_TARGET_NONE);
+                mEventQueue.onOverviewShownFromAltTab();
+            } else {
+                mOverviewCommandHelper.onOverviewShown();
+            }
+        }
+
+        @Override
+        public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+            if (triggeredFromAltTab && !triggeredFromHomeKey) {
+                // onOverviewShownFromAltTab initiates quick scrub. Ending it here.
+                mEventQueue.onQuickScrubEnd();
+            }
+        }
+
+        @Override
+        public void onQuickStep(MotionEvent motionEvent) {
+            mEventQueue.onQuickStep(motionEvent);
+            TraceHelper.endSection("SysUiBinder", "onQuickStep");
+
+        }
+
+        @Override
+        public void onTip(int actionType, int viewType) {
+            mOverviewCommandHelper.onTip(actionType, viewType);
         }
     };
 
-    private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
-
     private static boolean sConnected = false;
-    private static boolean sQuickScrubEnabled = false;
 
     public static boolean isConnected() {
         return sConnected;
     }
 
-    public static boolean isQuickScrubEnabled() {
-        return sQuickScrubEnabled;
-    }
-
     private ActivityManagerWrapper mAM;
-    private RunningTaskInfo mRunningTask;
     private RecentsModel mRecentsModel;
-    private Intent mHomeIntent;
-    private ComponentName mLauncher;
     private MotionEventQueue mEventQueue;
     private MainThreadExecutor mMainThreadExecutor;
     private ISystemUiProxy mISystemUiProxy;
+    private OverviewCommandHelper mOverviewCommandHelper;
+    private OverviewInteractionState mOverviewInteractionState;
+    private OverviewCallbacks mOverviewCallbacks;
+    private TaskOverlayFactory mTaskOverlayFactory;
 
     private Choreographer mMainThreadChoreographer;
     private Choreographer mBackgroundThreadChoreographer;
-    private MotionEventQueue mNoOpEventQueue;
 
     @Override
     public void onCreate() {
         super.onCreate();
         mAM = ActivityManagerWrapper.getInstance();
         mRecentsModel = RecentsModel.getInstance(this);
+        mRecentsModel.setPreloadTasksInBackground(true);
         mMainThreadExecutor = new MainThreadExecutor();
-
-        mHomeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(getPackageName())
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0);
-        mLauncher = new ComponentName(getPackageName(), info.activityInfo.name);
-        // Clear the packageName as system can fail to dedupe it b/64108432
-        mHomeIntent.setComponent(mLauncher).setPackage(null);
-
+        mOverviewCommandHelper = new OverviewCommandHelper(this);
         mMainThreadChoreographer = Choreographer.getInstance();
-        mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
-        mEventQueue = mNoOpEventQueue;
+        mEventQueue = new MotionEventQueue(mMainThreadChoreographer, TouchConsumer.NO_OP);
+        mOverviewInteractionState = OverviewInteractionState.getInstance(this);
+        mOverviewCallbacks = OverviewCallbacks.get(this);
+        mTaskOverlayFactory = TaskOverlayFactory.get(this);
 
         sConnected = true;
 
@@ -168,8 +198,8 @@
 
     @Override
     public void onDestroy() {
+        mOverviewCommandHelper.onDestroy();
         sConnected = false;
-        sQuickScrubEnabled = false;
         super.onDestroy();
     }
 
@@ -179,52 +209,80 @@
         return mMyBinder;
     }
 
-    private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
-        mRunningTask = mAM.getRunningTask();
-
+    private void setupTouchConsumer(@HitTarget int downHitTarget) {
         mEventQueue.reset();
-
-        if (mRunningTask == null) {
-            mEventQueue = mNoOpEventQueue;
-        } else if (mRunningTask.topActivity.equals(mLauncher)) {
-            mEventQueue = getLauncherEventQueue();
-        } else {
+        TouchConsumer oldConsumer = mEventQueue.getConsumer();
+        if (oldConsumer.deferNextEventToMainThread()) {
             mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
-                    new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
-                    mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
-                    mBackgroundThreadChoreographer));
+                    new DeferredTouchConsumer((v) -> getCurrentTouchConsumer(downHitTarget,
+                            oldConsumer.forceToLauncherConsumer(), v)));
+            mEventQueue.deferInit();
+        } else {
+            mEventQueue = new MotionEventQueue(
+                    mMainThreadChoreographer, getCurrentTouchConsumer(downHitTarget, false, null));
         }
     }
 
-    private MotionEventQueue getLauncherEventQueue() {
-        Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
-        if (launcher == null) {
-            return mNoOpEventQueue;
-        }
+    private TouchConsumer getCurrentTouchConsumer(
+            @HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) {
+        RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
 
-        View target = launcher.getDragLayer();
-        return new MotionEventQueue(mMainThreadChoreographer,
-                new LauncherTouchConsumer(launcher, target));
+        if (runningTaskInfo == null && !forceToLauncher) {
+            return TouchConsumer.NO_OP;
+        } else if (forceToLauncher ||
+                runningTaskInfo.topActivity.equals(mOverviewCommandHelper.overviewComponent)) {
+            return OverviewTouchConsumer.newInstance(
+                    mOverviewCommandHelper.getActivityControlHelper(), false);
+        } else {
+            if (tracker == null) {
+                tracker = VelocityTracker.obtain();
+            }
+            return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
+                            mOverviewCommandHelper.overviewIntent,
+                            mOverviewCommandHelper.getActivityControlHelper(), mMainThreadExecutor,
+                            mBackgroundThreadChoreographer, downHitTarget, mOverviewCallbacks,
+                            mTaskOverlayFactory, tracker);
+        }
     }
 
-    private static class LauncherTouchConsumer implements TouchConsumer {
+    private void initBackgroundChoreographer() {
+        if (sRemoteUiThread == null) {
+            sRemoteUiThread = new HandlerThread("remote-ui");
+            sRemoteUiThread.start();
+        }
+        new Handler(sRemoteUiThread.getLooper()).post(() ->
+                mBackgroundThreadChoreographer = ChoreographerCompat.getSfInstance());
+    }
 
-        private final Launcher mLauncher;
-        private final View mTarget;
+    public static class OverviewTouchConsumer<T extends BaseDraggingActivity>
+            implements TouchConsumer {
+
+        private final ActivityControlHelper<T> mActivityHelper;
+        private final T mActivity;
+        private final BaseDragLayer mTarget;
         private final int[] mLocationOnScreen = new int[2];
         private final PointF mDownPos = new PointF();
         private final int mTouchSlop;
         private final QuickScrubController mQuickScrubController;
 
+        private final boolean mStartingInActivityBounds;
+
         private boolean mTrackingStarted = false;
         private boolean mInvalidated = false;
 
-        LauncherTouchConsumer(Launcher launcher, View target) {
-            mLauncher = launcher;
-            mTarget = target;
-            mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+        private float mLastProgress = 0;
+        private boolean mStartPending = false;
+        private boolean mEndPending = false;
 
-            mQuickScrubController = mLauncher.<RecentsView>getOverviewPanel()
+        OverviewTouchConsumer(ActivityControlHelper<T> activityHelper, T activity,
+                boolean startingInActivityBounds) {
+            mActivityHelper = activityHelper;
+            mActivity = activity;
+            mTarget = activity.getDragLayer();
+            mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+            mStartingInActivityBounds = startingInActivityBounds;
+
+            mQuickScrubController = mActivity.<RecentsView>getOverviewPanel()
                     .getQuickScrubController();
         }
 
@@ -233,11 +291,12 @@
             if (mInvalidated) {
                 return;
             }
-            if (!mTarget.hasWindowFocus()) {
-                return;
-            }
             int action = ev.getActionMasked();
             if (action == ACTION_DOWN) {
+                if (mStartingInActivityBounds) {
+                    startTouchTracking(ev, false /* updateLocationOffset */);
+                    return;
+                }
                 mTrackingStarted = false;
                 mDownPos.set(ev.getX(), ev.getY());
             } else if (!mTrackingStarted) {
@@ -248,17 +307,15 @@
                             mInvalidated = true;
                         }
                         break;
+                    case ACTION_CANCEL:
+                    case ACTION_UP:
+                        startTouchTracking(ev, true /* updateLocationOffset */);
+                        break;
                     case ACTION_MOVE: {
                         float displacement = ev.getY() - mDownPos.y;
                         if (Math.abs(displacement) >= mTouchSlop) {
-                            mTrackingStarted = true;
-                            mTarget.getLocationOnScreen(mLocationOnScreen);
-
-                            // Send a down event only when mTouchSlop is crossed.
-                            MotionEvent down = MotionEvent.obtain(ev);
-                            down.setAction(ACTION_DOWN);
-                            sendEvent(down);
-                            down.recycle();
+                            // Start tracking only when mTouchSlop is crossed.
+                            startTouchTracking(ev, true /* updateLocationOffset */);
                         }
                     }
                 }
@@ -273,36 +330,73 @@
             }
         }
 
+        private void startTouchTracking(MotionEvent ev, boolean updateLocationOffset) {
+            if (updateLocationOffset) {
+                mTarget.getLocationOnScreen(mLocationOnScreen);
+            }
+
+            // Send down touch event
+            MotionEvent down = MotionEvent.obtain(ev);
+            down.setAction(ACTION_DOWN);
+            sendEvent(down);
+            down.recycle();
+
+            mTrackingStarted = true;
+        }
+
         private void sendEvent(MotionEvent ev) {
             int flags = ev.getEdgeFlags();
-            ev.setEdgeFlags(flags | EDGE_NAV_BAR);
+            ev.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
             ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
-            mTarget.dispatchTouchEvent(ev);
+            if (!mTrackingStarted) {
+                mTarget.onInterceptTouchEvent(ev);
+            }
+            mTarget.onTouchEvent(ev);
             ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
             ev.setEdgeFlags(flags);
         }
 
         @Override
+        public void onQuickStep(MotionEvent ev) {
+            if (mInvalidated) {
+                return;
+            }
+            OverviewCallbacks.get(mActivity).closeAllWindows();
+            ActivityManagerWrapper.getInstance()
+                    .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+        }
+
+        @Override
         public void updateTouchTracking(int interactionType) {
             if (mInvalidated) {
                 return;
             }
-            if (TouchConsumer.isInteractionQuick(interactionType)) {
+            if (interactionType == INTERACTION_QUICK_SCRUB) {
+                if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+                    mInvalidated = true;
+                    return;
+                }
+                OverviewCallbacks.get(mActivity).closeAllWindows();
+                ActivityManagerWrapper.getInstance()
+                        .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+
+                mStartPending = true;
                 Runnable action = () -> {
-                    Runnable onComplete = null;
-                    if (interactionType == INTERACTION_QUICK_SCRUB) {
-                        mQuickScrubController.onQuickScrubStart(true);
-                    } else if (interactionType == INTERACTION_QUICK_SWITCH) {
-                        onComplete = mQuickScrubController::onQuickSwitch;
+                    if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+                        mInvalidated = true;
+                        return;
                     }
-                    mLauncher.getStateManager().goToState(OVERVIEW, true, 0,
-                            QUICK_SWITCH_START_DURATION, onComplete);
+                    mActivityHelper.onQuickInteractionStart(mActivity, null, true);
+                    mQuickScrubController.onQuickScrubProgress(mLastProgress);
+                    mStartPending = false;
+
+                    if (mEndPending) {
+                        mQuickScrubController.onQuickScrubEnd();
+                        mEndPending = false;
+                    }
                 };
 
-                if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
-                    // Hide the minus one overlay so launcher can get window focus.
-                    mLauncher.onQuickstepGestureStarted(true);
-                }
+                mActivityHelper.executeOnWindowAvailable(mActivity, action);
             }
         }
 
@@ -311,25 +405,29 @@
             if (mInvalidated) {
                 return;
             }
-            mQuickScrubController.onQuickScrubEnd();
+            if (mStartPending) {
+                mEndPending = true;
+            } else {
+                mQuickScrubController.onQuickScrubEnd();
+            }
         }
 
         @Override
         public void onQuickScrubProgress(float progress) {
-            if (mInvalidated) {
+            mLastProgress = progress;
+            if (mInvalidated || mStartPending) {
                 return;
             }
             mQuickScrubController.onQuickScrubProgress(progress);
         }
 
-    }
-
-    private void initBackgroundChoreographer() {
-        if (sRemoteUiThread == null) {
-            sRemoteUiThread = new HandlerThread("remote-ui");
-            sRemoteUiThread.start();
+        public static TouchConsumer newInstance(
+                ActivityControlHelper activityHelper, boolean startingInActivityBounds) {
+            BaseDraggingActivity activity = activityHelper.getCreatedActivity();
+            if (activity == null) {
+                return TouchConsumer.NO_OP;
+            }
+            return new OverviewTouchConsumer(activityHelper, activity, startingInActivityBounds);
         }
-        new Handler(sRemoteUiThread.getLooper()).post(() ->
-                mBackgroundThreadChoreographer = Choreographer.getInstance());
     }
 }
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 6b1c5e1..8e34490 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -15,133 +15,164 @@
  */
 package com.android.quickstep;
 
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
+import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.Utilities.postAsyncCallback;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_FROM_APP_START_DURATION;
 import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
-import static com.android.quickstep.TouchConsumer.isInteractionQuick;
-import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 
 import android.animation.Animator;
-import android.animation.AnimatorSet;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.animation.RectEvaluator;
 import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
-import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
-import android.graphics.Matrix;
+import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.support.annotation.AnyThread;
 import android.support.annotation.UiThread;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
+import android.view.HapticFeedbackConstants;
 import android.view.View;
 import android.view.ViewTreeObserver.OnDrawListener;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.ActivityControlHelper.AnimationFactory;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
 import com.android.quickstep.TouchConsumer.InteractionType;
+import com.android.quickstep.TouchInteractionService.OverviewTouchConsumer;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
+import com.android.quickstep.util.TransformedRect;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.LatencyTrackerCompat;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.WindowCallbacksCompat;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
 import java.util.StringJoiner;
+import java.util.function.BiFunction;
 
 @TargetApi(Build.VERSION_CODES.O)
-public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler {
+public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
     private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
     private static final boolean DEBUG_STATES = false;
 
     // Launcher UI related states
     private static final int STATE_LAUNCHER_PRESENT = 1 << 0;
-    private static final int STATE_LAUNCHER_DRAWN = 1 << 1;
-    private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 2;
+    private static final int STATE_LAUNCHER_STARTED = 1 << 1;
+    private static final int STATE_LAUNCHER_DRAWN = 1 << 2;
+    private static final int STATE_ACTIVITY_MULTIPLIER_COMPLETE = 1 << 3;
 
     // Internal initialization states
-    private static final int STATE_APP_CONTROLLER_RECEIVED = 1 << 3;
+    private static final int STATE_APP_CONTROLLER_RECEIVED = 1 << 4;
 
     // Interaction finish states
-    private static final int STATE_SCALED_CONTROLLER_RECENTS = 1 << 4;
-    private static final int STATE_SCALED_CONTROLLER_APP = 1 << 5;
+    private static final int STATE_SCALED_CONTROLLER_RECENTS = 1 << 5;
+    private static final int STATE_SCALED_CONTROLLER_APP = 1 << 6;
 
-    private static final int STATE_HANDLER_INVALIDATED = 1 << 6;
-    private static final int STATE_GESTURE_STARTED = 1 << 7;
+    private static final int STATE_HANDLER_INVALIDATED = 1 << 7;
+    private static final int STATE_GESTURE_STARTED_QUICKSTEP = 1 << 8;
+    private static final int STATE_GESTURE_STARTED_QUICKSCRUB = 1 << 9;
+    private static final int STATE_GESTURE_CANCELLED = 1 << 10;
+    private static final int STATE_GESTURE_COMPLETED = 1 << 11;
 
     // States for quick switch/scrub
-    private static final int STATE_SWITCH_TO_SCREENSHOT_COMPLETE = 1 << 8;
-    private static final int STATE_QUICK_SWITCH = 1 << 9;
-    private static final int STATE_QUICK_SCRUB_START = 1 << 10;
-    private static final int STATE_QUICK_SCRUB_END = 1 << 11;
+    private static final int STATE_CURRENT_TASK_FINISHED = 1 << 12;
+    private static final int STATE_QUICK_SCRUB_START = 1 << 13;
+    private static final int STATE_QUICK_SCRUB_END = 1 << 14;
 
+    private static final int STATE_CAPTURE_SCREENSHOT = 1 << 15;
+    private static final int STATE_SCREENSHOT_CAPTURED = 1 << 16;
+
+    private static final int STATE_RESUME_LAST_TASK = 1 << 17;
+    private static final int STATE_ASSIST_DATA_RECEIVED = 1 << 18;
 
     private static final int LAUNCHER_UI_STATES =
-            STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE;
+            STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_ACTIVITY_MULTIPLIER_COMPLETE
+            | STATE_LAUNCHER_STARTED;
+
+    private static final int LONG_SWIPE_ENTER_STATE =
+            STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED
+                    | STATE_APP_CONTROLLER_RECEIVED;
+
+    private static final int LONG_SWIPE_START_STATE =
+            STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_STARTED
+                    | STATE_APP_CONTROLLER_RECEIVED | STATE_SCREENSHOT_CAPTURED;
 
     // For debugging, keep in sync with above states
     private static final String[] STATES = new String[] {
             "STATE_LAUNCHER_PRESENT",
+            "STATE_LAUNCHER_STARTED",
             "STATE_LAUNCHER_DRAWN",
             "STATE_ACTIVITY_MULTIPLIER_COMPLETE",
             "STATE_APP_CONTROLLER_RECEIVED",
             "STATE_SCALED_CONTROLLER_RECENTS",
             "STATE_SCALED_CONTROLLER_APP",
             "STATE_HANDLER_INVALIDATED",
-            "STATE_GESTURE_STARTED",
-            "STATE_SWITCH_TO_SCREENSHOT_COMPLETE",
-            "STATE_QUICK_SWITCH",
+            "STATE_GESTURE_STARTED_QUICKSTEP",
+            "STATE_GESTURE_STARTED_QUICKSCRUB",
+            "STATE_GESTURE_CANCELLED",
+            "STATE_GESTURE_COMPLETED",
+            "STATE_CURRENT_TASK_FINISHED",
             "STATE_QUICK_SCRUB_START",
-            "STATE_QUICK_SCRUB_END"
+            "STATE_QUICK_SCRUB_END",
+            "STATE_CAPTURE_SCREENSHOT",
+            "STATE_SCREENSHOT_CAPTURED",
+            "STATE_RESUME_LAST_TASK",
+            "STATE_ASSIST_DATA_RECEIVED",
     };
 
-    private static final long MAX_SWIPE_DURATION = 200;
-    private static final long MIN_SWIPE_DURATION = 80;
+    public static final long MAX_SWIPE_DURATION = 350;
+    public static final long MIN_SWIPE_DURATION = 80;
+    public static final long MIN_OVERSHOOT_DURATION = 120;
 
-    private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
+    public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
+    private static final float SWIPE_DURATION_MULTIPLIER =
+            Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
 
-    // The bounds of the source app in device coordinates
-    private final Rect mSourceStackBounds = new Rect();
-    // The insets of the source app
-    private final Rect mSourceInsets = new Rect();
-    // The source app bounds with the source insets applied, in the source app window coordinates
-    private final Rect mSourceRect = new Rect();
-    // The insets to be used for clipping the app window, which can be larger than mSourceInsets
-    // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
-    // app window coordinates.
-    private final Rect mSourceWindowClipInsets = new Rect();
-    // The bounds of launcher (not including insets) in device coordinates
-    private final Rect mHomeStackBounds = new Rect();
-    // The bounds of the task view in launcher window coordinates
-    private final Rect mTargetRect = new Rect();
-    // Doesn't change after initialized, used as an anchor when changing mTargetRect
-    private final Rect mInitialTargetRect = new Rect();
-    // The interpolated rect from the source app rect to the target rect
-    private final Rect mCurrentRect = new Rect();
-    // The clip rect in source app window coordinates
-    private final Rect mClipRect = new Rect();
-    private final RectEvaluator mRectEvaluator = new RectEvaluator(mCurrentRect);
+    private final ClipAnimationHelper mClipAnimationHelper = new ClipAnimationHelper();
+
+    protected Runnable mGestureEndCallback;
+    protected boolean mIsGoingToHome;
     private DeviceProfile mDp;
     private int mTransitionDragLength;
 
@@ -151,38 +182,68 @@
     // visible.
     private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
 
-    private final MainThreadExecutor mMainExecutor = new MainThreadExecutor();
+    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
 
+    // An increasing identifier per single instance of OtherActivityTouchConsumer. Generally one
+    // instance of OtherActivityTouchConsumer will only have one swipe handle, but sometimes we can
+    // end up with multiple handlers if we get recents command in the middle of a swipe gesture.
+    // This is used to match the corresponding activity manager callbacks in
+    // OtherActivityTouchConsumer
+    public final int id;
     private final Context mContext;
+    private final ActivityControlHelper<T> mActivityControlHelper;
+    private final ActivityInitListener mActivityInitListener;
+
     private final int mRunningTaskId;
+    private final RunningTaskInfo mRunningTaskInfo;
+    private ThumbnailData mTaskSnapshot;
 
     private MultiStateCallback mStateCallback;
     private AnimatorPlaybackController mLauncherTransitionController;
 
-    private Launcher mLauncher;
-    private LauncherLayoutListener mLauncherLayoutListener;
+    private T mActivity;
+    private LayoutListener mLayoutListener;
     private RecentsView mRecentsView;
+    private SyncRtSurfaceTransactionApplier mSyncTransactionApplier;
     private QuickScrubController mQuickScrubController;
+    private AnimationFactory mAnimationFactory = (t, i) -> { };
 
     private Runnable mLauncherDrawnCallback;
 
     private boolean mWasLauncherAlreadyVisible;
 
-    private float mCurrentDisplacement;
+    private boolean mPassedOverviewThreshold;
     private boolean mGestureStarted;
+    private int mLogAction = Touch.SWIPE;
+    private float mCurrentQuickScrubProgress;
+    private boolean mQuickScrubBlocked;
 
     private @InteractionType int mInteractionType = INTERACTION_NORMAL;
 
-    private InputConsumerController mInputConsumer =
-            InputConsumerController.getRecentsAnimationInputConsumer();
+    private final RecentsAnimationWrapper mRecentsAnimationWrapper =
+            new RecentsAnimationWrapper(this::createNewTouchProxyHandler);
 
-    private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
-    private Matrix mTmpMatrix = new Matrix();
+    private final long mTouchTimeMs;
+    private long mLauncherFrameDrawnTime;
 
-    WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
+    private boolean mBgLongSwipeMode = false;
+    private boolean mUiLongSwipeMode = false;
+    private float mLongSwipeDisplacement = 0;
+    private LongSwipeHelper mLongSwipeController;
+
+    private Bundle mAssistData;
+
+    WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context,
+            long touchTimeMs, ActivityControlHelper<T> controller) {
+        this.id = id;
         mContext = context;
+        mRunningTaskInfo = runningTaskInfo;
         mRunningTaskId = runningTaskInfo.id;
-        mInputConsumer.registerInputConsumer();
+        mTouchTimeMs = touchTimeMs;
+        mActivityControlHelper = controller;
+        mActivityInitListener = mActivityControlHelper
+                .createActivityInitListener(this::onActivityInit);
+
         initStateCallbacks();
     }
 
@@ -195,82 +256,92 @@
             }
         };
 
-        mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
+        mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSCRUB,
                 this::initializeLauncherAnimationController);
+        mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED_QUICKSTEP,
+                this::initializeLauncherAnimationController);
+
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN,
                 this::launcherFrameDrawn);
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED,
-                this::notifyGestureStarted);
 
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_APP | STATE_APP_CONTROLLER_RECEIVED,
-                this::resumeLastTask);
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS
-                | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_APP_CONTROLLER_RECEIVED,
-                this::switchToScreenshot);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED_QUICKSTEP,
+                this::notifyGestureStartedAsync);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_STARTED_QUICKSCRUB,
+                this::notifyGestureStartedAsync);
 
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS
-                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE,
-                this::setupLauncherUiAfterSwipeUpAnimation);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
+                        | STATE_GESTURE_CANCELLED,
+                this::resetStateForAnimationCancel);
+
+        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
+                this::sendRemoteAnimationsToAnimationFactory);
 
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_APP,
-                this::reset);
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_RECENTS,
-                this::reset);
+                this::resumeLastTaskForQuickstep);
+        mStateCallback.addCallback(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
+                this::resumeLastTask);
+
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE
+                        | STATE_CAPTURE_SCREENSHOT,
+                this::switchToScreenshot);
+
+        mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED
+                        | STATE_SCALED_CONTROLLER_RECENTS,
+                this::finishCurrentTransitionToHome);
+
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_SCALED_CONTROLLER_RECENTS
+                        | STATE_CURRENT_TASK_FINISHED | STATE_GESTURE_COMPLETED
+                        | STATE_GESTURE_STARTED_QUICKSTEP,
+                this::setupLauncherUiAfterSwipeUpAnimation);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_SCALED_CONTROLLER_RECENTS
+                        | STATE_CURRENT_TASK_FINISHED | STATE_GESTURE_COMPLETED
+                        | STATE_GESTURE_STARTED_QUICKSTEP | STATE_ASSIST_DATA_RECEIVED,
+                this::preloadAssistData);
 
         mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                 this::invalidateHandlerWithLauncher);
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED
+                | STATE_SCALED_CONTROLLER_APP,
+                this::notifyTransitionCancelled);
 
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SWITCH,
-                this::onQuickInteractionStart);
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SCRUB_START,
-                this::onQuickInteractionStart);
-
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SWITCH_TO_SCREENSHOT_COMPLETE
-                | STATE_QUICK_SWITCH, this::switchToFinalAppAfterQuickSwitch);
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SWITCH_TO_SCREENSHOT_COMPLETE
+        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
+                        | STATE_APP_CONTROLLER_RECEIVED, this::onQuickScrubStart);
+        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
+                | STATE_SCALED_CONTROLLER_RECENTS, this::onFinishedTransitionToQuickScrub);
+        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_CURRENT_TASK_FINISHED
                 | STATE_QUICK_SCRUB_END, this::switchToFinalAppAfterQuickScrub);
+
+        mStateCallback.addCallback(LONG_SWIPE_ENTER_STATE, this::checkLongSwipeCanEnter);
+        mStateCallback.addCallback(LONG_SWIPE_START_STATE, this::checkLongSwipeCanStart);
+    }
+
+    private void executeOnUiThread(Runnable action) {
+        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
+            action.run();
+        } else {
+            postAsyncCallback(mMainThreadHandler, action);
+        }
     }
 
     private void setStateOnUiThread(int stateFlag) {
-        Handler handler = mMainExecutor.getHandler();
-        if (Looper.myLooper() == handler.getLooper()) {
+        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
             mStateCallback.setState(stateFlag);
         } else {
-            postAtFrontOfQueueAsynchronously(handler, () -> mStateCallback.setState(stateFlag));
+            postAsyncCallback(mMainThreadHandler, () -> mStateCallback.setState(stateFlag));
         }
     }
 
     private void initTransitionEndpoints(DeviceProfile dp) {
         mDp = dp;
 
-        mSourceRect.set(0, 0, dp.widthPx - mSourceInsets.left - mSourceInsets.right,
-                dp.heightPx - mSourceInsets.top - mSourceInsets.bottom);
-        RecentsView.getPageRect(dp, mContext, mTargetRect);
-        mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
-                mHomeStackBounds.top - mSourceStackBounds.top);
-        mInitialTargetRect.set(mTargetRect);
-
-        // Calculate the clip based on the target rect (since the content insets and the
-        // launcher insets may differ, so the aspect ratio of the target rect can differ
-        // from the source rect. The difference between the target rect (scaled to the
-        // source rect) is the amount to clip on each edge.
-        Rect scaledTargetRect = new Rect(mTargetRect);
-        Utilities.scaleRectAboutCenter(scaledTargetRect,
-                (float) mSourceRect.width() / mTargetRect.width());
-        scaledTargetRect.offsetTo(mSourceInsets.left, mSourceInsets.top);
-        mSourceWindowClipInsets.set(scaledTargetRect.left, scaledTargetRect.top,
-                mDp.widthPx - scaledTargetRect.right,
-                mDp.heightPx - scaledTargetRect.bottom);
-
-        Rect targetInsets = dp.getInsets();
-        mTransitionDragLength = dp.hotseatBarSizePx;
-        if (dp.isVerticalBarLayout()) {
-            int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
-            mTransitionDragLength += dp.hotseatBarSidePaddingPx + hotseatInset;
-        } else {
-            mTransitionDragLength += targetInsets.bottom;
-        }
+        TransformedRect tempRect = new TransformedRect();
+        mTransitionDragLength = mActivityControlHelper
+                .getSwipeUpDestinationAndLength(dp, mContext, mInteractionType, tempRect);
+        mClipAnimationHelper.updateTargetRect(tempRect);
     }
 
     private long getFadeInDuration() {
@@ -285,81 +356,84 @@
         }
     }
 
-    @Override
-    protected boolean init(final Launcher launcher, boolean alreadyOnHome) {
-        if (launcher == mLauncher) {
+    public void initWhenReady() {
+        mActivityInitListener.register();
+    }
+
+    private boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
+        if (mActivity == activity) {
             return true;
         }
-        if (mLauncher != null) {
+        if (mActivity != null) {
             // The launcher may have been recreated as a result of device rotation.
             int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
             initStateCallbacks();
             mStateCallback.setState(oldState);
-            mLauncherLayoutListener.setHandler(null);
+            mLayoutListener.setHandler(null);
         }
         mWasLauncherAlreadyVisible = alreadyOnHome;
-        mLauncher = launcher;
-
-        // For the duration of the gesture, lock the screen orientation to ensure that we do not
-        // rotate mid-quickscrub
-        mLauncher.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
-
-        LauncherState startState = mLauncher.getStateManager().getState();
-        if (startState.disableRestore) {
-            startState = mLauncher.getStateManager().getRestState();
+        mActivity = activity;
+        // Override the visibility of the activity until the gesture actually starts and we swipe
+        // up, or until we transition home and the home animation is composed
+        if (alreadyOnHome) {
+            mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+        } else {
+            mActivity.addForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
         }
-        mLauncher.getStateManager().setRestState(startState);
 
-        AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
-
-        mRecentsView = mLauncher.getOverviewPanel();
+        mRecentsView = activity.getOverviewPanel();
+        mSyncTransactionApplier = new SyncRtSurfaceTransactionApplier(mRecentsView);
         mQuickScrubController = mRecentsView.getQuickScrubController();
-        mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
+        mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
 
-        final int state;
+        mStateCallback.setState(STATE_LAUNCHER_PRESENT);
+        if (alreadyOnHome) {
+            onLauncherStart(activity);
+        } else {
+            activity.setOnStartCallback(this::onLauncherStart);
+        }
+        return true;
+    }
+
+    private void onLauncherStart(final T activity) {
+        if (mActivity != activity) {
+            return;
+        }
+        if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
+            return;
+        }
+
+        mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
+                mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
+        AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);
+
         if (mWasLauncherAlreadyVisible) {
-            DeviceProfile dp = mLauncher.getDeviceProfile();
-            long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
-            mLauncherTransitionController = launcher.getStateManager()
-                    .createAnimationToNewWorkspace(OVERVIEW, accuracy);
-            mLauncherTransitionController.dispatchOnStart();
-            mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
-
-            state = STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN
-                    | STATE_LAUNCHER_PRESENT;
+            mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN);
         } else {
             TraceHelper.beginSection("WTS-init");
-            launcher.getStateManager().goToState(OVERVIEW, false);
-            TraceHelper.partitionSection("WTS-init", "State changed");
-
-            // TODO: Implement a better animation for fading in
-            View rootView = launcher.getRootView();
-            rootView.setAlpha(0);
-            rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
+            View dragLayer = activity.getDragLayer();
+            mActivityControlHelper.getAlphaProperty(activity).setValue(0);
+            dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
 
                 @Override
                 public void onDraw() {
                     TraceHelper.endSection("WTS-init", "Launcher frame is drawn");
-                    rootView.post(() ->
-                            rootView.getViewTreeObserver().removeOnDrawListener(this));
-                    if (launcher != mLauncher) {
+                    dragLayer.post(() ->
+                            dragLayer.getViewTreeObserver().removeOnDrawListener(this));
+                    if (activity != mActivity) {
                         return;
                     }
 
                     mStateCallback.setState(STATE_LAUNCHER_DRAWN);
                 }
             });
-            state = STATE_LAUNCHER_PRESENT;
-
-            // Optimization, hide the all apps view to prevent layout while initializing
-            mLauncher.getAppsView().setVisibility(View.GONE);
         }
 
         mRecentsView.showTask(mRunningTaskId);
-        mLauncherLayoutListener.open();
-
-        mStateCallback.setState(state);
-        return true;
+        mRecentsView.setRunningTaskHidden(true);
+        mRecentsView.setRunningTaskIconScaledDown(true);
+        mLayoutListener.open();
+        mStateCallback.setState(STATE_LAUNCHER_STARTED);
     }
 
     public void setLauncherOnDrawCallback(Runnable callback) {
@@ -367,26 +441,48 @@
     }
 
     private void launcherFrameDrawn() {
-        View rootView = mLauncher.getRootView();
-        if (rootView.getAlpha() < 1) {
+        AlphaProperty property = mActivityControlHelper.getAlphaProperty(mActivity);
+        if (property.getValue() < 1) {
             if (mGestureStarted) {
                 final MultiStateCallback callback = mStateCallback;
-                rootView.animate().alpha(1)
-                        .setDuration(getFadeInDuration())
-                        .withEndAction(() -> callback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE));
+                ObjectAnimator animator = ObjectAnimator.ofFloat(
+                        property, MultiValueAlpha.VALUE, 1);
+                animator.setDuration(getFadeInDuration()).addListener(
+                        new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                callback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
+                            }
+                        });
+                animator.start();
             } else {
-                rootView.setAlpha(1);
+                property.setValue(1);
                 mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
             }
         }
         if (mLauncherDrawnCallback != null) {
             mLauncherDrawnCallback.run();
         }
+        mLauncherFrameDrawnTime = SystemClock.uptimeMillis();
+    }
+
+    private void sendRemoteAnimationsToAnimationFactory() {
+        mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationWrapper.targetSet);
     }
 
     private void initializeLauncherAnimationController() {
-        mLauncherLayoutListener.setHandler(this);
-        onLauncherLayoutChanged();
+        mLayoutListener.setHandler(this);
+        buildAnimationController();
+
+        if (LatencyTrackerCompat.isEnabled(mContext)) {
+            LatencyTrackerCompat.logToggleRecents((int) (mLauncherFrameDrawnTime - mTouchTimeMs));
+        }
+
+        // This method is only called when STATE_GESTURE_STARTED_QUICKSTEP/
+        // STATE_GESTURE_STARTED_QUICKSCRUB is set, so we can enable the high-res thumbnail loader
+        // here once we are sure that we will end up in an overview state
+        RecentsModel.getInstance(mContext).getRecentsTaskLoader()
+                .getHighResThumbnailLoader().setVisible(true);
     }
 
     public void updateInteractionType(@InteractionType int interactionType) {
@@ -394,172 +490,179 @@
             throw new IllegalArgumentException(
                     "Can't change interaction type from " + mInteractionType);
         }
-        if (!isInteractionQuick(interactionType)) {
+        if (interactionType != INTERACTION_QUICK_SCRUB) {
             throw new IllegalArgumentException(
                     "Can't change interaction type to " + interactionType);
         }
         mInteractionType = interactionType;
+        mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub);
 
-        setStateOnUiThread(interactionType == INTERACTION_QUICK_SWITCH
-                ? STATE_QUICK_SWITCH : STATE_QUICK_SCRUB_START);
+        setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED);
 
         // Start the window animation without waiting for launcher.
-        animateToProgress(1f, QUICK_SWITCH_START_DURATION);
+        animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR,
+                true /* goingToHome */);
     }
 
-    private void onQuickInteractionStart() {
-        mQuickScrubController.onQuickScrubStart(false);
+    private void shiftAnimationDestinationForQuickscrub() {
+        TransformedRect tempRect = new TransformedRect();
+        mActivityControlHelper
+                .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect);
+        mClipAnimationHelper.updateTargetRect(tempRect);
+
+        float offsetY =
+                mActivityControlHelper.getTranslationYForQuickScrub(tempRect, mDp, mContext);
+        float scale, offsetX;
+        Resources res = mContext.getResources();
+
+        if (ActivityManagerWrapper.getInstance().getRecentTasks(2, UserHandle.myUserId()).size()
+                < 2) {
+            // There are not enough tasks, we don't need to shift
+            offsetX = 0;
+            scale = 1;
+        } else {
+            offsetX = res.getDimensionPixelSize(R.dimen.recents_page_spacing)
+                    + tempRect.rect.width();
+            float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 +
+                    res.getDimensionPixelSize(R.dimen.recents_page_spacing);
+            float interpolation = Math.min(1, offsetX / distanceToReachEdge);
+            scale = TaskView.getCurveScaleForInterpolation(interpolation);
+        }
+        mClipAnimationHelper.offsetTarget(scale, Utilities.isRtl(res) ? -offsetX : offsetX, offsetY,
+                QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR);
     }
 
     @WorkerThread
     public void updateDisplacement(float displacement) {
-        mCurrentDisplacement = displacement;
+        // We are moving in the negative x/y direction
+        displacement = -displacement;
+        if (displacement > mTransitionDragLength) {
+            mCurrentShift.updateValue(1);
 
-        float translation = Utilities.boundToRange(-mCurrentDisplacement, 0, mTransitionDragLength);
-        float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
-        mCurrentShift.updateValue(shift);
+            if (!mBgLongSwipeMode) {
+                mBgLongSwipeMode = true;
+                executeOnUiThread(this::onLongSwipeEnabledUi);
+            }
+            mLongSwipeDisplacement = displacement - mTransitionDragLength;
+            executeOnUiThread(this::onLongSwipeDisplacementUpdated);
+        } else {
+            if (mBgLongSwipeMode) {
+                mBgLongSwipeMode = false;
+                executeOnUiThread(this::onLongSwipeDisabledUi);
+            }
+            float translation = Math.max(displacement, 0);
+            float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
+            mCurrentShift.updateValue(shift);
+        }
     }
 
     /**
-     * Called by {@link #mLauncherLayoutListener} when launcher layout changes
+     * Called by {@link #mLayoutListener} when launcher layout changes
      */
-    public void onLauncherLayoutChanged() {
-        initTransitionEndpoints(mLauncher.getDeviceProfile());
+    public void buildAnimationController() {
+        initTransitionEndpoints(mActivity.getDeviceProfile());
+        mAnimationFactory.createActivityController(mTransitionDragLength, mInteractionType);
+    }
 
-        if (!mWasLauncherAlreadyVisible) {
-            float startProgress;
-            AllAppsTransitionController controller = mLauncher.getAllAppsController();
-
-            if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
-                startProgress = 1;
-            } else {
-                float scrollRange = Math.max(controller.getShiftRange(), 1);
-                startProgress = (mTransitionDragLength / scrollRange) + 1;
-            }
-            AnimatorSet anim = new AnimatorSet();
-            ObjectAnimator shiftAnim = ObjectAnimator.ofFloat(controller, ALL_APPS_PROGRESS,
-                    startProgress, OVERVIEW.getVerticalProgress(mLauncher));
-            shiftAnim.setInterpolator(LINEAR);
-            anim.play(shiftAnim);
-
-            // TODO: Link this animation to state animation, so that it is cancelled
-            // automatically on state change
-            anim.setDuration(mTransitionDragLength * 2);
-            mLauncherTransitionController =
-                    AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
-            mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
-        }
+    private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
+        mLauncherTransitionController = anim;
+        mLauncherTransitionController.dispatchOnStart();
+        mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
     }
 
     @WorkerThread
     private void updateFinalShift() {
         float shift = mCurrentShift.value;
 
-        synchronized (mRecentsAnimationWrapper) {
-            if (mRecentsAnimationWrapper.controller != null) {
-                synchronized (mTargetRect) {
-                    mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
-                }
-                float scale = (float) mCurrentRect.width() / mSourceRect.width();
+        RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
+        if (controller != null) {
 
-                mClipRect.left = (int) (mSourceWindowClipInsets.left * shift);
-                mClipRect.top = (int) (mSourceWindowClipInsets.top * shift);
-                mClipRect.right = (int) (mDp.widthPx - (mSourceWindowClipInsets.right * shift));
-                mClipRect.bottom = (int) (mDp.heightPx - (mSourceWindowClipInsets.bottom * shift));
+            mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift,
+                    Looper.myLooper() == mMainThreadHandler.getLooper()
+                            ? mSyncTransactionApplier
+                            : null);
 
-                mTmpMatrix.setScale(scale, scale, 0, 0);
-                mTmpMatrix.postTranslate(mCurrentRect.left - mSourceInsets.left * scale * shift,
-                        mCurrentRect.top - mSourceInsets.top * scale * shift);
-                TransactionCompat transaction = new TransactionCompat();
-                for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
-                    if (app.mode == MODE_CLOSING) {
-                        transaction.setMatrix(app.leash, mTmpMatrix)
-                                .setWindowCrop(app.leash, mClipRect)
-                                .show(app.leash);
-                    }
-                }
-                transaction.apply();
+            boolean passedThreshold = shift > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
+            mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
+            if (mActivityControlHelper.shouldMinimizeSplitScreen()) {
+                mRecentsAnimationWrapper.setSplitScreenMinimizedForTransaction(passedThreshold);
             }
         }
 
-        if (mLauncherTransitionController != null) {
-            Runnable runOnUi = () -> {
-                if (mLauncherTransitionController == null) {
-                    return;
-                }
-                mLauncherTransitionController.setPlayFraction(shift);
-
-                // Make sure the window follows the first task if it moves, e.g. during quick scrub.
-                int firstTaskIndex = mRecentsView.getFirstTaskIndex();
-                View firstTask = mRecentsView.getPageAt(firstTaskIndex);
-                int scrollForFirstTask = mRecentsView.getScrollForPage(firstTaskIndex);
-                int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
-                if (offsetFromFirstTask != 0) {
-                    synchronized (mTargetRect) {
-                        mTargetRect.set(mInitialTargetRect);
-                        Utilities.scaleRectAboutCenter(mTargetRect, firstTask.getScaleX());
-                        int offsetX = (int) (offsetFromFirstTask + firstTask.getTranslationX());
-                        mTargetRect.offset(offsetX, 0);
-                    }
-                }
-            };
-            if (Looper.getMainLooper() == Looper.myLooper()) {
-                runOnUi.run();
-            } else {
-                // The fling operation completed even before the launcher was drawn
-                mMainExecutor.execute(runOnUi);
-            }
-        }
+        executeOnUiThread(this::updateFinalShiftUi);
     }
 
-    public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
-            RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) {
-        if (apps != null) {
-            // Use the top closing app to determine the insets for the animation
-            for (RemoteAnimationTargetCompat target : apps) {
-                if (target.mode == MODE_CLOSING) {
-                    DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
-                    if (minimizedHomeBounds != null) {
-                        mHomeStackBounds.set(minimizedHomeBounds);
-                        dp = dp.getMultiWindowProfile(mContext,
-                                new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
-                        dp.updateInsets(homeContentInsets);
-                    } else {
-                        mHomeStackBounds.set(new Rect(0, 0, dp.widthPx, dp.heightPx));
-                        // TODO: Workaround for an existing issue where the home content insets are
-                        // not valid immediately after rotation, just use the stable insets for now
-                        Rect insets = new Rect();
-                        WindowManagerWrapper.getInstance().getStableInsets(insets);
-                        dp.updateInsets(insets);
-                    }
-
-                    // Initialize the start and end animation bounds
-                    // TODO: Remove once platform is updated
-                    try {
-                        mSourceInsets.set(target.getContentInsets());
-                    } catch (Error e) {
-                        // TODO: Remove once platform is updated, use stable insets as fallback
-                        WindowManagerWrapper.getInstance().getStableInsets(mSourceInsets);
-                    }
-                    mSourceStackBounds.set(target.sourceContainerBounds);
-
-                    initTransitionEndpoints(dp);
-                    break;
-                }
+    private void updateFinalShiftUi() {
+        final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
+        if (passed != mPassedOverviewThreshold) {
+            mPassedOverviewThreshold = passed;
+            if (mInteractionType == INTERACTION_NORMAL && mRecentsView != null) {
+                mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
             }
         }
 
-        mRecentsAnimationWrapper.setController(controller, apps);
+        if (mLauncherTransitionController == null || mLauncherTransitionController
+                .getAnimationPlayer().isStarted()) {
+            return;
+        }
+        mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
+    }
+
+    public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
+            RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
+        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
+        final Rect overviewStackBounds;
+        RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
+
+        if (minimizedHomeBounds != null && runningTaskTarget != null) {
+            overviewStackBounds = mActivityControlHelper
+                    .getOverviewWindowBounds(minimizedHomeBounds, runningTaskTarget);
+            dp = dp.getMultiWindowProfile(mContext,
+                    new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
+            dp.updateInsets(homeContentInsets);
+        } else {
+            if (mActivity != null) {
+                int loc[] = new int[2];
+                View rootView = mActivity.getRootView();
+                rootView.getLocationOnScreen(loc);
+                overviewStackBounds = new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
+                        loc[1] + rootView.getHeight());
+            } else {
+                overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
+            }
+            // If we are not in multi-window mode, home insets should be same as system insets.
+            Rect insets = new Rect();
+            WindowManagerWrapper.getInstance().getStableInsets(insets);
+            dp = dp.copy(mContext);
+            dp.updateInsets(insets);
+        }
+        dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
+
+        if (runningTaskTarget != null) {
+            mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
+        }
+        mClipAnimationHelper.prepareAnimation(false /* isOpening */);
+        initTransitionEndpoints(dp);
+
+        mRecentsAnimationWrapper.setController(controller, targets);
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
+
+        mPassedOverviewThreshold = false;
+    }
+
+    public void onRecentsAnimationCanceled() {
+        mRecentsAnimationWrapper.setController(null, null);
+        mActivityInitListener.unregister();
+        setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
     }
 
     public void onGestureStarted() {
-        if (mLauncher != null) {
-            notifyGestureStarted();
-        }
-
-        setStateOnUiThread(STATE_GESTURE_STARTED);
+        notifyGestureStartedAsync();
+        setStateOnUiThread(mInteractionType == INTERACTION_NORMAL
+                ? STATE_GESTURE_STARTED_QUICKSTEP : STATE_GESTURE_STARTED_QUICKSCRUB);
         mGestureStarted = true;
+        mRecentsAnimationWrapper.hideCurrentInputMethod();
         mRecentsAnimationWrapper.enableInputConsumer();
     }
 
@@ -567,48 +670,161 @@
      * Notifies the launcher that the swipe gesture has started. This can be called multiple times
      * on both background and UI threads
      */
-    private void notifyGestureStarted() {
-        mLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+    @AnyThread
+    private void notifyGestureStartedAsync() {
+        final T curActivity = mActivity;
+        if (curActivity != null) {
+            // Once the gesture starts, we can no longer transition home through the button, so
+            // reset the force override of the activity visibility
+            mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+        }
     }
 
     @WorkerThread
     public void onGestureEnded(float endVelocity) {
-        Resources res = mContext.getResources();
-        float flingThreshold = res.getDimension(R.dimen.quickstep_fling_threshold_velocity);
-        boolean isFling = Math.abs(endVelocity) > flingThreshold;
+        float flingThreshold = mContext.getResources()
+                .getDimension(R.dimen.quickstep_fling_threshold_velocity);
+        boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;
+        setStateOnUiThread(STATE_GESTURE_COMPLETED);
 
-        long duration = MAX_SWIPE_DURATION;
-        final float endShift;
-        if (!isFling) {
-            endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
+        mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
+
+        if (mBgLongSwipeMode) {
+            executeOnUiThread(() -> onLongSwipeGestureFinishUi(endVelocity, isFling));
         } else {
-            endShift = endVelocity < 0 ? 1 : 0;
-            float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
-            if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
-                float distanceToTravel = (endShift - mCurrentShift.value) * mTransitionDragLength;
+            handleNormalGestureEnd(endVelocity, isFling);
+        }
+    }
 
-                // we want the page's snap velocity to approximately match the velocity at
-                // which the user flings, so we scale the duration by a value near to the
-                // derivative of the scroll interpolator at zero, ie. 5.
-                duration = 5 * Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
+    @UiThread
+    private TouchConsumer createNewTouchProxyHandler() {
+        mCurrentShift.finishAnimation();
+        if (mLauncherTransitionController != null) {
+            mLauncherTransitionController.getAnimationPlayer().end();
+        }
+        // Hide the task view, if not already hidden
+        setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
+
+        return OverviewTouchConsumer.newInstance(mActivityControlHelper, true);
+    }
+
+    private void handleNormalGestureEnd(float endVelocity, boolean isFling) {
+        float velocityPxPerMs = endVelocity / 1000;
+        long duration = MAX_SWIPE_DURATION;
+        float currentShift = mCurrentShift.value;
+        final boolean goingToHome;
+        float endShift;
+        final float startShift;
+        Interpolator interpolator = DEACCEL;
+        if (!isFling) {
+            goingToHome = currentShift >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted;
+            endShift = goingToHome ? 1 : 0;
+            long expectedDuration = Math.abs(Math.round((endShift - currentShift)
+                    * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER));
+            duration = Math.min(MAX_SWIPE_DURATION, expectedDuration);
+            startShift = currentShift;
+            interpolator = goingToHome ? OVERSHOOT_1_2 : DEACCEL;
+        } else {
+            goingToHome = endVelocity < 0;
+            endShift = goingToHome ? 1 : 0;
+            startShift = Utilities.boundToRange(currentShift - velocityPxPerMs
+                    * SINGLE_FRAME_MS / mTransitionDragLength, 0, 1);
+            float minFlingVelocity = mContext.getResources()
+                    .getDimension(R.dimen.quickstep_fling_min_velocity);
+            if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
+                if (goingToHome) {
+                    Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
+                            startShift, endShift, endShift, velocityPxPerMs, mTransitionDragLength);
+                    endShift = overshoot.end;
+                    interpolator = overshoot.interpolator;
+                    duration = Utilities.boundToRange(overshoot.duration, MIN_OVERSHOOT_DURATION,
+                            MAX_SWIPE_DURATION);
+                } else {
+                    float distanceToTravel = (endShift - currentShift) * mTransitionDragLength;
+
+                    // we want the page's snap velocity to approximately match the velocity at
+                    // which the user flings, so we scale the duration by a value near to the
+                    // derivative of the scroll interpolator at zero, ie. 2.
+                    long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs));
+                    duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
+                }
             }
         }
+        if (goingToHome) {
+            mRecentsAnimationWrapper.enableTouchProxy();
+        }
 
-        animateToProgress(endShift, duration);
+        animateToProgress(startShift, endShift, duration, interpolator, goingToHome);
+    }
+
+    private void doLogGesture(boolean toLauncher) {
+        DeviceProfile dp = mDp;
+        if (dp == null) {
+            // We probably never received an animation controller, skip logging.
+            return;
+        }
+        final int direction;
+        if (dp.isVerticalBarLayout()) {
+            direction = (dp.isSeascape() ^ toLauncher) ? Direction.LEFT : Direction.RIGHT;
+        } else {
+            direction = toLauncher ? Direction.UP : Direction.DOWN;
+        }
+
+        int dstContainerType = toLauncher ? ContainerType.TASKSWITCHER : ContainerType.APP;
+        UserEventDispatcher.newInstance(mContext).logStateChangeAction(
+                mLogAction, direction,
+                ContainerType.NAVBAR, ContainerType.APP,
+                dstContainerType,
+                0);
     }
 
     /** Animates to the given progress, where 0 is the current app and 1 is overview. */
-    private void animateToProgress(float progress, long duration) {
-        ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
-        anim.setInterpolator(Interpolators.SCROLL);
+    private void animateToProgress(float start, float end, long duration,
+            Interpolator interpolator, boolean goingToHome) {
+        mRecentsAnimationWrapper.runOnInit(() -> animateToProgressInternal(start, end, duration,
+                interpolator, goingToHome));
+    }
+
+    private void animateToProgressInternal(float start, float end, long duration,
+            Interpolator interpolator, boolean goingToHome) {
+        mIsGoingToHome = goingToHome;
+        ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration);
+        anim.setInterpolator(interpolator);
         anim.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationSuccess(Animator animator) {
-                setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
-                        ? STATE_SCALED_CONTROLLER_APP : STATE_SCALED_CONTROLLER_RECENTS);
+                setStateOnUiThread(mIsGoingToHome
+                        ? (STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT)
+                        : STATE_SCALED_CONTROLLER_APP);
             }
         });
         anim.start();
+        long startMillis = SystemClock.uptimeMillis();
+        executeOnUiThread(() -> {
+            // Animate the launcher components at the same time as the window, always on UI thread.
+            if (mLauncherTransitionController != null && !mWasLauncherAlreadyVisible
+                    && start != end && duration > 0) {
+                // Adjust start progress and duration in case we are on a different thread.
+                long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
+                elapsedMillis = Utilities.boundToRange(elapsedMillis, 0, duration);
+                float elapsedProgress = (float) elapsedMillis / duration;
+                float adjustedStart = Utilities.mapRange(elapsedProgress, start, end);
+                long adjustedDuration = duration - elapsedMillis;
+                // We want to use the same interpolator as the window, but need to adjust it to
+                // interpolate over the remaining progress (end - start).
+                mLauncherTransitionController.dispatchSetInterpolator(Interpolators.mapToProgress(
+                        interpolator, adjustedStart, end));
+                mLauncherTransitionController.getAnimationPlayer().setDuration(adjustedDuration);
+                mLauncherTransitionController.getAnimationPlayer().start();
+            }
+        });
+    }
+
+    @UiThread
+    private void resumeLastTaskForQuickstep() {
+        setStateOnUiThread(STATE_RESUME_LAST_TASK);
+        doLogGesture(false /* toLauncher */);
+        reset();
     }
 
     @UiThread
@@ -625,23 +841,37 @@
     }
 
     private void invalidateHandler() {
-        mCurrentShift.cancelAnimation();
+        mCurrentShift.finishAnimation();
 
         if (mGestureEndCallback != null) {
-            mGestureEndCallback.accept(this);
+            mGestureEndCallback.run();
         }
 
-        clearReference();
-        mInputConsumer.unregisterInputConsumer();
+        mActivityInitListener.unregister();
+        mRecentsAnimationWrapper.unregisterInputConsumer();
+        mTaskSnapshot = null;
     }
 
     private void invalidateHandlerWithLauncher() {
         mLauncherTransitionController = null;
-        mLauncherLayoutListener.setHandler(null);
-        mLauncherLayoutListener.close(false);
+        mLayoutListener.finish();
+        mActivityControlHelper.getAlphaProperty(mActivity).setValue(1);
 
-        // Restore the requested orientation to the user preference after the gesture has ended
-        mLauncher.updateRequestedOrientation();
+        mRecentsView.setRunningTaskHidden(false);
+        mRecentsView.setRunningTaskIconScaledDown(false);
+        mQuickScrubController.cancelActiveQuickscrub();
+    }
+
+    private void notifyTransitionCancelled() {
+        mAnimationFactory.onTransitionCancelled();
+    }
+
+    private void resetStateForAnimationCancel() {
+        boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
+        mActivityControlHelper.onTransitionCancelled(mActivity, wasVisible);
+
+        // Leave the pending invisible flag, as it may be used by wallpaper open animation.
+        mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
     }
 
     public void layoutListenerClosed() {
@@ -651,44 +881,115 @@
     }
 
     private void switchToScreenshot() {
-        synchronized (mRecentsAnimationWrapper) {
-            if (mRecentsAnimationWrapper.controller != null) {
-                TransactionCompat transaction = new TransactionCompat();
-                for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
-                    if (app.mode == MODE_CLOSING) {
-                        // Update the screenshot of the task
-                        final ThumbnailData thumbnail =
-                                mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
-                        mRecentsView.updateThumbnail(app.taskId, thumbnail);
+        boolean finishTransitionPosted = false;
+        RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
+        if (controller != null) {
+            // Update the screenshot of the task
+            if (mTaskSnapshot == null) {
+                mTaskSnapshot = controller.screenshotTask(mRunningTaskId);
+            }
+            TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot);
+            mRecentsView.setRunningTaskHidden(false);
+            if (taskView != null) {
+                // Defer finishing the animation until the next launcher frame with the
+                // new thumbnail
+                finishTransitionPosted = new WindowCallbacksCompat(taskView) {
+
+                    // The number of frames to defer until we actually finish the animation
+                    private int mDeferFrameCount = 2;
+
+                    @Override
+                    public void onPostDraw(Canvas canvas) {
+                        if (mDeferFrameCount > 0) {
+                            mDeferFrameCount--;
+                            // Workaround, detach and reattach to invalidate the root node for
+                            // another draw
+                            detach();
+                            attach();
+                            taskView.invalidate();
+                            return;
+                        }
+
+                        setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+                        detach();
                     }
-                }
-                transaction.apply();
+                }.attach();
             }
         }
-        mRecentsAnimationWrapper.finish(true /* toHome */,
-                () -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE));
+        if (!finishTransitionPosted) {
+            // If we haven't posted a draw callback, set the state immediately.
+            setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+        }
+    }
+
+    private void finishCurrentTransitionToHome() {
+        synchronized (mRecentsAnimationWrapper) {
+            mRecentsAnimationWrapper.finish(true /* toHome */,
+                    () -> setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+        }
     }
 
     private void setupLauncherUiAfterSwipeUpAnimation() {
-        // Re apply state in case we did something funky during the transition.
-        mLauncher.getStateManager().reapplyState();
-
-        // Animate ui the first icon.
-        View currentRecentsPage = mRecentsView.getPageAt(mRecentsView.getCurrentPage());
-        if (currentRecentsPage instanceof TaskView) {
-            ((TaskView) currentRecentsPage).animateIconToScale(1f);
+        if (mLauncherTransitionController != null) {
+            mLauncherTransitionController.getAnimationPlayer().end();
+            mLauncherTransitionController = null;
         }
+        mActivityControlHelper.onSwipeUpComplete(mActivity);
+
+        // Animate the first icon.
+        mRecentsView.animateUpRunningTaskIconScale();
+        mRecentsView.setSwipeDownShouldLaunchApp(true);
+
+        RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+
+        doLogGesture(true /* toLauncher */);
+        reset();
+    }
+
+    private void onQuickScrubStart() {
+        if (!mQuickScrubController.prepareQuickScrub(TAG)) {
+            mQuickScrubBlocked = true;
+            setStateOnUiThread(STATE_RESUME_LAST_TASK | STATE_HANDLER_INVALIDATED);
+            return;
+        }
+        if (mLauncherTransitionController != null) {
+            mLauncherTransitionController.getAnimationPlayer().end();
+            mLauncherTransitionController = null;
+        }
+
+        mActivityControlHelper.onQuickInteractionStart(mActivity, mRunningTaskInfo, false);
+
+        // Inform the last progress in case we skipped before.
+        mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress);
+    }
+
+    private void onFinishedTransitionToQuickScrub() {
+        if (mQuickScrubBlocked) {
+            return;
+        }
+        mQuickScrubController.onFinishedTransitionToQuickScrub();
+
+        mRecentsView.animateUpRunningTaskIconScale();
+        RecentsModel.getInstance(mContext).onOverviewShown(false, TAG);
+    }
+
+    public void onQuickScrubProgress(float progress) {
+        mCurrentQuickScrubProgress = progress;
+        if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null
+                || mQuickScrubBlocked) {
+            return;
+        }
+        mQuickScrubController.onQuickScrubProgress(progress);
     }
 
     public void onQuickScrubEnd() {
         setStateOnUiThread(STATE_QUICK_SCRUB_END);
     }
 
-    private void switchToFinalAppAfterQuickSwitch() {
-        mQuickScrubController.onQuickSwitch();
-    }
-
     private void switchToFinalAppAfterQuickScrub() {
+        if (mQuickScrubBlocked) {
+            return;
+        }
         mQuickScrubController.onQuickScrubEnd();
 
         // Normally this is handled in reset(), but since we are still scrubbing after the
@@ -697,16 +998,6 @@
         setStateOnUiThread(STATE_HANDLER_INVALIDATED);
     }
 
-    public void onQuickScrubProgress(float progress) {
-        if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null) {
-            // TODO: We can still get progress events while launcher is not ready on the worker
-            // thread. Keep track of last received progress and apply that progress when launcher
-            // is ready
-            return;
-        }
-        mQuickScrubController.onQuickScrubProgress(progress);
-    }
-
     private void debugNewState(int stateFlag) {
         if (!DEBUG_STATES) {
             return;
@@ -726,4 +1017,101 @@
         Log.d(TAG, "[" + System.identityHashCode(this) + "] Adding " + stateFlagStr + " to "
                 + currentStateStr);
     }
+
+    public void setGestureEndCallback(Runnable gestureEndCallback) {
+        mGestureEndCallback = gestureEndCallback;
+    }
+
+    // Handling long swipe
+    private void onLongSwipeEnabledUi() {
+        mUiLongSwipeMode = true;
+        checkLongSwipeCanEnter();
+        checkLongSwipeCanStart();
+    }
+
+    private void onLongSwipeDisabledUi() {
+        mUiLongSwipeMode = false;
+
+        if (mLongSwipeController != null) {
+            mLongSwipeController.destroy();
+            setTargetAlphaProvider((t, a1) -> a1);
+
+            // Rebuild animations
+            buildAnimationController();
+        }
+    }
+
+    private void onLongSwipeDisplacementUpdated() {
+        if (!mUiLongSwipeMode || mLongSwipeController == null) {
+            return;
+        }
+
+        mLongSwipeController.onMove(mLongSwipeDisplacement);
+    }
+
+    private void checkLongSwipeCanEnter() {
+        if (!mUiLongSwipeMode || !mStateCallback.hasStates(LONG_SWIPE_ENTER_STATE)
+                || !mActivityControlHelper.supportsLongSwipe(mActivity)) {
+            return;
+        }
+
+        // We are entering long swipe mode, make sure the screen shot is captured.
+        mStateCallback.setState(STATE_CAPTURE_SCREENSHOT);
+
+    }
+
+    private void checkLongSwipeCanStart() {
+        if (!mUiLongSwipeMode || !mStateCallback.hasStates(LONG_SWIPE_START_STATE)
+                || !mActivityControlHelper.supportsLongSwipe(mActivity)) {
+            return;
+        }
+
+        RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
+        if (targetSet == null) {
+            // This can happen when cancelAnimation comes on the background thread, while we are
+            // processing the long swipe on the UI thread.
+            return;
+        }
+
+        mLongSwipeController = mActivityControlHelper.getLongSwipeController(
+                mActivity, mRunningTaskId);
+        onLongSwipeDisplacementUpdated();
+        setTargetAlphaProvider(WindowTransformSwipeHandler::getHiddenTargetAlpha);
+    }
+
+    private void onLongSwipeGestureFinishUi(float velocity, boolean isFling) {
+        if (!mUiLongSwipeMode || mLongSwipeController == null) {
+            mUiLongSwipeMode = false;
+            handleNormalGestureEnd(velocity, isFling);
+            return;
+        }
+        mUiLongSwipeMode = false;
+        finishCurrentTransitionToHome();
+        mLongSwipeController.end(velocity, isFling,
+                () -> setStateOnUiThread(STATE_HANDLER_INVALIDATED));
+
+    }
+
+    private void setTargetAlphaProvider(
+            BiFunction<RemoteAnimationTargetCompat, Float, Float> provider) {
+        mClipAnimationHelper.setTaskAlphaCallback(provider);
+        updateFinalShift();
+    }
+
+    public void onAssistDataReceived(Bundle assistData) {
+        mAssistData = assistData;
+        setStateOnUiThread(STATE_ASSIST_DATA_RECEIVED);
+    }
+
+    private void preloadAssistData() {
+        RecentsModel.getInstance(mContext).preloadAssistData(mRunningTaskId, mAssistData);
+    }
+
+    public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
+        if (!(app.isNotInRecents
+                || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) {
+            return 0;
+        }
+        return expectedAlpha;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
new file mode 100644
index 0000000..261f45d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.util.LayoutUtils;
+import com.android.quickstep.views.RecentsView;
+
+public class FallbackRecentsView extends RecentsView<RecentsActivity> {
+
+    public FallbackRecentsView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setOverviewStateEnabled(true);
+        getQuickScrubController().onFinishedTransitionToQuickScrub();
+    }
+
+    @Override
+    protected void startHome() {
+        mActivity.startHome();
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        super.onViewAdded(child);
+        updateEmptyMessage();
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+        updateEmptyMessage();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        maybeDrawEmptyMessage(canvas);
+        super.draw(canvas);
+    }
+
+    @Override
+    protected void getTaskSize(DeviceProfile dp, Rect outRect) {
+        LayoutUtils.calculateFallbackTaskSize(getContext(), dp, outRect);
+    }
+
+    @Override
+    public boolean shouldUseMultiWindowTaskSizeStrategy() {
+        // Just use the activity task size for multi-window as well.
+        return false;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java
new file mode 100644
index 0000000..ca8c252
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.RecentsActivity;
+
+public class RecentsRootView extends BaseDragLayer<RecentsActivity> {
+
+    private final RecentsActivity mActivity;
+
+    private final Point mLastKnownSize = new Point(10, 10);
+
+    public RecentsRootView(Context context, AttributeSet attrs) {
+        super(context, attrs, 1 /* alphaChannelCount */);
+        mActivity = (RecentsActivity) BaseActivity.fromContext(context);
+        setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | SYSTEM_UI_FLAG_LAYOUT_STABLE);
+    }
+
+    public Point getLastKnownSize() {
+        return mLastKnownSize;
+    }
+
+    public void setup() {
+        mControllers = new TouchController[] { new RecentsTaskController(mActivity) };
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Check size changes before the actual measure, to avoid multiple measure calls.
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height = MeasureSpec.getSize(heightMeasureSpec);
+        if (mLastKnownSize.x != width || mLastKnownSize.y != height) {
+            mLastKnownSize.set(width, height);
+            mActivity.onRootViewSizeChanged();
+        }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @TargetApi(23)
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        // Update device profile before notifying the children.
+        mActivity.getDeviceProfile().updateInsets(insets);
+        setInsets(insets);
+        return true; // I'll take it from here
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
+        // modifying child layout params.
+        if (!insets.equals(mInsets)) {
+            super.setInsets(insets);
+        }
+        setBackground(insets.top == 0 ? null
+                : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
+    }
+
+    public void dispatchInsets() {
+        mActivity.getDeviceProfile().updateInsets(mInsets);
+        super.setInsets(mInsets);
+    }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
new file mode 100644
index 0000000..9463cc9
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import com.android.launcher3.uioverrides.TaskViewTouchController;
+import com.android.quickstep.RecentsActivity;
+
+public class RecentsTaskController extends TaskViewTouchController<RecentsActivity> {
+
+    public RecentsTaskController(RecentsActivity activity) {
+        super(activity);
+    }
+
+    @Override
+    protected boolean isRecentsInteractive() {
+        return mActivity.hasWindowFocus();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
new file mode 100644
index 0000000..6dff187
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/logging/UserEventDispatcherExtension.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.logging;
+
+import android.content.Context;
+import android.util.Log;
+
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CANCEL_TARGET;
+import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
+import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
+
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.systemui.shared.system.MetricsLoggerCompat;
+
+/**
+ * This class handles AOSP MetricsLogger function calls and logging around
+ * quickstep interactions.
+ */
+@SuppressWarnings("unused")
+public class UserEventDispatcherExtension extends UserEventDispatcher {
+
+    private static final String TAG = "UserEventDispatcher";
+
+    public UserEventDispatcherExtension(Context context) { }
+
+    public void logStateChangeAction(int action, int dir, int srcChildTargetType,
+                                     int srcParentContainerType, int dstContainerType,
+                                     int pageIndex) {
+        new MetricsLoggerCompat().visibility(MetricsLoggerCompat.OVERVIEW_ACTIVITY,
+                dstContainerType == LauncherLogProto.ContainerType.TASKSWITCHER);
+        super.logStateChangeAction(action, dir, srcChildTargetType, srcParentContainerType,
+                dstContainerType, pageIndex);
+    }
+
+    public void logActionTip(int actionType, int viewType) {
+        LauncherLogProto.Action action = new LauncherLogProto.Action();
+        LauncherLogProto.Target target = new LauncherLogProto.Target();
+        switch(actionType) {
+            case VISIBLE:
+                action.type = LauncherLogProto.Action.Type.TIP;
+                target.type = LauncherLogProto.Target.Type.CONTAINER;
+                target.containerType = LauncherLogProto.ContainerType.TIP;
+                break;
+            case DISMISS:
+                action.type = LauncherLogProto.Action.Type.TOUCH;
+                action.touch = LauncherLogProto.Action.Touch.TAP;
+                target.type = LauncherLogProto.Target.Type.CONTROL;
+                target.controlType = CANCEL_TARGET;
+                break;
+            default:
+                Log.e(TAG, "Unexpected action type = " + actionType);
+        }
+
+        switch(viewType) {
+            case RECENTS_QUICK_SCRUB_ONBOARDING_TIP:
+                target.tipType = LauncherLogProto.TipType.QUICK_SCRUB_TEXT;
+                break;
+            case RECENTS_SWIPE_UP_ONBOARDING_TIP:
+                target.tipType = LauncherLogProto.TipType.SWIPE_UP_TEXT;
+                break;
+            default:
+                Log.e(TAG, "Unexpected viewType = " + viewType);
+        }
+        LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
+        dispatchUserEvent(event, null);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
new file mode 100644
index 0000000..df70a8a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.QuickScrubController.QUICK_SCRUB_TRANSLATION_Y_FACTOR;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
+
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.RemoteException;
+import android.support.annotation.Nullable;
+import android.view.Surface;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.utilities.RectFEvaluator;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import com.android.systemui.shared.system.TransactionCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+
+/**
+ * Utility class to handle window clip animation
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class ClipAnimationHelper {
+
+    // The bounds of the source app in device coordinates
+    private final Rect mSourceStackBounds = new Rect();
+    // The insets of the source app
+    private final Rect mSourceInsets = new Rect();
+    // The source app bounds with the source insets applied, in the source app window coordinates
+    private final RectF mSourceRect = new RectF();
+    // The bounds of the task view in launcher window coordinates
+    private final RectF mTargetRect = new RectF();
+    // Set when the final window destination is changed, such as offsetting for quick scrub
+    private final PointF mTargetOffset = new PointF();
+    // The insets to be used for clipping the app window, which can be larger than mSourceInsets
+    // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
+    // app window coordinates.
+    private final RectF mSourceWindowClipInsets = new RectF();
+
+    // The bounds of launcher (not including insets) in device coordinates
+    public final Rect mHomeStackBounds = new Rect();
+
+    // The clip rect in source app window coordinates
+    private final Rect mClipRect = new Rect();
+    private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
+    private final Matrix mTmpMatrix = new Matrix();
+    private final RectF mTmpRectF = new RectF();
+
+    private float mTargetScale = 1f;
+    private float mOffsetScale = 1f;
+    private Interpolator mInterpolator = LINEAR;
+    // We translate y slightly faster than the rest of the animation for quick scrub.
+    private Interpolator mOffsetYInterpolator = LINEAR;
+
+    // Whether to boost the opening animation target layers, or the closing
+    private int mBoostModeTargetLayers = -1;
+    // Wether or not applyTransform has been called yet since prepareAnimation()
+    private boolean mIsFirstFrame = true;
+
+    private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
+            (t, a1) -> a1;
+
+    private void updateSourceStack(RemoteAnimationTargetCompat target) {
+        mSourceInsets.set(target.contentInsets);
+        mSourceStackBounds.set(target.sourceContainerBounds);
+
+        // TODO: Should sourceContainerBounds already have this offset?
+        mSourceStackBounds.offsetTo(target.position.x, target.position.y);
+
+    }
+
+    public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
+        mHomeStackBounds.set(homeStackBounds);
+        updateSourceStack(target);
+    }
+
+    public void updateTargetRect(TransformedRect targetRect) {
+        mOffsetScale = targetRect.scale;
+        mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
+                mSourceStackBounds.width() - mSourceInsets.right,
+                mSourceStackBounds.height() - mSourceInsets.bottom);
+        mTargetRect.set(targetRect.rect);
+        Utilities.scaleRectFAboutCenter(mTargetRect, targetRect.scale);
+        mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
+                mHomeStackBounds.top - mSourceStackBounds.top);
+
+        // Calculate the clip based on the target rect (since the content insets and the
+        // launcher insets may differ, so the aspect ratio of the target rect can differ
+        // from the source rect. The difference between the target rect (scaled to the
+        // source rect) is the amount to clip on each edge.
+        RectF scaledTargetRect = new RectF(mTargetRect);
+        Utilities.scaleRectFAboutCenter(scaledTargetRect,
+                mSourceRect.width() / mTargetRect.width());
+        scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
+        mSourceWindowClipInsets.set(
+                Math.max(scaledTargetRect.left, 0),
+                Math.max(scaledTargetRect.top, 0),
+                Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
+                Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
+        mSourceRect.set(scaledTargetRect);
+    }
+
+    public void prepareAnimation(boolean isOpening) {
+        mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
+    }
+
+    public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress,
+            @Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier) {
+        RectF currentRect;
+        mTmpRectF.set(mTargetRect);
+        Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
+        float offsetYProgress = mOffsetYInterpolator.getInterpolation(progress);
+        progress = mInterpolator.getInterpolation(progress);
+        currentRect =  mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
+
+        synchronized (mTargetOffset) {
+            // Stay lined up with the center of the target, since it moves for quick scrub.
+            currentRect.offset(mTargetOffset.x * mOffsetScale * progress,
+                    mTargetOffset.y  * offsetYProgress);
+        }
+
+        mClipRect.left = (int) (mSourceWindowClipInsets.left * progress);
+        mClipRect.top = (int) (mSourceWindowClipInsets.top * progress);
+        mClipRect.right = (int)
+                (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress));
+        mClipRect.bottom = (int)
+                (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
+
+        SurfaceParams[] params = new SurfaceParams[targetSet.unfilteredApps.length];
+        for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
+            RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
+            mTmpMatrix.setTranslate(app.position.x, app.position.y);
+            Rect crop = app.sourceContainerBounds;
+            float alpha = 1f;
+            if (app.mode == targetSet.targetMode) {
+                if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+                    mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
+                    mTmpMatrix.postTranslate(app.position.x, app.position.y);
+                    crop = mClipRect;
+                }
+
+                if (app.isNotInRecents
+                        || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+                    alpha = 1 - progress;
+                }
+
+                alpha = mTaskAlphaCallback.apply(app, alpha);
+            }
+
+            params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop,
+                    RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
+        }
+        applyParams(syncTransactionApplier, params);
+        return currentRect;
+    }
+
+    private void applyParams(@Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier,
+            SurfaceParams[] params) {
+        if (syncTransactionApplier != null) {
+            syncTransactionApplier.scheduleApply(params);
+        } else {
+            TransactionCompat t = new TransactionCompat();
+            for (SurfaceParams param : params) {
+                SyncRtSurfaceTransactionApplier.applyParams(t, param);
+            }
+            t.setEarlyWakeup();
+            t.apply();
+        }
+    }
+
+    public void setTaskAlphaCallback(
+            BiFunction<RemoteAnimationTargetCompat, Float, Float> callback) {
+        mTaskAlphaCallback = callback;
+    }
+
+    public void offsetTarget(float scale, float offsetX, float offsetY, Interpolator interpolator) {
+        synchronized (mTargetOffset) {
+            mTargetOffset.set(offsetX, offsetY);
+        }
+        mTargetScale = scale;
+        mInterpolator = interpolator;
+        mOffsetYInterpolator = Interpolators.clampToProgress(mInterpolator, 0,
+                QUICK_SCRUB_TRANSLATION_Y_FACTOR);
+    }
+
+    public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
+        fromTaskThumbnailView(ttv, rv, null);
+    }
+
+    public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
+            @Nullable RemoteAnimationTargetCompat target) {
+        BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
+        BaseDragLayer dl = activity.getDragLayer();
+
+        int[] pos = new int[2];
+        dl.getLocationOnScreen(pos);
+        mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight());
+        mHomeStackBounds.offset(pos[0], pos[1]);
+
+        if (target != null) {
+            updateSourceStack(target);
+        } else  if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
+            updateStackBoundsToMultiWindowTaskSize(activity);
+        } else {
+            mSourceStackBounds.set(mHomeStackBounds);
+            mSourceInsets.set(activity.getDeviceProfile().getInsets());
+        }
+
+        TransformedRect targetRect = new TransformedRect();
+        dl.getDescendantRectRelativeToSelf(ttv, targetRect.rect);
+        updateTargetRect(targetRect);
+
+        if (target == null) {
+            // Transform the clip relative to the target rect. Only do this in the case where we
+            // aren't applying the insets to the app windows (where the clip should be in target app
+            // space)
+            float scale = mTargetRect.width() / mSourceRect.width();
+            mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale;
+            mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale;
+            mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale;
+            mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale;
+        }
+    }
+
+    private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
+        ISystemUiProxy sysUiProxy = RecentsModel.getInstance(activity).getSystemUiProxy();
+        if (sysUiProxy != null) {
+            try {
+                mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds());
+                return;
+            } catch (RemoteException e) {
+                // Use half screen size
+            }
+        }
+
+        // Assume that the task size is half screen size (minus the insets and the divider size)
+        DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
+        // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+        // account for system insets
+        int taskWidth = fullDp.availableWidthPx;
+        int taskHeight = fullDp.availableHeightPx;
+        int halfDividerSize = activity.getResources()
+                .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
+
+        Rect insets = new Rect();
+        WindowManagerWrapper.getInstance().getStableInsets(insets);
+        if (fullDp.isLandscape) {
+            taskWidth = taskWidth / 2 - halfDividerSize;
+        } else {
+            taskHeight = taskHeight / 2 - halfDividerSize;
+        }
+
+        // Align the task to bottom left/right edge (closer to nav bar).
+        int left = activity.getDeviceProfile().isSeascape() ? insets.left
+                : (insets.left + fullDp.availableWidthPx - taskWidth);
+        mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
+        mSourceStackBounds.offset(left, insets.top + fullDp.availableHeightPx - taskHeight);
+    }
+
+    public void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
+        RectF currentRect =  mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
+        canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
+                mSourceStackBounds.top - mHomeStackBounds.top);
+        mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL);
+
+        canvas.concat(mTmpMatrix);
+        canvas.translate(mTargetRect.left, mTargetRect.top);
+
+        float insetProgress = (1 - progress);
+        ttv.drawOnCanvas(canvas,
+                -mSourceWindowClipInsets.left * insetProgress,
+                -mSourceWindowClipInsets.top * insetProgress,
+                ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
+                ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
+                ttv.getCornerRadius() * progress);
+    }
+
+    public RectF getTargetRect() {
+        return mTargetRect;
+    }
+
+    public RectF getSourceRect() {
+        return mSourceRect;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
new file mode 100644
index 0000000..ec9c7ea
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.support.annotation.AnyThread;
+import android.support.annotation.IntDef;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+
+import java.lang.annotation.Retention;
+
+public class LayoutUtils {
+
+    private static final int MULTI_WINDOW_STRATEGY_HALF_SCREEN = 1;
+    private static final int MULTI_WINDOW_STRATEGY_DEVICE_PROFILE = 2;
+
+    @Retention(SOURCE)
+    @IntDef({MULTI_WINDOW_STRATEGY_HALF_SCREEN, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE})
+    private @interface MultiWindowStrategy {}
+
+    public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+        float extraSpace;
+        if (dp.isVerticalBarLayout()) {
+            extraSpace = 0;
+        } else {
+            extraSpace = dp.hotseatBarSizePx + dp.verticalDragHandleSizePx;
+        }
+        calculateTaskSize(context, dp, extraSpace, MULTI_WINDOW_STRATEGY_HALF_SCREEN, outRect);
+    }
+
+    public static void calculateFallbackTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+        calculateTaskSize(context, dp, 0, MULTI_WINDOW_STRATEGY_DEVICE_PROFILE, outRect);
+    }
+
+    @AnyThread
+    public static void calculateTaskSize(Context context, DeviceProfile dp,
+            float extraVerticalSpace, @MultiWindowStrategy int multiWindowStrategy, Rect outRect) {
+        float taskWidth, taskHeight, paddingHorz;
+        Resources res = context.getResources();
+        Rect insets = dp.getInsets();
+
+        if (dp.isMultiWindowMode) {
+            if (multiWindowStrategy == MULTI_WINDOW_STRATEGY_HALF_SCREEN) {
+                DeviceProfile fullDp = dp.getFullScreenProfile();
+                // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+                // account for system insets
+                taskWidth = fullDp.availableWidthPx;
+                taskHeight = fullDp.availableHeightPx;
+                float halfDividerSize = res.getDimension(R.dimen.multi_window_task_divider_size)
+                        / 2;
+
+                if (fullDp.isLandscape) {
+                    taskWidth = taskWidth / 2 - halfDividerSize;
+                } else {
+                    taskHeight = taskHeight / 2 - halfDividerSize;
+                }
+            } else {
+                // multiWindowStrategy == MULTI_WINDOW_STRATEGY_DEVICE_PROFILE
+                taskWidth = dp.widthPx;
+                taskHeight = dp.heightPx;
+            }
+            paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space);
+        } else {
+            taskWidth = dp.availableWidthPx;
+            taskHeight = dp.availableHeightPx;
+            paddingHorz = res.getDimension(dp.isVerticalBarLayout()
+                    ? R.dimen.landscape_task_card_horz_space
+                    : R.dimen.portrait_task_card_horz_space);
+        }
+
+        float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
+        float paddingVert = res.getDimension(R.dimen.task_card_vert_space);
+
+        // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
+        // we override the insets ourselves.
+        int launcherVisibleWidth = dp.widthPx - insets.left - insets.right;
+        int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom;
+
+        float availableHeight = launcherVisibleHeight
+                - topIconMargin - extraVerticalSpace - paddingVert;
+        float availableWidth = launcherVisibleWidth - paddingHorz;
+
+        float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
+        float outWidth = scale * taskWidth;
+        float outHeight = scale * taskHeight;
+
+        // Center in the visible space
+        float x = insets.left + (launcherVisibleWidth - outWidth) / 2;
+        float y = insets.top + Math.max(topIconMargin,
+                (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
+        outRect.set(Math.round(x), Math.round(y),
+                Math.round(x + outWidth), Math.round(y + outHeight));
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
new file mode 100644
index 0000000..e798d5c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.ValueAnimator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class to update multiple values with different interpolators and durations during
+ * the same animation.
+ */
+public abstract class MultiValueUpdateListener implements ValueAnimator.AnimatorUpdateListener {
+
+    private final ArrayList<FloatProp> mAllProperties = new ArrayList<>();
+
+    @Override
+    public final void onAnimationUpdate(ValueAnimator animator) {
+        final float percent = animator.getAnimatedFraction();
+        final float currentPlayTime = percent * animator.getDuration();
+
+        for (int i = mAllProperties.size() - 1; i >= 0; i--) {
+            FloatProp prop = mAllProperties.get(i);
+            float time = Math.max(0, currentPlayTime - prop.mDelay);
+            float newPercent = Math.min(1f, time / prop.mDuration);
+            newPercent = prop.mInterpolator.getInterpolation(newPercent);
+            prop.value = prop.mEnd * newPercent + prop.mStart * (1 - newPercent);
+        }
+        onUpdate(percent);
+    }
+
+    public abstract void onUpdate(float percent);
+
+    public final class FloatProp {
+
+        public float value;
+
+        private final float mStart;
+        private final float mEnd;
+        private final float mDelay;
+        private final float mDuration;
+        private final Interpolator mInterpolator;
+
+        public FloatProp(float start, float end, float delay, float duration, Interpolator i) {
+            value = mStart = start;
+            mEnd = end;
+            mDelay = delay;
+            mDuration = duration;
+            mInterpolator = i;
+
+            mAllProperties.add(this);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
new file mode 100644
index 0000000..a7e6d74
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.AnimatorSet;
+import android.app.ActivityOptions;
+import android.os.Handler;
+
+import com.android.launcher3.LauncherAnimationRunner;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+
+@FunctionalInterface
+public interface RemoteAnimationProvider {
+
+    static final int Z_BOOST_BASE = 800570000;
+
+    AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targets);
+
+    default ActivityOptions toActivityOptions(Handler handler, long duration) {
+        LauncherAnimationRunner runner = new LauncherAnimationRunner(handler,
+                false /* startAtFrontOfQueue */) {
+
+            @Override
+            public void onCreateAnimation(RemoteAnimationTargetCompat[] targetCompats,
+                    AnimationResult result) {
+                result.setAnimation(createWindowAnimation(targetCompats));
+            }
+        };
+        return ActivityOptionsCompat.makeRemoteAnimation(
+                new RemoteAnimationAdapterCompat(runner, duration, 0));
+    }
+
+    /**
+     * Prepares the given {@param targets} for a remote animation, and should be called with the
+     * transaction from the first frame of animation.
+     *
+     * @param boostModeTargets The mode indicating which targets to boost in z-order above other
+     *                         targets.
+     */
+    static void prepareTargetsForFirstFrame(RemoteAnimationTargetCompat[] targets,
+            TransactionCompat t, int boostModeTargets) {
+        for (RemoteAnimationTargetCompat target : targets) {
+            t.setLayer(target.leash, getLayer(target, boostModeTargets));
+            t.show(target.leash);
+        }
+    }
+
+    static int getLayer(RemoteAnimationTargetCompat target, int boostModeTarget) {
+        return target.mode == boostModeTarget
+                ? Z_BOOST_BASE + target.prefixOrderIndex
+                : target.prefixOrderIndex;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
new file mode 100644
index 0000000..c372485
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.util.ArrayList;
+
+/**
+ * Holds a collection of RemoteAnimationTargets, filtered by different properties.
+ */
+public class RemoteAnimationTargetSet {
+
+    public final RemoteAnimationTargetCompat[] unfilteredApps;
+    public final RemoteAnimationTargetCompat[] apps;
+    public final int targetMode;
+
+    public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) {
+        ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
+        if (apps != null) {
+            for (RemoteAnimationTargetCompat target : apps) {
+                if (target.mode == targetMode) {
+                    filteredApps.add(target);
+                }
+            }
+        }
+
+        this.unfilteredApps = apps;
+        this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]);
+        this.targetMode = targetMode;
+    }
+
+    public RemoteAnimationTargetCompat findTask(int taskId) {
+        for (RemoteAnimationTargetCompat target : apps) {
+            if (target.taskId == taskId) {
+                return target;
+            }
+        }
+        return null;
+    }
+
+    public boolean isAnimatingHome() {
+        for (RemoteAnimationTargetCompat target : apps) {
+            if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
new file mode 100644
index 0000000..40dd74b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.quickstep.util.RemoteAnimationProvider.prepareTargetsForFirstFrame;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+
+/**
+ * Animation listener which fades out the closing targets
+ */
+public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener {
+
+    private final RemoteAnimationTargetSet mTarget;
+    private boolean mFirstFrame = true;
+
+    public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] targets) {
+        mTarget = new RemoteAnimationTargetSet(targets, MODE_CLOSING);
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator valueAnimator) {
+        TransactionCompat t = new TransactionCompat();
+        if (mFirstFrame) {
+            prepareTargetsForFirstFrame(mTarget.unfilteredApps, t, MODE_CLOSING);
+            mFirstFrame = false;
+        }
+
+        float alpha = 1 - valueAnimator.getAnimatedFraction();
+        for (RemoteAnimationTargetCompat app : mTarget.apps) {
+            t.setAlpha(app.leash, alpha);
+        }
+        t.apply();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
new file mode 100644
index 0000000..48b07a7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TaskViewDrawable.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
+import android.view.View;
+
+import com.android.launcher3.Utilities;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.quickstep.views.TaskView;
+
+public class TaskViewDrawable extends Drawable {
+
+    public static final FloatProperty<TaskViewDrawable> PROGRESS =
+            new FloatProperty<TaskViewDrawable>("progress") {
+                @Override
+                public void setValue(TaskViewDrawable taskViewDrawable, float v) {
+                    taskViewDrawable.setProgress(v);
+                }
+
+                @Override
+                public Float get(TaskViewDrawable taskViewDrawable) {
+                    return taskViewDrawable.mProgress;
+                }
+            };
+
+    /**
+     * The progress at which we play the atomic icon scale animation.
+     */
+    private static final float ICON_SCALE_THRESHOLD = 0.95f;
+
+    private final RecentsView mParent;
+    private final View mIconView;
+    private final int[] mIconPos;
+
+    private final TaskThumbnailView mThumbnailView;
+
+    private final ClipAnimationHelper mClipAnimationHelper;
+
+    private float mProgress = 1;
+    private boolean mPassedIconScaleThreshold;
+    private ValueAnimator mIconScaleAnimator;
+    private float mIconScale;
+
+    public TaskViewDrawable(TaskView tv, RecentsView parent) {
+        mParent = parent;
+        mIconView = tv.getIconView();
+        mIconPos = new int[2];
+        mIconScale = mIconView.getScaleX();
+        Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
+
+        mThumbnailView = tv.getThumbnail();
+        mClipAnimationHelper = new ClipAnimationHelper();
+        mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
+    }
+
+    public void setProgress(float progress) {
+        mProgress = progress;
+        mParent.invalidate();
+        boolean passedIconScaleThreshold = progress <= ICON_SCALE_THRESHOLD;
+        if (mPassedIconScaleThreshold != passedIconScaleThreshold) {
+            mPassedIconScaleThreshold = passedIconScaleThreshold;
+            animateIconScale(mPassedIconScaleThreshold ? 0 : 1);
+        }
+    }
+
+    private void animateIconScale(float toScale) {
+        if (mIconScaleAnimator != null) {
+            mIconScaleAnimator.cancel();
+        }
+        mIconScaleAnimator = ValueAnimator.ofFloat(mIconScale, toScale);
+        mIconScaleAnimator.addUpdateListener(valueAnimator -> {
+            mIconScale = (float) valueAnimator.getAnimatedValue();
+            if (mProgress > ICON_SCALE_THRESHOLD) {
+                // Speed up the icon scale to ensure it is 1 when progress is 1.
+                float iconProgress = (mProgress - ICON_SCALE_THRESHOLD) / (1 - ICON_SCALE_THRESHOLD);
+                if (iconProgress > mIconScale) {
+                    mIconScale = iconProgress;
+                }
+            }
+            invalidateSelf();
+        });
+        mIconScaleAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mIconScaleAnimator = null;
+            }
+        });
+        mIconScaleAnimator.setDuration(TaskView.SCALE_ICON_DURATION);
+        mIconScaleAnimator.start();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.save();
+        canvas.translate(mParent.getScrollX(), mParent.getScrollY());
+        mClipAnimationHelper.drawForProgress(mThumbnailView, canvas, mProgress);
+        canvas.restore();
+
+        canvas.save();
+        canvas.translate(mIconPos[0], mIconPos[1]);
+        canvas.scale(mIconScale, mIconScale, mIconView.getWidth() / 2, mIconView.getHeight() / 2);
+        mIconView.draw(canvas);
+        canvas.restore();
+    }
+
+    public ClipAnimationHelper getClipAnimationHelper() {
+        return mClipAnimationHelper;
+    }
+
+    @Override
+    public void setAlpha(int i) { }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) { }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/TransformedRect.java b/quickstep/src/com/android/quickstep/util/TransformedRect.java
new file mode 100644
index 0000000..79f11e4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TransformedRect.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.graphics.Rect;
+
+/**
+ * A wrapper around {@link Rect} with additional transformation properties
+ */
+public class TransformedRect {
+
+    public final Rect rect = new Rect();
+    public float scale = 1;
+
+    public void set(TransformedRect transformedRect) {
+        rect.set(transformedRect.rect);
+        scale = transformedRect.scale;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
new file mode 100644
index 0000000..fbecd84
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+import com.android.launcher3.Utilities;
+import com.android.quickstep.views.RecentsView.PageCallbacks;
+import com.android.quickstep.views.RecentsView.ScrollState;
+
+public class ClearAllButton extends Button implements PageCallbacks {
+
+    private float mScrollAlpha = 1;
+    private float mContentAlpha = 1;
+
+    private final boolean mIsRtl;
+
+    private int mScrollOffset;
+
+    public ClearAllButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mIsRtl = Utilities.isRtl(context.getResources());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        RecentsView parent = (RecentsView) getParent();
+        mScrollOffset = mIsRtl ? parent.getPaddingRight() / 2 : - parent.getPaddingLeft() / 2;
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    public void setContentAlpha(float alpha) {
+        if (mContentAlpha != alpha) {
+            mContentAlpha = alpha;
+            updateAlpha();
+        }
+    }
+
+    @Override
+    public void onPageScroll(ScrollState scrollState) {
+        float width = getWidth();
+        if (width == 0) {
+            return;
+        }
+
+        float shift = Math.min(scrollState.scrollFromEdge, width);
+        setTranslationX(mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift));
+        mScrollAlpha = 1 - shift / width;
+        updateAlpha();
+    }
+
+    private void updateAlpha() {
+        final float alpha = mScrollAlpha * mContentAlpha;
+        setAlpha(alpha);
+        setClickable(alpha == 1);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
new file mode 100644
index 0000000..8659949
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.launcher3.FastBitmapDrawable;
+import java.util.ArrayList;
+
+/**
+ * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
+ * when the drawable changes.
+ */
+public class IconView extends View {
+
+    public interface OnScaleUpdateListener {
+        public void onScaleUpdate(float scale);
+    }
+
+    private Drawable mDrawable;
+
+    private ArrayList<OnScaleUpdateListener> mScaleListeners;
+
+    public IconView(Context context) {
+        super(context);
+    }
+
+    public IconView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public IconView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public void setDrawable(Drawable d) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+        }
+        mDrawable = d;
+        if (mDrawable != null) {
+            mDrawable.setCallback(this);
+            mDrawable.setBounds(0, 0, getWidth(), getHeight());
+        }
+        invalidate();
+    }
+
+    public Drawable getDrawable() {
+        return mDrawable;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        if (mDrawable != null) {
+            mDrawable.setBounds(0, 0, w, h);
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mDrawable;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+
+        final Drawable drawable = mDrawable;
+        if (drawable != null && drawable.isStateful()
+                && drawable.setState(getDrawableState())) {
+            invalidateDrawable(drawable);
+        }
+    }
+
+    @Override
+    public void invalidateDrawable(@NonNull Drawable drawable) {
+        super.invalidateDrawable(drawable);
+        if (drawable instanceof FastBitmapDrawable && mScaleListeners != null) {
+            for (OnScaleUpdateListener listener : mScaleListeners) {
+                listener.onScaleUpdate(((FastBitmapDrawable) drawable).getScale());
+            }
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mDrawable != null) {
+            mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    public void addUpdateScaleListener(OnScaleUpdateListener listener) {
+        if (mScaleListeners == null) {
+            mScaleListeners = new ArrayList<>();
+        }
+        mScaleListeners.add(listener);
+        if (mDrawable instanceof FastBitmapDrawable) {
+            listener.onScaleUpdate(((FastBitmapDrawable) mDrawable).getScale());
+        }
+    }
+
+    public void removeUpdateScaleListener(OnScaleUpdateListener listener) {
+        if (mScaleListeners != null) {
+            mScaleListeners.remove(listener);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
similarity index 79%
rename from quickstep/src/com/android/quickstep/LauncherLayoutListener.java
rename to quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index fbdbe7a..61740d7 100644
--- a/quickstep/src/com/android/quickstep/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.quickstep;
+package com.android.quickstep.views;
+
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
 
 import android.graphics.Rect;
 import android.view.MotionEvent;
@@ -21,11 +24,14 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
+import com.android.quickstep.ActivityControlHelper.LayoutListener;
+import com.android.quickstep.WindowTransformSwipeHandler;
 
 /**
  * Floating view which shows the task snapshot allowing it to be dragged and placed.
  */
-public class LauncherLayoutListener extends AbstractFloatingView implements Insettable {
+public class LauncherLayoutListener extends AbstractFloatingView
+        implements Insettable, LayoutListener {
 
     private final Launcher mLauncher;
     private WindowTransformSwipeHandler mHandler;
@@ -36,6 +42,7 @@
         setVisibility(INVISIBLE);
     }
 
+    @Override
     public void setHandler(WindowTransformSwipeHandler handler) {
         mHandler = handler;
     }
@@ -43,7 +50,7 @@
     @Override
     public void setInsets(Rect insets) {
         if (mHandler != null) {
-            mHandler.onLauncherLayoutChanged();
+            mHandler.buildAnimationController();
         }
     }
 
@@ -65,6 +72,7 @@
         }
     }
 
+    @Override
     public void open() {
         if (!mIsOpen) {
             mLauncher.getDragLayer().addView(this);
@@ -86,4 +94,11 @@
     protected boolean isOfType(int type) {
         return (type & TYPE_QUICKSTEP_PREVIEW) != 0;
     }
+
+    @Override
+    public void finish() {
+        setHandler(null);
+        close(false);
+        mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
new file mode 100644
index 0000000..7c5828b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.view.View;
+import android.view.ViewDebug;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.views.ScrimView;
+import com.android.quickstep.OverviewInteractionState;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.LayoutUtils;
+
+/**
+ * {@link RecentsView} used in Launcher activity
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class LauncherRecentsView extends RecentsView<Launcher> {
+
+    public static final FloatProperty<LauncherRecentsView> TRANSLATION_Y_FACTOR =
+            new FloatProperty<LauncherRecentsView>("translationYFactor") {
+
+                @Override
+                public void setValue(LauncherRecentsView view, float v) {
+                    view.setTranslationYFactor(v);
+                }
+
+                @Override
+                public Float get(LauncherRecentsView view) {
+                    return view.mTranslationYFactor;
+                }
+            };
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private float mTranslationYFactor;
+
+    public LauncherRecentsView(Context context) {
+        this(context, null);
+    }
+
+    public LauncherRecentsView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setContentAlpha(0);
+    }
+
+    @Override
+    protected void startHome() {
+        mActivity.getStateManager().goToState(NORMAL);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        setTranslationYFactor(mTranslationYFactor);
+    }
+
+    public void setTranslationYFactor(float translationFactor) {
+        mTranslationYFactor = translationFactor;
+        setTranslationY(computeTranslationYForFactor(mTranslationYFactor));
+    }
+
+    public float computeTranslationYForFactor(float translationYFactor) {
+        return translationYFactor * (getPaddingBottom() - getPaddingTop());
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        maybeDrawEmptyMessage(canvas);
+        super.draw(canvas);
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        super.onViewAdded(child);
+        updateEmptyMessage();
+    }
+
+    @Override
+    protected void onTaskStackUpdated() {
+        // Lazily update the empty message only when the task stack is reapplied
+        updateEmptyMessage();
+    }
+
+    /**
+     * Animates adjacent tasks and translate hotseat off screen as well.
+     */
+    @Override
+    public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv,
+            ClipAnimationHelper helper) {
+        AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv, helper);
+
+        if (!OverviewInteractionState.getInstance(mActivity).isSwipeUpGestureEnabled()) {
+            // Hotseat doesn't move when opening recents with the button,
+            // so don't animate it here either.
+            return anim;
+        }
+
+        float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN;
+        LauncherState state = mActivity.getStateManager().getState();
+        if ((state.getVisibleElements(mActivity) & ALL_APPS_HEADER_EXTRA) != 0) {
+            float maxShiftRange = mActivity.getDeviceProfile().heightPx;
+            float currShiftRange = mActivity.getAllAppsController().getShiftRange();
+            allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange;
+        }
+        anim.play(ObjectAnimator.ofFloat(
+                mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
+
+        ObjectAnimator dragHandleAnim = ObjectAnimator.ofInt(
+                mActivity.findViewById(R.id.scrim_view), ScrimView.DRAG_HANDLE_ALPHA, 0);
+        dragHandleAnim.setInterpolator(Interpolators.ACCEL_2);
+        anim.play(dragHandleAnim);
+
+        return anim;
+    }
+
+    @Override
+    protected void getTaskSize(DeviceProfile dp, Rect outRect) {
+        LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
+    }
+
+    @Override
+    protected void onTaskLaunched(boolean success) {
+        if (success) {
+            mActivity.getStateManager().goToState(NORMAL, false /* animate */);
+        } else {
+            LauncherState state = mActivity.getStateManager().getState();
+            mActivity.getAllAppsController().setState(state);
+        }
+        super.onTaskLaunched(success);
+    }
+
+    @Override
+    public boolean shouldUseMultiWindowTaskSizeStrategy() {
+        return mActivity.isInMultiWindowModeCompat();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
new file mode 100644
index 0000000..2680a26
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
+import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.LayoutTransition.TransitionListener;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.support.annotation.Nullable;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.SparseBooleanArray;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.ListView;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PropertyListBuilder;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.util.Themes;
+import com.android.quickstep.OverviewCallbacks;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.TaskUtils;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.TaskViewDrawable;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.BackgroundExecutor;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * A list of recent tasks.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public abstract class RecentsView<T extends BaseActivity> extends PagedView implements Insettable {
+
+    private static final String TAG = RecentsView.class.getSimpleName();
+
+    public static final FloatProperty<RecentsView> CONTENT_ALPHA =
+            new FloatProperty<RecentsView>("contentAlpha") {
+                @Override
+                public void setValue(RecentsView view, float v) {
+                    view.setContentAlpha(v);
+                }
+
+                @Override
+                public Float get(RecentsView view) {
+                    return view.getContentAlpha();
+                }
+            };
+
+    private final Rect mTempRect = new Rect();
+
+    private static final int DISMISS_TASK_DURATION = 300;
+    private static final int ADDITION_TASK_DURATION = 200;
+    // The threshold at which we update the SystemUI flags when animating from the task into the app
+    public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
+
+    private static final float[] sTempFloatArray = new float[3];
+
+    protected final T mActivity;
+    private final QuickScrubController mQuickScrubController;
+    private final float mFastFlingVelocity;
+    private final RecentsModel mModel;
+    private final int mTaskTopMargin;
+    private final ClearAllButton mClearAllButton;
+    private final Rect mClearAllButtonDeadZoneRect = new Rect();
+    private final Rect mTaskViewDeadZoneRect = new Rect();
+
+    private final ScrollState mScrollState = new ScrollState();
+    // Keeps track of the previously known visible tasks for purposes of loading/unloading task data
+    private final SparseBooleanArray mHasVisibleTaskData = new SparseBooleanArray();
+
+    /**
+     * TODO: Call reloadIdNeeded in onTaskStackChanged.
+     */
+    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+        @Override
+        public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
+            if (!mHandleTaskStackChanges) {
+                return;
+            }
+            updateThumbnail(taskId, snapshot);
+        }
+
+        @Override
+        public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+            if (!mHandleTaskStackChanges) {
+                return;
+            }
+            // Check this is for the right user
+            if (!checkCurrentOrManagedUserId(userId, getContext())) {
+                return;
+            }
+
+            // Remove the task immediately from the task list
+            TaskView taskView = getTaskView(taskId);
+            if (taskView != null) {
+                removeView(taskView);
+            }
+        }
+
+        @Override
+        public void onActivityUnpinned() {
+            if (!mHandleTaskStackChanges) {
+                return;
+            }
+
+            reloadIfNeeded();
+            enableLayoutTransitions();
+        }
+
+        @Override
+        public void onTaskRemoved(int taskId) {
+            if (!mHandleTaskStackChanges) {
+                return;
+            }
+            BackgroundExecutor.get().submit(() -> {
+                TaskView taskView = getTaskView(taskId);
+                if (taskView == null) {
+                    return;
+                }
+                Handler handler = taskView.getHandler();
+                if (handler == null) {
+                    return;
+                }
+
+                // TODO: Add callbacks from AM reflecting adding/removing from the recents list, and
+                //       remove all these checks
+                Task.TaskKey taskKey = taskView.getTask().key;
+                if (PackageManagerWrapper.getInstance().getActivityInfo(taskKey.getComponent(),
+                        taskKey.userId) == null) {
+                    // The package was uninstalled
+                    handler.post(() ->
+                            dismissTask(taskView, true /* animate */, false /* removeTask */));
+                } else {
+                    RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(getContext());
+                    RecentsTaskLoadPlan.PreloadOptions opts =
+                            new RecentsTaskLoadPlan.PreloadOptions();
+                    opts.loadTitles = false;
+                    loadPlan.preloadPlan(opts, mModel.getRecentsTaskLoader(), -1,
+                            UserHandle.myUserId());
+                    if (loadPlan.getTaskStack().findTaskWithId(taskId) == null) {
+                        // The task was removed from the recents list
+                        handler.post(() ->
+                                dismissTask(taskView, true /* animate */, false /* removeTask */));
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onPinnedStackAnimationStarted() {
+            // Needed for activities that auto-enter PiP, which will not trigger a remote
+            // animation to be created
+            mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+        }
+    };
+
+    private int mLoadPlanId = -1;
+
+    // Only valid until the launcher state changes to NORMAL
+    private int mRunningTaskId = -1;
+    private boolean mRunningTaskTileHidden;
+    private Task mTmpRunningTask;
+
+    private boolean mRunningTaskIconScaledDown = false;
+
+    private boolean mOverviewStateEnabled;
+    private boolean mHandleTaskStackChanges;
+    private Runnable mNextPageSwitchRunnable;
+    private boolean mSwipeDownShouldLaunchApp;
+    private boolean mTouchDownToStartHome;
+    private final int mTouchSlop;
+    private int mDownX;
+    private int mDownY;
+
+    private PendingAnimation mPendingAnimation;
+    private LayoutTransition mLayoutTransition;
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private float mContentAlpha = 1;
+
+    // Keeps track of task id whose visual state should not be reset
+    private int mIgnoreResetTaskId = -1;
+
+    // Variables for empty state
+    private final Drawable mEmptyIcon;
+    private final CharSequence mEmptyMessage;
+    private final TextPaint mEmptyMessagePaint;
+    private final Point mLastMeasureSize = new Point();
+    private final int mEmptyMessagePadding;
+    private boolean mShowEmptyMessage;
+    private Layout mEmptyTextLayout;
+
+    private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
+            (inMultiWindowMode) -> {
+        if (!inMultiWindowMode && mOverviewStateEnabled) {
+            // TODO: Re-enable layout transitions for addition of the unpinned task
+            reloadIfNeeded();
+        }
+    };
+
+    public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
+        enableFreeScroll(true);
+
+        mFastFlingVelocity = getResources()
+                .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
+        mActivity = (T) BaseActivity.fromContext(context);
+        mQuickScrubController = new QuickScrubController(mActivity, this);
+        mModel = RecentsModel.getInstance(context);
+
+        mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
+                .inflate(R.layout.overview_clear_all_button, this, false);
+        mClearAllButton.setOnClickListener(this::dismissAllTasks);
+
+        mIsRtl = !Utilities.isRtl(getResources());
+        setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
+        mTaskTopMargin = getResources()
+                .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+
+        mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
+        mEmptyIcon.setCallback(this);
+        mEmptyMessage = context.getText(R.string.recents_empty_message);
+        mEmptyMessagePaint = new TextPaint();
+        mEmptyMessagePaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
+        mEmptyMessagePaint.setTextSize(getResources()
+                .getDimension(R.dimen.recents_empty_message_text_size));
+        mEmptyMessagePadding = getResources()
+                .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
+        setWillNotDraw(false);
+        updateEmptyMessage();
+    }
+
+    public boolean isRtl() {
+        return mIsRtl;
+    }
+
+    public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
+        TaskView taskView = getTaskView(taskId);
+        if (taskView != null) {
+            taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
+        }
+        return taskView;
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        updateTaskStackListenerState();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updateTaskStackListenerState();
+        mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        updateTaskStackListenerState();
+        mActivity.removeMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
+        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+
+        // Clear the task data for the removed child if it was visible
+        if (child != mClearAllButton) {
+            Task task = ((TaskView) child).getTask();
+            if (mHasVisibleTaskData.get(task.key.id)) {
+                mHasVisibleTaskData.delete(task.key.id);
+                RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+                loader.unloadTaskData(task);
+                loader.getHighResThumbnailLoader().onTaskInvisible(task);
+            }
+        }
+    }
+
+    public boolean isTaskViewVisible(TaskView tv) {
+        // For now, just check if it's the active task or an adjacent task
+        return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
+    }
+
+    public TaskView getTaskView(int taskId) {
+        for (int i = 0; i < getTaskViewCount(); i++) {
+            TaskView tv = (TaskView) getChildAt(i);
+            if (tv.getTask().key != null && tv.getTask().key.id == taskId) {
+                return tv;
+            }
+        }
+        return null;
+    }
+
+    public void setOverviewStateEnabled(boolean enabled) {
+        mOverviewStateEnabled = enabled;
+        updateTaskStackListenerState();
+    }
+
+    public void setNextPageSwitchRunnable(Runnable r) {
+        mNextPageSwitchRunnable = r;
+    }
+
+    @Override
+    protected void onPageEndTransition() {
+        super.onPageEndTransition();
+        if (mNextPageSwitchRunnable != null) {
+            mNextPageSwitchRunnable.run();
+            mNextPageSwitchRunnable = null;
+        }
+        if (getNextPage() > 0) {
+            setSwipeDownShouldLaunchApp(true);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        super.onTouchEvent(ev);
+        final int x = (int) ev.getX();
+        final int y = (int) ev.getY();
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_UP:
+                if (mShowEmptyMessage) {
+                    onAllTasksRemoved();
+                }
+                if (mTouchDownToStartHome) {
+                    startHome();
+                }
+                mTouchDownToStartHome = false;
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                mTouchDownToStartHome = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                // Passing the touch slop will not allow dismiss to home
+                if (mTouchDownToStartHome && Math.hypot(mDownX - x, mDownY - y) > mTouchSlop) {
+                    mTouchDownToStartHome = false;
+                }
+                break;
+            case MotionEvent.ACTION_DOWN:
+                // Touch down anywhere but the deadzone around the visible clear all button and
+                // between the task views will start home on touch up
+                if (mTouchState == TOUCH_STATE_REST) {
+                    updateDeadZoneRects();
+                    final boolean clearAllButtonDeadZoneConsumed = mClearAllButton.getAlpha() == 1
+                            && mClearAllButtonDeadZoneRect.contains(x, y);
+                    if (!clearAllButtonDeadZoneConsumed
+                            && !mTaskViewDeadZoneRect.contains(x + getScrollX(), y)) {
+                        mTouchDownToStartHome = true;
+                    }
+                }
+                mDownX = x;
+                mDownY = y;
+                break;
+        }
+
+
+        // Do not let touch escape to siblings below this view.
+        return true;
+    }
+
+    private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
+        if (mPendingAnimation != null) {
+            mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(loadPlan));
+            return;
+        }
+        TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
+        if (stack == null) {
+            removeAllViews();
+            onTaskStackUpdated();
+            return;
+        }
+
+        int oldChildCount = getChildCount();
+
+        // Ensure there are as many views as there are tasks in the stack (adding and trimming as
+        // necessary)
+        final LayoutInflater inflater = LayoutInflater.from(getContext());
+        final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
+
+        // Unload existing visible task data
+        unloadVisibleTaskData();
+
+        TaskView ignoreRestTaskView =
+                mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
+
+        final int requiredTaskCount = tasks.size();
+        if (getTaskViewCount() != requiredTaskCount) {
+            if (oldChildCount > 0) {
+                removeView(mClearAllButton);
+            }
+            for (int i = getChildCount(); i < requiredTaskCount; i++) {
+                addView(inflater.inflate(R.layout.task, this, false));
+            }
+            while (getChildCount() > requiredTaskCount) {
+                removeView(getChildAt(getChildCount() - 1));
+            }
+            if (requiredTaskCount > 0) {
+                addView(mClearAllButton);
+            }
+        }
+
+        // Rebind and reset all task views
+        for (int i = requiredTaskCount - 1; i >= 0; i--) {
+            final int pageIndex = requiredTaskCount - i - 1;
+            final Task task = tasks.get(i);
+            final TaskView taskView = (TaskView) getChildAt(pageIndex);
+            taskView.bind(task);
+        }
+        if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) {
+            // If the taskView mapping is changing, do not preserve the visuals. Since we are
+            // mostly preserving the first task, and new taskViews are added to the end, it should
+            // generally map to the same task.
+            mIgnoreResetTaskId = -1;
+        }
+        resetTaskVisuals();
+
+        if (oldChildCount != getChildCount()) {
+            mQuickScrubController.snapToNextTaskIfAvailable();
+        }
+        onTaskStackUpdated();
+    }
+
+    public int getTaskViewCount() {
+        // Account for the clear all button.
+        int childCount = getChildCount();
+        return childCount == 0 ? 0 : childCount - 1;
+    }
+
+    protected void onTaskStackUpdated() { }
+
+    public void resetTaskVisuals() {
+        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
+            TaskView taskView = (TaskView) getChildAt(i);
+            if (mIgnoreResetTaskId != taskView.getTask().key.id) {
+                taskView.resetVisualProperties();
+            }
+        }
+        if (mRunningTaskTileHidden) {
+            setRunningTaskHidden(mRunningTaskTileHidden);
+        }
+
+        // Force apply the scale.
+        if (mIgnoreResetTaskId != mRunningTaskId) {
+            applyRunningTaskIconScale();
+        }
+
+        updateCurveProperties();
+        // Update the set of visible task's data
+        loadVisibleTaskData();
+    }
+
+    private void updateTaskStackListenerState() {
+        boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow()
+                && getWindowVisibility() == VISIBLE;
+        if (handleTaskStackChanges != mHandleTaskStackChanges) {
+            mHandleTaskStackChanges = handleTaskStackChanges;
+            if (handleTaskStackChanges) {
+                reloadIfNeeded();
+            }
+        }
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        mInsets.set(insets);
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        getTaskSize(dp, mTempRect);
+
+        // Keep this logic in sync with ActivityControlHelper.getTranslationYForQuickScrub.
+        mTempRect.top -= mTaskTopMargin;
+        setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
+                dp.availableWidthPx + mInsets.left - mTempRect.right,
+                dp.availableHeightPx + mInsets.top - mTempRect.bottom);
+    }
+
+    protected abstract void getTaskSize(DeviceProfile dp, Rect outRect);
+
+    public void getTaskSize(Rect outRect) {
+        getTaskSize(mActivity.getDeviceProfile(), outRect);
+    }
+
+    @Override
+    protected boolean computeScrollHelper() {
+        boolean scrolling = super.computeScrollHelper();
+        boolean isFlingingFast = false;
+        updateCurveProperties();
+        if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) {
+            if (scrolling) {
+                // Check if we are flinging quickly to disable high res thumbnail loading
+                isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity;
+            }
+
+            // After scrolling, update the visible task's data
+            loadVisibleTaskData();
+        }
+
+        // Update the high res thumbnail loader
+        RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+        loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast);
+        return scrolling;
+    }
+
+    /**
+     * Scales and adjusts translation of adjacent pages as if on a curved carousel.
+     */
+    public void updateCurveProperties() {
+        if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
+            return;
+        }
+        int scrollX = getScrollX();
+        final int halfPageWidth = getNormalChildWidth() / 2;
+        final int screenCenter = mInsets.left + getPaddingLeft() + scrollX + halfPageWidth;
+        final int halfScreenWidth = getMeasuredWidth() / 2;
+        final int pageSpacing = mPageSpacing;
+        mScrollState.scrollFromEdge = mIsRtl ? scrollX : (mMaxScrollX - scrollX);
+
+        final int pageCount = getPageCount();
+        for (int i = 0; i < pageCount; i++) {
+            View page = getPageAt(i);
+            float pageCenter = page.getLeft() + page.getTranslationX() + halfPageWidth;
+            float distanceFromScreenCenter = screenCenter - pageCenter;
+            float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
+            mScrollState.linearInterpolation = Math.min(1,
+                    Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+            ((PageCallbacks) page).onPageScroll(mScrollState);
+        }
+    }
+
+    /**
+     * Iterates through all thet asks, and loads the associated task data for newly visible tasks,
+     * and unloads the associated task data for tasks that are no longer visible.
+     */
+    public void loadVisibleTaskData() {
+        if (!mOverviewStateEnabled) {
+            // Skip loading visible task data if we've already left the overview state
+            return;
+        }
+
+        RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+        int centerPageIndex = getPageNearestToCenterOfScreen();
+        int numChildren = getTaskViewCount();
+        int lower = Math.max(0, centerPageIndex - 2);
+        int upper = Math.min(centerPageIndex + 2, numChildren - 1);
+
+        // Update the task data for the in/visible children
+        for (int i = 0; i < numChildren; i++) {
+            TaskView taskView = (TaskView) getChildAt(i);
+            Task task = taskView.getTask();
+            boolean visible = lower <= i && i <= upper;
+            if (visible) {
+                if (task == mTmpRunningTask) {
+                    // Skip loading if this is the task that we are animating into
+                    continue;
+                }
+                if (!mHasVisibleTaskData.get(task.key.id)) {
+                    loader.loadTaskData(task);
+                    loader.getHighResThumbnailLoader().onTaskVisible(task);
+                }
+                mHasVisibleTaskData.put(task.key.id, visible);
+            } else {
+                if (mHasVisibleTaskData.get(task.key.id)) {
+                    loader.unloadTaskData(task);
+                    loader.getHighResThumbnailLoader().onTaskInvisible(task);
+                }
+                mHasVisibleTaskData.delete(task.key.id);
+            }
+        }
+    }
+
+    /**
+     * Unloads any associated data from the currently visible tasks
+     */
+    private void unloadVisibleTaskData() {
+        RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
+        for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
+            if (mHasVisibleTaskData.valueAt(i)) {
+                TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
+                if (taskView != null) {
+                    Task task = taskView.getTask();
+                    loader.unloadTaskData(task);
+                    loader.getHighResThumbnailLoader().onTaskInvisible(task);
+                }
+            }
+        }
+        mHasVisibleTaskData.clear();
+    }
+
+    protected void onAllTasksRemoved() {
+        startHome();
+    }
+
+    protected abstract void startHome();
+
+    public void reset() {
+        mRunningTaskId = -1;
+        mRunningTaskTileHidden = false;
+        mIgnoreResetTaskId = -1;
+
+        unloadVisibleTaskData();
+        setCurrentPage(0);
+
+        OverviewCallbacks.get(getContext()).onResetOverview();
+    }
+
+    /**
+     * Reloads the view if anything in recents changed.
+     */
+    public void reloadIfNeeded() {
+        if (!mModel.isLoadPlanValid(mLoadPlanId)) {
+            mLoadPlanId = mModel.loadTasks(mRunningTaskId, this::applyLoadPlan);
+        }
+    }
+
+    /**
+     * Ensures that the first task in the view represents {@param task} and reloads the view
+     * if needed. This allows the swipe-up gesture to assume that the first tile always
+     * corresponds to the correct task.
+     * All subsequent calls to reload will keep the task as the first item until {@link #reset()}
+     * is called.
+     * Also scrolls the view to this task
+     */
+    public void showTask(int runningTaskId) {
+        if (getChildCount() == 0) {
+            // Add an empty view for now until the task plan is loaded and applied
+            final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
+                    .inflate(R.layout.task, this, false);
+            addView(taskView);
+            addView(mClearAllButton);
+
+            // The temporary running task is only used for the duration between the start of the
+            // gesture and the task list is loaded and applied
+            mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(),
+                    new ComponentName(getContext(), getClass()), 0, 0), null, null, "", "", 0, 0,
+                    false, true, false, false, new ActivityManager.TaskDescription(), 0,
+                    new ComponentName("", ""), false);
+            taskView.bind(mTmpRunningTask);
+        }
+        setCurrentTask(runningTaskId);
+    }
+
+    /**
+     * Hides the tile associated with {@link #mRunningTaskId}
+     */
+    public void setRunningTaskHidden(boolean isHidden) {
+        mRunningTaskTileHidden = isHidden;
+        TaskView runningTask = getTaskView(mRunningTaskId);
+        if (runningTask != null) {
+            runningTask.setAlpha(isHidden ? 0 : mContentAlpha);
+        }
+    }
+
+    /**
+     * Similar to {@link #showTask(int)} but does not put any restrictions on the first tile.
+     */
+    public void setCurrentTask(int runningTaskId) {
+        boolean runningTaskTileHidden = mRunningTaskTileHidden;
+        boolean runningTaskIconScaledDown = mRunningTaskIconScaledDown;
+
+        setRunningTaskIconScaledDown(false);
+        setRunningTaskHidden(false);
+        mRunningTaskId = runningTaskId;
+        setRunningTaskIconScaledDown(runningTaskIconScaledDown);
+        setRunningTaskHidden(runningTaskTileHidden);
+
+        setCurrentPage(0);
+
+        // Load the tasks (if the loading is already
+        mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+    }
+
+    public void showNextTask() {
+        TaskView runningTaskView = getTaskView(mRunningTaskId);
+        if (runningTaskView == null) {
+            // Launch the first task
+            if (getTaskViewCount() > 0) {
+                ((TaskView) getChildAt(0)).launchTask(true /* animate */);
+            }
+        } else {
+            // Get the next launch task
+            int runningTaskIndex = indexOfChild(runningTaskView);
+            int nextTaskIndex = Math.max(0, Math.min(getTaskViewCount() - 1, runningTaskIndex + 1));
+            if (nextTaskIndex < getTaskViewCount()) {
+                ((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */);
+            }
+        }
+    }
+
+    public QuickScrubController getQuickScrubController() {
+        return mQuickScrubController;
+    }
+
+    public void setRunningTaskIconScaledDown(boolean isScaledDown) {
+        if (mRunningTaskIconScaledDown != isScaledDown) {
+            mRunningTaskIconScaledDown = isScaledDown;
+            applyRunningTaskIconScale();
+        }
+    }
+
+    private void applyRunningTaskIconScale() {
+        TaskView firstTask = getTaskView(mRunningTaskId);
+        if (firstTask != null) {
+            firstTask.setIconScaleAndDim(mRunningTaskIconScaledDown ? 0 : 1);
+        }
+    }
+
+    public void animateUpRunningTaskIconScale() {
+        mRunningTaskIconScaledDown = false;
+        TaskView firstTask = getTaskView(mRunningTaskId);
+        if (firstTask != null) {
+            firstTask.animateIconScaleAndDimIntoView();
+        }
+    }
+
+    private void enableLayoutTransitions() {
+        if (mLayoutTransition == null) {
+            mLayoutTransition = new LayoutTransition();
+            mLayoutTransition.enableTransitionType(LayoutTransition.APPEARING);
+            mLayoutTransition.setDuration(ADDITION_TASK_DURATION);
+            mLayoutTransition.setStartDelay(LayoutTransition.APPEARING, 0);
+
+            mLayoutTransition.addTransitionListener(new TransitionListener() {
+                @Override
+                public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+                }
+
+                @Override
+                public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+                    // When the unpinned task is added, snap to first page and disable transitions
+                    if (view instanceof TaskView) {
+                        snapToPage(0);
+                        disableLayoutTransitions();
+                    }
+
+                }
+            });
+        }
+        setLayoutTransition(mLayoutTransition);
+    }
+
+    private void disableLayoutTransitions() {
+        setLayoutTransition(null);
+    }
+
+    public void setSwipeDownShouldLaunchApp(boolean swipeDownShouldLaunchApp) {
+        mSwipeDownShouldLaunchApp = swipeDownShouldLaunchApp;
+    }
+
+    public boolean shouldSwipeDownLaunchApp() {
+        return mSwipeDownShouldLaunchApp;
+    }
+
+    public interface PageCallbacks {
+
+        /**
+         * Updates the page UI based on scroll params.
+         */
+        default void onPageScroll(ScrollState scrollState) {}
+    }
+
+    public static class ScrollState {
+
+        /**
+         * The progress from 0 to 1, where 0 is the center
+         * of the screen and 1 is the edge of the screen.
+         */
+        public float linearInterpolation;
+
+        /**
+         * The amount by which all the content is scrolled relative to the end of the list.
+         */
+        public float scrollFromEdge;
+    }
+
+    public void setIgnoreResetTask(int taskId) {
+        mIgnoreResetTaskId = taskId;
+    }
+
+    public void clearIgnoreResetTask(int taskId) {
+        if (mIgnoreResetTaskId == taskId) {
+            mIgnoreResetTaskId = -1;
+        }
+    }
+
+    private void addDismissedTaskAnimations(View taskView, AnimatorSet anim, long duration) {
+        addAnim(ObjectAnimator.ofFloat(taskView, ALPHA, 0), duration, ACCEL_2, anim);
+        addAnim(ObjectAnimator.ofFloat(taskView, TRANSLATION_Y, -taskView.getHeight()),
+                duration, LINEAR, anim);
+    }
+
+    private void removeTask(Task task, int index, PendingAnimation.OnEndListener onEndListener,
+                            boolean shouldLog) {
+        if (task != null) {
+            ActivityManagerWrapper.getInstance().removeTask(task.key.id);
+            if (shouldLog) {
+                mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+                        onEndListener.logAction, Direction.UP, index,
+                        TaskUtils.getLaunchComponentKeyForTask(task.key));
+            }
+        }
+    }
+
+    public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
+            boolean shouldRemoveTask, long duration) {
+        if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+            throw new IllegalStateException("Another pending animation is still running");
+        }
+        AnimatorSet anim = new AnimatorSet();
+        PendingAnimation pendingAnimation = new PendingAnimation(anim);
+
+        int count = getPageCount();
+        if (count == 0) {
+            return pendingAnimation;
+        }
+
+        int[] oldScroll = new int[count];
+        getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
+
+        int[] newScroll = new int[count];
+        getPageScrolls(newScroll, false, (v) -> v.getVisibility() != GONE && v != taskView);
+
+        int taskCount = getTaskViewCount();
+        int scrollDiffPerPage = 0;
+        if (count > 1) {
+            scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
+        }
+        int draggedIndex = indexOfChild(taskView);
+
+        boolean needsCurveUpdates = false;
+        for (int i = 0; i < count; i++) {
+            View child = getChildAt(i);
+            if (child == taskView) {
+                if (animateTaskView) {
+                    addDismissedTaskAnimations(taskView, anim, duration);
+                }
+            } else {
+                // If we just take newScroll - oldScroll, everything to the right of dragged task
+                // translates to the left. We need to offset this in some cases:
+                // - In RTL, add page offset to all pages, since we want pages to move to the right
+                // Additionally, add a page offset if:
+                // - Current page is rightmost page (leftmost for RTL)
+                // - Dragging an adjacent page on the left side (right side for RTL)
+                int offset = mIsRtl ? scrollDiffPerPage : 0;
+                if (mCurrentPage == draggedIndex) {
+                    int lastPage = taskCount - 1;
+                    if (mCurrentPage == lastPage) {
+                        offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
+                    }
+                } else {
+                    // Dragging an adjacent page.
+                    int negativeAdjacent = mCurrentPage - 1; // (Right in RTL, left in LTR)
+                    if (draggedIndex == negativeAdjacent) {
+                        offset += mIsRtl ? -scrollDiffPerPage : scrollDiffPerPage;
+                    }
+                }
+                int scrollDiff = newScroll[i] - oldScroll[i] + offset;
+                if (scrollDiff != 0) {
+                    addAnim(ObjectAnimator.ofFloat(child, TRANSLATION_X, scrollDiff),
+                            duration, ACCEL, anim);
+                    needsCurveUpdates = true;
+                }
+            }
+        }
+
+        if (needsCurveUpdates) {
+            ValueAnimator va = ValueAnimator.ofFloat(0, 1);
+            va.addUpdateListener((a) -> updateCurveProperties());
+            anim.play(va);
+        }
+
+        // Add a tiny bit of translation Z, so that it draws on top of other views
+        if (animateTaskView) {
+            taskView.setTranslationZ(0.1f);
+        }
+
+        mPendingAnimation = pendingAnimation;
+        mPendingAnimation.addEndListener((onEndListener) -> {
+           if (onEndListener.isSuccess) {
+               if (shouldRemoveTask) {
+                   removeTask(taskView.getTask(), draggedIndex, onEndListener, true);
+               }
+               int pageToSnapTo = mCurrentPage;
+               if (draggedIndex < pageToSnapTo || pageToSnapTo == (getTaskViewCount() - 1)) {
+                   pageToSnapTo -= 1;
+               }
+               removeView(taskView);
+
+               if (getTaskViewCount() == 0) {
+                   removeView(mClearAllButton);
+                   onAllTasksRemoved();
+               } else {
+                   snapToPageImmediately(pageToSnapTo);
+               }
+           }
+           resetTaskVisuals();
+           mPendingAnimation = null;
+        });
+        return pendingAnimation;
+    }
+
+    public PendingAnimation createAllTasksDismissAnimation(long duration) {
+        if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+            throw new IllegalStateException("Another pending animation is still running");
+        }
+        AnimatorSet anim = new AnimatorSet();
+        PendingAnimation pendingAnimation = new PendingAnimation(anim);
+
+        int count = getTaskViewCount();
+        for (int i = 0; i < count; i++) {
+            addDismissedTaskAnimations(getChildAt(i), anim, duration);
+        }
+
+        mPendingAnimation = pendingAnimation;
+        mPendingAnimation.addEndListener((onEndListener) -> {
+            if (onEndListener.isSuccess) {
+                int taskViewCount = getTaskViewCount();
+                for (int i = 0; i < taskViewCount; i++) {
+                    removeTask(getTaskViewAt(i).getTask(), -1, onEndListener, false);
+                }
+                removeAllViews();
+                onAllTasksRemoved();
+            }
+            mPendingAnimation = null;
+        });
+        return pendingAnimation;
+    }
+
+    private static void addAnim(ObjectAnimator anim, long duration,
+            TimeInterpolator interpolator, AnimatorSet set) {
+        anim.setDuration(duration).setInterpolator(interpolator);
+        set.play(anim);
+    }
+
+    private boolean snapToPageRelative(int pageCount, int delta, boolean cycle) {
+        if (pageCount == 0) {
+            return false;
+        }
+        final int newPageUnbound = getNextPage() + delta;
+        if (!cycle && (newPageUnbound < 0 || newPageUnbound >= pageCount)) {
+            return false;
+        }
+        snapToPage((newPageUnbound + pageCount) % pageCount);
+        getChildAt(getNextPage()).requestFocus();
+        return true;
+    }
+
+    private void runDismissAnimation(PendingAnimation pendingAnim) {
+        AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(
+                pendingAnim.anim, DISMISS_TASK_DURATION);
+        controller.dispatchOnStart();
+        controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
+        controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
+        controller.start();
+    }
+
+    public void dismissTask(TaskView taskView, boolean animateTaskView, boolean removeTask) {
+        runDismissAnimation(createTaskDismissAnimation(taskView, animateTaskView, removeTask,
+                DISMISS_TASK_DURATION));
+    }
+
+    @SuppressWarnings("unused")
+    private void dismissAllTasks(View view) {
+        runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION));
+    }
+
+    private void dismissCurrentTask() {
+        TaskView taskView = getTaskView(getNextPage());
+        if (taskView != null) {
+            dismissTask(taskView, true /*animateTaskView*/, true /*removeTask*/);
+        }
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_TAB:
+                    return snapToPageRelative(getTaskViewCount(), event.isShiftPressed() ? -1 : 1,
+                            event.isAltPressed() /* cycle */);
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    return snapToPageRelative(getPageCount(), mIsRtl ? -1 : 1, false /* cycle */);
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    return snapToPageRelative(getPageCount(), mIsRtl ? 1 : -1, false /* cycle */);
+                case KeyEvent.KEYCODE_DEL:
+                case KeyEvent.KEYCODE_FORWARD_DEL:
+                    dismissCurrentTask();
+                    return true;
+                case KeyEvent.KEYCODE_NUMPAD_DOT:
+                    if (event.isAltPressed()) {
+                        // Numpad DEL pressed while holding Alt.
+                        dismissCurrentTask();
+                        return true;
+                    }
+            }
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction,
+            @Nullable Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (gainFocus && getChildCount() > 0) {
+            switch (direction) {
+                case FOCUS_FORWARD:
+                    setCurrentPage(0);
+                    break;
+                case FOCUS_BACKWARD:
+                case FOCUS_RIGHT:
+                case FOCUS_LEFT:
+                    setCurrentPage(getChildCount() - 1);
+                    break;
+            }
+        }
+    }
+
+    public float getContentAlpha() {
+        return mContentAlpha;
+    }
+
+    public void setContentAlpha(float alpha) {
+        if (alpha == mContentAlpha) {
+            return;
+        }
+        alpha = Utilities.boundToRange(alpha, 0, 1);
+        mContentAlpha = alpha;
+        for (int i = getTaskViewCount() - 1; i >= 0; i--) {
+            TaskView child = getTaskViewAt(i);
+            if (!mRunningTaskTileHidden || child.getTask().key.id != mRunningTaskId) {
+                getChildAt(i).setAlpha(alpha);
+            }
+        }
+        mClearAllButton.setContentAlpha(mContentAlpha);
+
+        int alphaInt = Math.round(alpha * 255);
+        mEmptyMessagePaint.setAlpha(alphaInt);
+        mEmptyIcon.setAlpha(alphaInt);
+
+        setVisibility(alpha > 0 ? VISIBLE : GONE);
+    }
+
+    private float[] getAdjacentScaleAndTranslation(TaskView currTask,
+            float currTaskToScale, float currTaskToTranslationY) {
+        float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale());
+        sTempFloatArray[0] = currTaskToScale;
+        sTempFloatArray[1] = mIsRtl ? -displacement : displacement;
+        sTempFloatArray[2] = currTaskToTranslationY;
+        return sTempFloatArray;
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        super.onViewAdded(child);
+        child.setAlpha(mContentAlpha);
+    }
+
+    public TaskView getTaskViewAt(int index) {
+        View child = getChildAt(index);
+        return child == mClearAllButton ? null : (TaskView) child;
+    }
+
+    public void updateEmptyMessage() {
+        boolean isEmpty = getChildCount() == 0;
+        boolean hasSizeChanged = mLastMeasureSize.x != getWidth()
+                || mLastMeasureSize.y != getHeight();
+        if (isEmpty == mShowEmptyMessage && !hasSizeChanged) {
+            return;
+        }
+        setContentDescription(isEmpty ? mEmptyMessage : "");
+        mShowEmptyMessage = isEmpty;
+        updateEmptyStateUi(hasSizeChanged);
+        invalidate();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        updateEmptyStateUi(changed);
+
+        // Set the pivot points to match the task preview center
+        setPivotY(((mInsets.top + getPaddingTop() + mTaskTopMargin)
+                + (getHeight() - mInsets.bottom - getPaddingBottom())) / 2);
+        setPivotX(((mInsets.left + getPaddingLeft())
+                + (getWidth() - mInsets.right - getPaddingRight())) / 2);
+    }
+
+    private void updateDeadZoneRects() {
+        // Get the deadzone rect surrounding the clear all button to not dismiss overview to home
+        mClearAllButtonDeadZoneRect.setEmpty();
+        if (mClearAllButton.getWidth() > 0) {
+            int verticalMargin = getResources()
+                    .getDimensionPixelSize(R.dimen.recents_clear_all_deadzone_vertical_margin);
+            mClearAllButton.getHitRect(mClearAllButtonDeadZoneRect);
+            mClearAllButtonDeadZoneRect.inset(-getPaddingRight() / 2, -verticalMargin);
+        }
+
+        // Get the deadzone rect between the task views
+        mTaskViewDeadZoneRect.setEmpty();
+        int count = getTaskViewCount();
+        if (count > 0) {
+            final View taskView = getTaskViewAt(0);
+            getTaskViewAt(count - 1).getHitRect(mTaskViewDeadZoneRect);
+            mTaskViewDeadZoneRect.union(taskView.getLeft(), taskView.getTop(), taskView.getRight(),
+                    taskView.getBottom());
+        }
+    }
+
+    private void updateEmptyStateUi(boolean sizeChanged) {
+        boolean hasValidSize = getWidth() > 0 && getHeight() > 0;
+        if (sizeChanged && hasValidSize) {
+            mEmptyTextLayout = null;
+            mLastMeasureSize.set(getWidth(), getHeight());
+        }
+
+        if (mShowEmptyMessage && hasValidSize && mEmptyTextLayout == null) {
+            int availableWidth = mLastMeasureSize.x - mEmptyMessagePadding - mEmptyMessagePadding;
+            mEmptyTextLayout = StaticLayout.Builder.obtain(mEmptyMessage, 0, mEmptyMessage.length(),
+                    mEmptyMessagePaint, availableWidth)
+                    .setAlignment(Layout.Alignment.ALIGN_CENTER)
+                    .build();
+            int totalHeight = mEmptyTextLayout.getHeight()
+                    + mEmptyMessagePadding + mEmptyIcon.getIntrinsicHeight();
+
+            int top = (mLastMeasureSize.y - totalHeight) / 2;
+            int left = (mLastMeasureSize.x - mEmptyIcon.getIntrinsicWidth()) / 2;
+            mEmptyIcon.setBounds(left, top, left + mEmptyIcon.getIntrinsicWidth(),
+                    top + mEmptyIcon.getIntrinsicHeight());
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || (mShowEmptyMessage && who == mEmptyIcon);
+    }
+
+    protected void maybeDrawEmptyMessage(Canvas canvas) {
+        if (mShowEmptyMessage && mEmptyTextLayout != null) {
+            // Offset to center in the visible (non-padded) part of RecentsView
+            mTempRect.set(mInsets.left + getPaddingLeft(), mInsets.top + getPaddingTop(),
+                    mInsets.right + getPaddingRight(), mInsets.bottom + getPaddingBottom());
+            canvas.save();
+            canvas.translate(getScrollX() + (mTempRect.left - mTempRect.right) / 2,
+                    (mTempRect.top - mTempRect.bottom) / 2);
+            mEmptyIcon.draw(canvas);
+            canvas.translate(mEmptyMessagePadding,
+                    mEmptyIcon.getBounds().bottom + mEmptyMessagePadding);
+            mEmptyTextLayout.draw(canvas);
+            canvas.restore();
+        }
+    }
+
+    /**
+     * Animate adjacent tasks off screen while scaling up.
+     *
+     * If launching one of the adjacent tasks, parallax the center task and other adjacent task
+     * to the right.
+     */
+    public AnimatorSet createAdjacentPageAnimForTaskLaunch(
+            TaskView tv, ClipAnimationHelper clipAnimationHelper) {
+        AnimatorSet anim = new AnimatorSet();
+
+        int taskIndex = indexOfChild(tv);
+        int centerTaskIndex = getCurrentPage();
+        boolean launchingCenterTask = taskIndex == centerTaskIndex;
+
+        float toScale = clipAnimationHelper.getSourceRect().width()
+                / clipAnimationHelper.getTargetRect().width();
+        float toTranslationY = clipAnimationHelper.getSourceRect().centerY()
+                - clipAnimationHelper.getTargetRect().centerY();
+        if (launchingCenterTask) {
+            TaskView centerTask = getTaskViewAt(centerTaskIndex);
+            if (taskIndex - 1 >= 0) {
+                TaskView adjacentTask = getTaskViewAt(taskIndex - 1);
+                float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
+                        toScale, toTranslationY);
+                scaleAndTranslation[1] = -scaleAndTranslation[1];
+                anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
+            }
+            if (taskIndex + 1 < getTaskViewCount()) {
+                TaskView adjacentTask = getTaskViewAt(taskIndex + 1);
+                float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
+                        toScale, toTranslationY);
+                anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
+            }
+        } else {
+            // We are launching an adjacent task, so parallax the center and other adjacent task.
+            float displacementX = tv.getWidth() * (toScale - tv.getCurveScale());
+            anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), TRANSLATION_X,
+                    mIsRtl ? -displacementX : displacementX));
+
+            int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex);
+            if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
+                anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex),
+                        new PropertyListBuilder()
+                                .translationX(mIsRtl ? -displacementX : displacementX)
+                                .scale(1)
+                                .build()));
+            }
+        }
+        return anim;
+    }
+
+    private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
+        AnimatorSet anim = new AnimatorSet();
+        anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
+        anim.play(ObjectAnimator.ofPropertyValuesHolder(child,
+                        new PropertyListBuilder()
+                                .translationX(toScaleAndTranslation[1])
+                                .translationY(toScaleAndTranslation[2])
+                                .build()));
+        return anim;
+    }
+
+    public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
+        if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+            throw new IllegalStateException("Another pending animation is still running");
+        }
+
+        int count = getChildCount();
+        if (count == 0) {
+            return new PendingAnimation(new AnimatorSet());
+        }
+
+        tv.setVisibility(INVISIBLE);
+        int targetSysUiFlags = tv.getThumbnail().getSysUiStatusNavFlags();
+        TaskViewDrawable drawable = new TaskViewDrawable(tv, this);
+        getOverlay().add(drawable);
+
+        final boolean[] passedOverviewThreshold = new boolean[] {false};
+        ObjectAnimator drawableAnim =
+                ObjectAnimator.ofFloat(drawable, TaskViewDrawable.PROGRESS, 1, 0);
+        drawableAnim.setInterpolator(LINEAR);
+        drawableAnim.addUpdateListener((animator) -> {
+            // Once we pass a certain threshold, update the sysui flags to match the target tasks'
+            // flags
+            mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW,
+                    animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD
+                            ? targetSysUiFlags
+                            : 0);
+
+            // Passing the threshold from taskview to fullscreen app will vibrate
+            final boolean passed = animator.getAnimatedFraction() >= MIN_PROGRESS_FOR_OVERVIEW;
+            if (passed != passedOverviewThreshold[0]) {
+                passedOverviewThreshold[0] = passed;
+                performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+            }
+        });
+
+        AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv,
+                drawable.getClipAnimationHelper());
+        anim.play(drawableAnim);
+        anim.setDuration(duration);
+
+        Consumer<Boolean> onTaskLaunchFinish = (result) -> {
+            onTaskLaunched(result);
+            tv.setVisibility(VISIBLE);
+            getOverlay().remove(drawable);
+        };
+
+        mPendingAnimation = new PendingAnimation(anim);
+        mPendingAnimation.addEndListener((onEndListener) -> {
+            if (onEndListener.isSuccess) {
+                Consumer<Boolean> onLaunchResult = (result) -> {
+                    onTaskLaunchFinish.accept(result);
+                    if (!result) {
+                        tv.notifyTaskLaunchFailed(TAG);
+                    }
+                };
+                tv.launchTask(false, onLaunchResult, getHandler());
+                Task task = tv.getTask();
+                if (task != null) {
+                    mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+                            onEndListener.logAction, Direction.DOWN, indexOfChild(tv),
+                            TaskUtils.getLaunchComponentKeyForTask(task.key));
+                }
+            } else {
+                onTaskLaunchFinish.accept(false);
+            }
+            mPendingAnimation = null;
+        });
+        return mPendingAnimation;
+    }
+
+    public abstract boolean shouldUseMultiWindowTaskSizeStrategy();
+
+    protected void onTaskLaunched(boolean success) {
+        resetTaskVisuals();
+    }
+
+    @Override
+    protected void notifyPageSwitchListener(int prevPage) {
+        super.notifyPageSwitchListener(prevPage);
+        loadVisibleTaskData();
+    }
+
+    @Override
+    protected String getCurrentPageDescription() {
+        return "";
+    }
+
+    @Override
+    public void addChildrenForAccessibility(ArrayList<View> outChildren) {
+        // Add children in reverse order
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            outChildren.add(getChildAt(i));
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        final AccessibilityNodeInfo.CollectionInfo
+                collectionInfo = AccessibilityNodeInfo.CollectionInfo.obtain(
+                1, getTaskViewCount(), false,
+                AccessibilityNodeInfo.CollectionInfo.SELECTION_MODE_NONE);
+        info.setCollectionInfo(collectionInfo);
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+
+        final int taskViewCount = getTaskViewCount();
+        event.setScrollable(taskViewCount > 0);
+
+        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
+            final int[] visibleTasks = getVisibleChildrenRange();
+            event.setFromIndex(taskViewCount - visibleTasks[1] - 1);
+            event.setToIndex(taskViewCount - visibleTasks[0] - 1);
+            event.setItemCount(taskViewCount);
+        }
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        // To hear position-in-list related feedback from Talkback.
+        return ListView.class.getName();
+    }
+
+    @Override
+    protected boolean isPageOrderFlipped() {
+        return true;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
new file mode 100644
index 0000000..8b5e832
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Path.Direction;
+import android.graphics.Path.Op;
+import android.util.AttributeSet;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ScrimView;
+
+/**
+ * Scrim used for all-apps and shelf in Overview
+ * In transposed layout, it behaves as a simple color scrim.
+ * In portrait layout, it draws a rounded rect such that
+ *    From normal state to overview state, the shelf just fades in and does not move
+ *    From overview state to all-apps state the shelf moves up and fades in to cover the screen
+ */
+public class ShelfScrimView extends ScrimView {
+
+    // If the progress is more than this, shelf follows the finger, otherwise it moves faster to
+    // cover the whole screen
+    private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f;
+
+    // In transposed layout, we simply draw a flat color.
+    private boolean mDrawingFlatColor;
+
+    // For shelf mode
+    private final int mEndAlpha;
+    private final float mRadius;
+    private final int mMaxScrimAlpha;
+    private final Paint mPaint;
+
+    // Mid point where the alpha changes
+    private int mMidAlpha;
+    private float mMidProgress;
+
+    private float mShiftRange;
+
+    private final float mShelfOffset;
+    private float mTopOffset;
+    private float mShelfTop;
+    private float mShelfTopAtThreshold;
+
+    private int mShelfColor;
+    private int mRemainingScreenColor;
+
+    private final Path mTempPath = new Path();
+    private final Path mRemainingScreenPath = new Path();
+    private boolean mRemainingScreenPathValid = false;
+
+    public ShelfScrimView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mMaxScrimAlpha = Math.round(OVERVIEW.getWorkspaceScrimAlpha(mLauncher) * 255);
+
+        mEndAlpha = Color.alpha(mEndScrim);
+        mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius);
+        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+        mShelfOffset = context.getResources().getDimension(R.dimen.shelf_surface_offset);
+        // Just assume the easiest UI for now, until we have the proper layout information.
+        mDrawingFlatColor = true;
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mRemainingScreenPathValid = false;
+    }
+
+    @Override
+    public void reInitUi() {
+        DeviceProfile dp = mLauncher.getDeviceProfile();
+        mDrawingFlatColor = dp.isVerticalBarLayout();
+
+        if (!mDrawingFlatColor) {
+            mRemainingScreenPathValid = false;
+            mShiftRange = mLauncher.getAllAppsController().getShiftRange();
+
+            mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
+            mMidAlpha = mMidProgress >= 1 ? 0
+                    : Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
+
+            mTopOffset = dp.getInsets().top - mShelfOffset;
+            mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
+            updateColors();
+        }
+        updateDragHandleAlpha();
+        invalidate();
+    }
+
+    @Override
+    public void updateColors() {
+        super.updateColors();
+        if (mDrawingFlatColor) {
+            mDragHandleOffset = 0;
+            return;
+        }
+
+        mDragHandleOffset = mShelfOffset - mDragHandleSize;
+        if (mProgress >= SCRIM_CATCHUP_THRESHOLD) {
+            mShelfTop = mShiftRange * mProgress + mTopOffset;
+        } else {
+            mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius,
+                    mShelfTopAtThreshold);
+        }
+
+        if (mProgress >= 1) {
+            mRemainingScreenColor = 0;
+            mShelfColor = 0;
+        } else if (mProgress >= mMidProgress) {
+            mRemainingScreenColor = 0;
+
+            int alpha = Math.round(Utilities.mapToRange(
+                    mProgress, mMidProgress, 1, mMidAlpha, 0, ACCEL));
+            mShelfColor = setAlphaComponent(mEndScrim, alpha);
+        } else {
+            mDragHandleOffset += mShiftRange * (mMidProgress - mProgress);
+
+            // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
+            int alpha = Math.round(
+                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha,
+                            (float) mMidAlpha, Interpolators.clampToProgress(ACCEL, 0.5f, 1f)));
+            mShelfColor = setAlphaComponent(mEndScrim, alpha);
+
+            int remainingScrimAlpha = Math.round(
+                    Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha,
+                            (float) 0, LINEAR));
+            mRemainingScreenColor = setAlphaComponent(mScrimColor, remainingScrimAlpha);
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        drawBackground(canvas);
+        drawDragHandle(canvas);
+    }
+
+    private void drawBackground(Canvas canvas) {
+        if (mDrawingFlatColor) {
+            if (mCurrentFlatColor != 0) {
+                canvas.drawColor(mCurrentFlatColor);
+            }
+            return;
+        }
+
+        if (Color.alpha(mShelfColor) == 0) {
+            return;
+        } else if (mProgress <= 0) {
+            canvas.drawColor(mShelfColor);
+            return;
+        }
+
+        int height = getHeight();
+        int width = getWidth();
+        // Draw the scrim over the remaining screen if needed.
+        if (mRemainingScreenColor != 0) {
+            if (!mRemainingScreenPathValid) {
+                mTempPath.reset();
+                // Using a arbitrary '+10' in the bottom to avoid any left-overs at the
+                // corners due to rounding issues.
+                mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10,
+                        mRadius, mRadius, Direction.CW);
+                mRemainingScreenPath.reset();
+                mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW);
+                mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE);
+            }
+
+            float offset = height - mRadius - mShelfTop;
+            canvas.translate(0, -offset);
+            mPaint.setColor(mRemainingScreenColor);
+            canvas.drawPath(mRemainingScreenPath, mPaint);
+            canvas.translate(0, offset);
+        }
+
+        mPaint.setColor(mShelfColor);
+        canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
new file mode 100644
index 0000000..41626c6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.TaskSystemShortcut;
+import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.IconView.OnScaleUpdateListener;
+
+/**
+ * Contains options for a recent task when long-pressing its icon.
+ */
+public class TaskMenuView extends AbstractFloatingView {
+
+    private static final Rect sTempRect = new Rect();
+
+    /** Note that these will be shown in order from top to bottom, if available for the task. */
+    public static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
+            new TaskSystemShortcut.AppInfo(),
+            new TaskSystemShortcut.SplitScreen(),
+            new TaskSystemShortcut.Pin(),
+            new TaskSystemShortcut.Install(),
+    };
+
+    private final OnScaleUpdateListener mTaskViewIconScaleListener = new OnScaleUpdateListener() {
+        @Override
+        public void onScaleUpdate(float scale) {
+            final Drawable drawable = mTaskIcon.getDrawable();
+            if (drawable instanceof FastBitmapDrawable) {
+                if (scale != ((FastBitmapDrawable) drawable).getScale()) {
+                    mMenuIconDrawable.setScale(scale);
+                }
+            }
+        }
+    };
+
+    private final OnScaleUpdateListener mMenuIconScaleListener = new OnScaleUpdateListener() {
+        @Override
+        public void onScaleUpdate(float scale) {
+            final Drawable taskViewDrawable = mTaskView.getIconView().getDrawable();
+            if (taskViewDrawable instanceof FastBitmapDrawable) {
+                final float currentScale = ((FastBitmapDrawable) taskViewDrawable).getScale();
+                if (currentScale != scale) {
+                    ((FastBitmapDrawable) taskViewDrawable).setScale(scale);
+                }
+            }
+        }
+    };
+
+    private static final int REVEAL_OPEN_DURATION = 150;
+    private static final int REVEAL_CLOSE_DURATION = 100;
+
+    private final float mThumbnailTopMargin;
+    private BaseDraggingActivity mActivity;
+    private TextView mTaskName;
+    private IconView mTaskIcon;
+    private AnimatorSet mOpenCloseAnimator;
+    private TaskView mTaskView;
+    private LinearLayout mOptionLayout;
+    private FastBitmapDrawable mMenuIconDrawable;
+
+    public TaskMenuView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        mActivity = BaseDraggingActivity.fromContext(context);
+        mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTaskName = findViewById(R.id.task_name);
+        mTaskIcon = findViewById(R.id.task_icon);
+        mOptionLayout = findViewById(R.id.menu_option_layout);
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            BaseDragLayer dl = mActivity.getDragLayer();
+            if (!dl.isEventOverView(this, ev)) {
+                // TODO: log this once we have a new container type for it?
+                close(true);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        if (animate) {
+            animateClose();
+        } else {
+            closeComplete();
+        }
+    }
+
+    @Override
+    public void logActionCommand(int command) {
+        // TODO
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        // Remove all scale listeners when menu is removed
+        mTaskView.getIconView().removeUpdateScaleListener(mTaskViewIconScaleListener);
+        mTaskIcon.removeUpdateScaleListener(mMenuIconScaleListener);
+    }
+
+    @Override
+    protected boolean isOfType(int type) {
+        return (type & TYPE_TASK_MENU) != 0;
+    }
+
+    public void setPosition(float x, float y) {
+        setX(x);
+        setY(y + mThumbnailTopMargin);
+    }
+
+    public static TaskMenuView showForTask(TaskView taskView) {
+        BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
+        final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
+                        R.layout.task_menu, activity.getDragLayer(), false);
+        return taskMenuView.populateAndShowForTask(taskView) ? taskMenuView : null;
+    }
+
+    private boolean populateAndShowForTask(TaskView taskView) {
+        if (isAttachedToWindow()) {
+            return false;
+        }
+        mActivity.getDragLayer().addView(this);
+        mTaskView = taskView;
+        addMenuOptions(mTaskView);
+        orientAroundTaskView(mTaskView);
+        post(this::animateOpen);
+        return true;
+    }
+
+    private void addMenuOptions(TaskView taskView) {
+        Drawable icon = taskView.getTask().icon.getConstantState().newDrawable();
+        mTaskIcon.setDrawable(icon);
+        mTaskIcon.setOnClickListener(v -> close(true));
+        mTaskName.setText(TaskUtils.getTitle(getContext(), taskView.getTask()));
+        mTaskName.setOnClickListener(v -> close(true));
+
+        // Set the icons to match scale by listening to each other's changes
+        mMenuIconDrawable = icon instanceof FastBitmapDrawable ? (FastBitmapDrawable) icon : null;
+        taskView.getIconView().addUpdateScaleListener(mTaskViewIconScaleListener);
+        mTaskIcon.addUpdateScaleListener(mMenuIconScaleListener);
+
+        // Move the icon and text up half an icon size to lay over the TaskView
+        LinearLayout.LayoutParams params =
+                (LinearLayout.LayoutParams) mTaskIcon.getLayoutParams();
+        params.topMargin = (int) -mThumbnailTopMargin;
+        mTaskIcon.setLayoutParams(params);
+
+        for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
+            OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, taskView);
+            if (onClickListener != null) {
+                addMenuOption(menuOption, onClickListener);
+            }
+        }
+    }
+
+    private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) {
+        ViewGroup menuOptionView = (ViewGroup) mActivity.getLayoutInflater().inflate(
+                R.layout.task_view_menu_option, this, false);
+        menuOptionView.findViewById(R.id.icon).setBackgroundResource(menuOption.iconResId);
+        ((TextView) menuOptionView.findViewById(R.id.text)).setText(menuOption.labelResId);
+        menuOptionView.setOnClickListener(onClickListener);
+        mOptionLayout.addView(menuOptionView);
+    }
+
+    private void orientAroundTaskView(TaskView taskView) {
+        measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskView, sTempRect);
+        Rect insets = mActivity.getDragLayer().getInsets();
+        BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
+        params.width = taskView.getMeasuredWidth();
+        params.gravity = Gravity.START;
+        setLayoutParams(params);
+        setScaleX(taskView.getScaleX());
+        setScaleY(taskView.getScaleY());
+        setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top);
+    }
+
+    private void animateOpen() {
+        animateOpenOrClosed(false);
+        mIsOpen = true;
+    }
+
+    private void animateClose() {
+        animateOpenOrClosed(true);
+    }
+
+    private void animateOpenOrClosed(boolean closing) {
+        if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
+            mOpenCloseAnimator.end();
+        }
+        mOpenCloseAnimator = LauncherAnimUtils.createAnimatorSet();
+
+        final Animator revealAnimator = createOpenCloseOutlineProvider()
+                .createRevealAnimator(this, closing);
+        revealAnimator.setInterpolator(Interpolators.DEACCEL);
+        mOpenCloseAnimator.play(revealAnimator);
+        mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA,
+                closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA));
+        mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                setVisibility(VISIBLE);
+            }
+
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                if (closing) {
+                    closeComplete();
+                }
+            }
+        });
+        mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1));
+        mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION);
+        mOpenCloseAnimator.start();
+    }
+
+    private void closeComplete() {
+        mIsOpen = false;
+        mActivity.getDragLayer().removeView(this);
+    }
+
+    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
+        float radius = getResources().getDimension(R.dimen.task_corner_radius);
+        Rect fromRect = new Rect(0, 0, getWidth(), 0);
+        Rect toRect = new Rect(0, 0, getWidth(), getHeight());
+        return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
new file mode 100644
index 0000000..7223f97
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LightingColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.Property;
+import android.view.View;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
+import com.android.quickstep.TaskOverlayFactory;
+import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+/**
+ * A task in the Recents view.
+ */
+public class TaskThumbnailView extends View {
+
+    private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
+    private static final LightingColorFilter[] sHighlightFilterCache = new LightingColorFilter[256];
+
+    public static final Property<TaskThumbnailView, Float> DIM_ALPHA =
+            new FloatProperty<TaskThumbnailView>("dimAlpha") {
+                @Override
+                public void setValue(TaskThumbnailView thumbnail, float dimAlpha) {
+                    thumbnail.setDimAlpha(dimAlpha);
+                }
+
+                @Override
+                public Float get(TaskThumbnailView thumbnailView) {
+                    return thumbnailView.mDimAlpha;
+                }
+            };
+
+    private final float mCornerRadius;
+
+    private final BaseActivity mActivity;
+    private final TaskOverlay mOverlay;
+    private final boolean mIsDarkTextTheme;
+    private final Paint mPaint = new Paint();
+    private final Paint mBackgroundPaint = new Paint();
+
+    private final Matrix mMatrix = new Matrix();
+
+    private float mClipBottom = -1;
+
+    private Task mTask;
+    private ThumbnailData mThumbnailData;
+    protected BitmapShader mBitmapShader;
+
+    private float mDimAlpha = 1f;
+    private float mDimAlphaMultiplier = 1f;
+
+    public TaskThumbnailView(Context context) {
+        this(context, null);
+    }
+
+    public TaskThumbnailView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
+        mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
+        mPaint.setFilterBitmap(true);
+        mBackgroundPaint.setColor(Color.WHITE);
+        mActivity = BaseActivity.fromContext(context);
+        mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
+    }
+
+    public void bind() {
+        mOverlay.reset();
+    }
+
+    /**
+     * Updates this thumbnail.
+     */
+    public void setThumbnail(Task task, ThumbnailData thumbnailData) {
+        mTask = task;
+        int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
+        mPaint.setColor(color);
+        mBackgroundPaint.setColor(color);
+
+        if (thumbnailData != null && thumbnailData.thumbnail != null) {
+            Bitmap bm = thumbnailData.thumbnail;
+            bm.prepareToDraw();
+            mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+            mPaint.setShader(mBitmapShader);
+            mThumbnailData = thumbnailData;
+            updateThumbnailMatrix();
+        } else {
+            mBitmapShader = null;
+            mThumbnailData = null;
+            mPaint.setShader(null);
+            mOverlay.reset();
+        }
+        updateThumbnailPaintFilter();
+    }
+
+    public void setDimAlphaMultipler(float dimAlphaMultipler) {
+        mDimAlphaMultiplier = dimAlphaMultipler;
+        setDimAlpha(mDimAlpha);
+    }
+
+    /**
+     * Sets the alpha of the dim layer on top of this view.
+     *
+     * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black.
+     */
+    public void setDimAlpha(float dimAlpha) {
+        mDimAlpha = dimAlpha;
+        updateThumbnailPaintFilter();
+    }
+
+    public float getDimAlpha() {
+        return mDimAlpha;
+    }
+
+    public Rect getInsets() {
+        if (mThumbnailData != null) {
+            return mThumbnailData.insets;
+        }
+        return new Rect();
+    }
+
+    public int getSysUiStatusNavFlags() {
+        if (mThumbnailData != null) {
+            int flags = 0;
+            flags |= (mThumbnailData.systemUiVisibility & SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0
+                    ? SystemUiController.FLAG_LIGHT_STATUS
+                    : SystemUiController.FLAG_DARK_STATUS;
+            flags |= (mThumbnailData.systemUiVisibility & SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
+                    ? SystemUiController.FLAG_LIGHT_NAV
+                    : SystemUiController.FLAG_DARK_NAV;
+            return flags;
+        }
+        return 0;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
+    }
+
+    public float getCornerRadius() {
+        return mCornerRadius;
+    }
+
+    public void drawOnCanvas(Canvas canvas, float x, float y, float width, float height,
+            float cornerRadius) {
+        // Draw the background in all cases, except when the thumbnail data is opaque
+        final boolean drawBackgroundOnly = mTask == null || mTask.isLocked || mBitmapShader == null
+                || mThumbnailData == null;
+        if (drawBackgroundOnly || mClipBottom > 0 || mThumbnailData.isTranslucent) {
+            canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
+            if (drawBackgroundOnly) {
+                return;
+            }
+        }
+
+        if (mClipBottom > 0) {
+            canvas.save();
+            canvas.clipRect(x, y, width, mClipBottom);
+            canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
+            canvas.restore();
+        } else {
+            canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
+        }
+    }
+
+    private void updateThumbnailPaintFilter() {
+        int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255);
+        if (mBitmapShader != null) {
+            LightingColorFilter filter = getDimmingColorFilter(mul, mIsDarkTextTheme);
+            mPaint.setColorFilter(filter);
+            mBackgroundPaint.setColorFilter(filter);
+        } else {
+            mPaint.setColorFilter(null);
+            mPaint.setColor(Color.argb(255, mul, mul, mul));
+        }
+        invalidate();
+    }
+
+    private void updateThumbnailMatrix() {
+        boolean rotate = false;
+        mClipBottom = -1;
+        if (mBitmapShader != null && mThumbnailData != null) {
+            float scale = mThumbnailData.scale;
+            Rect thumbnailInsets  = mThumbnailData.insets;
+            final float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
+                    (thumbnailInsets.left + thumbnailInsets.right) * scale;
+            final float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
+                    (thumbnailInsets.top + thumbnailInsets.bottom) * scale;
+
+            final float thumbnailScale;
+            final DeviceProfile profile = mActivity.getDeviceProfile();
+
+            if (getMeasuredWidth() == 0) {
+                // If we haven't measured , skip the thumbnail drawing and only draw the background
+                // color
+                thumbnailScale = 0f;
+            } else {
+                final Configuration configuration =
+                        getContext().getResources().getConfiguration();
+                // Rotate the screenshot if not in multi-window mode
+                rotate = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
+                        configuration.orientation != mThumbnailData.orientation &&
+                        !mActivity.isInMultiWindowModeCompat() &&
+                        mThumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
+                // Scale the screenshot to always fit the width of the card.
+                thumbnailScale = rotate
+                        ? getMeasuredWidth() / thumbnailHeight
+                        : getMeasuredWidth() / thumbnailWidth;
+            }
+
+            if (rotate) {
+                int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
+                mMatrix.setRotate(90 * rotationDir);
+                int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top;
+                int newTopInset = rotationDir == 1 ? thumbnailInsets.left : thumbnailInsets.right;
+                mMatrix.postTranslate(-newLeftInset * scale, -newTopInset * scale);
+                if (rotationDir == -1) {
+                    // Crop the right/bottom side of the screenshot rather than left/top
+                    float excessHeight = thumbnailWidth * thumbnailScale - getMeasuredHeight();
+                    mMatrix.postTranslate(0, -excessHeight);
+                }
+                // Move the screenshot to the thumbnail window (rotation moved it out).
+                if (rotationDir == 1) {
+                    mMatrix.postTranslate(mThumbnailData.thumbnail.getHeight(), 0);
+                } else {
+                    mMatrix.postTranslate(0, mThumbnailData.thumbnail.getWidth());
+                }
+            } else {
+                mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
+                        -mThumbnailData.insets.top * scale);
+            }
+            mMatrix.postScale(thumbnailScale, thumbnailScale);
+            mBitmapShader.setLocalMatrix(mMatrix);
+
+            float bitmapHeight = Math.max((rotate ? thumbnailWidth : thumbnailHeight)
+                    * thumbnailScale, 0);
+            if (Math.round(bitmapHeight) < getMeasuredHeight()) {
+                mClipBottom = bitmapHeight;
+            }
+            mPaint.setShader(mBitmapShader);
+        }
+
+        if (rotate) {
+            // The overlay doesn't really work when the screenshot is rotated, so don't add it.
+            mOverlay.reset();
+        } else {
+            mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix);
+        }
+        invalidate();
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        updateThumbnailMatrix();
+    }
+
+    private static LightingColorFilter getDimmingColorFilter(int intensity, boolean shouldLighten) {
+        intensity = Utilities.boundToRange(intensity, 0, 255);
+        if (intensity == 255) {
+            return null;
+        }
+        if (shouldLighten) {
+            if (sHighlightFilterCache[intensity] == null) {
+                int colorAdd = 255 - intensity;
+                sHighlightFilterCache[intensity] = new LightingColorFilter(
+                        Color.argb(255, intensity, intensity, intensity),
+                        Color.argb(255, colorAdd, colorAdd, colorAdd));
+            }
+            return sHighlightFilterCache[intensity];
+        } else {
+            if (sDimFilterCache[intensity] == null) {
+                sDimFilterCache[intensity] = new LightingColorFilter(
+                        Color.argb(255, intensity, intensity, intensity), 0);
+            }
+            return sDimFilterCache[intensity];
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
new file mode 100644
index 0000000..ee542d5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import static android.widget.Toast.LENGTH_SHORT;
+
+import static com.android.launcher3.BaseActivity.fromContext;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.Log;
+import android.util.Property;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.Toast;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.TaskSystemShortcut;
+import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.RecentsView.PageCallbacks;
+import com.android.quickstep.views.RecentsView.ScrollState;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.util.function.Consumer;
+
+/**
+ * A task in the Recents view.
+ */
+public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
+
+    private static final String TAG = TaskView.class.getSimpleName();
+
+    /** A curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+    private static final TimeInterpolator CURVE_INTERPOLATOR
+            = x -> (float) -Math.cos(x * Math.PI) / 2f + .5f;
+
+    /**
+     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
+     * In the resting position of the carousel, the adjacent pages have about half this scrim.
+     */
+    public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
+
+    /**
+     * How much to scale down pages near the edge of the screen.
+     */
+    private static final float EDGE_SCALE_DOWN_FACTOR = 0.03f;
+
+    public static final long SCALE_ICON_DURATION = 120;
+    private static final long DIM_ANIM_DURATION = 700;
+
+    public static final Property<TaskView, Float> ZOOM_SCALE =
+            new FloatProperty<TaskView>("zoomScale") {
+                @Override
+                public void setValue(TaskView taskView, float v) {
+                    taskView.setZoomScale(v);
+                }
+
+                @Override
+                public Float get(TaskView taskView) {
+                    return taskView.mZoomScale;
+                }
+            };
+
+    private static FloatProperty<TaskView> FOCUS_TRANSITION =
+            new FloatProperty<TaskView>("focusTransition") {
+        @Override
+        public void setValue(TaskView taskView, float v) {
+            taskView.setIconAndDimTransitionProgress(v);
+        }
+
+        @Override
+        public Float get(TaskView taskView) {
+            return taskView.mFocusTransitionProgress;
+        }
+    };
+
+    private final OnAttachStateChangeListener mTaskMenuStateListener =
+            new OnAttachStateChangeListener() {
+                @Override
+                public void onViewAttachedToWindow(View view) {
+                }
+
+                @Override
+                public void onViewDetachedFromWindow(View view) {
+                    if (mMenuView != null) {
+                        mMenuView.removeOnAttachStateChangeListener(this);
+                        mMenuView = null;
+                    }
+                }
+            };
+
+    private Task mTask;
+    private TaskThumbnailView mSnapshotView;
+    private TaskMenuView mMenuView;
+    private IconView mIconView;
+    private float mCurveScale;
+    private float mZoomScale;
+
+    private Animator mIconAndDimAnimator;
+    private float mFocusTransitionProgress = 1;
+
+    public TaskView(Context context) {
+        this(context, null);
+    }
+
+    public TaskView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setOnClickListener((view) -> {
+            if (getTask() == null) {
+                return;
+            }
+            launchTask(true /* animate */);
+            fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
+                    Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
+                    TaskUtils.getLaunchComponentKeyForTask(getTask().key));
+        });
+        setOutlineProvider(new TaskOutlineProvider(getResources()));
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mSnapshotView = findViewById(R.id.snapshot);
+        mIconView = findViewById(R.id.icon);
+    }
+
+    /**
+     * Updates this task view to the given {@param task}.
+     */
+    public void bind(Task task) {
+        if (mTask != null) {
+            mTask.removeCallback(this);
+        }
+        mTask = task;
+        mSnapshotView.bind();
+        task.addCallback(this);
+        setContentDescription(task.titleDescription);
+    }
+
+    public Task getTask() {
+        return mTask;
+    }
+
+    public TaskThumbnailView getThumbnail() {
+        return mSnapshotView;
+    }
+
+    public IconView getIconView() {
+        return mIconView;
+    }
+
+    public void launchTask(boolean animate) {
+        launchTask(animate, (result) -> {
+            if (!result) {
+                notifyTaskLaunchFailed(TAG);
+            }
+        }, getHandler());
+    }
+
+    public void launchTask(boolean animate, Consumer<Boolean> resultCallback,
+            Handler resultCallbackHandler) {
+        if (mTask != null) {
+            final ActivityOptions opts;
+            if (animate) {
+                opts = ((BaseDraggingActivity) fromContext(getContext()))
+                        .getActivityLaunchOptions(this);
+            } else {
+                opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
+            }
+            ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync(mTask.key,
+                    opts, resultCallback, resultCallbackHandler);
+        }
+    }
+
+    @Override
+    public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData) {
+        mSnapshotView.setThumbnail(task, thumbnailData);
+        mIconView.setDrawable(task.icon);
+        mIconView.setOnClickListener(icon -> showTaskMenu());
+        mIconView.setOnLongClickListener(icon -> {
+            requestDisallowInterceptTouchEvent(true);
+            return showTaskMenu();
+        });
+    }
+
+    private boolean showTaskMenu() {
+        getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
+        mMenuView = TaskMenuView.showForTask(this);
+        if (mMenuView != null) {
+            mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
+        }
+        return mMenuView != null;
+    }
+
+    @Override
+    public void onTaskDataUnloaded() {
+        mSnapshotView.setThumbnail(null, null);
+        mIconView.setDrawable(null);
+        mIconView.setOnLongClickListener(null);
+    }
+
+    @Override
+    public void onTaskWindowingModeChanged() {
+        // Do nothing
+    }
+
+    private void setIconAndDimTransitionProgress(float progress) {
+        mFocusTransitionProgress = progress;
+        mSnapshotView.setDimAlphaMultipler(progress);
+        float scale = FAST_OUT_SLOW_IN.getInterpolation(Utilities.boundToRange(
+                progress * DIM_ANIM_DURATION / SCALE_ICON_DURATION,  0, 1));
+        mIconView.setScaleX(scale);
+        mIconView.setScaleY(scale);
+    }
+
+    public void animateIconScaleAndDimIntoView() {
+        if (mIconAndDimAnimator != null) {
+            mIconAndDimAnimator.cancel();
+        }
+        mIconAndDimAnimator = ObjectAnimator.ofFloat(this, FOCUS_TRANSITION, 1);
+        mIconAndDimAnimator.setDuration(DIM_ANIM_DURATION).setInterpolator(LINEAR);
+        mIconAndDimAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mIconAndDimAnimator = null;
+            }
+        });
+        mIconAndDimAnimator.start();
+    }
+
+    protected void setIconScaleAndDim(float iconScale) {
+        if (mIconAndDimAnimator != null) {
+            mIconAndDimAnimator.cancel();
+        }
+        setIconAndDimTransitionProgress(iconScale);
+    }
+
+    public void resetVisualProperties() {
+        setZoomScale(1);
+        setTranslationX(0f);
+        setTranslationY(0f);
+        setTranslationZ(0);
+        setAlpha(1f);
+        setIconScaleAndDim(1);
+    }
+
+    @Override
+    public void onPageScroll(ScrollState scrollState) {
+        float curveInterpolation =
+                CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
+
+        mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
+        setCurveScale(getCurveScaleForCurveInterpolation(curveInterpolation));
+
+        if (mMenuView != null) {
+            mMenuView.setPosition(getX() - getRecentsView().getScrollX(), getY());
+            mMenuView.setScaleX(getScaleX());
+            mMenuView.setScaleY(getScaleY());
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        setPivotX((right - left) * 0.5f);
+        setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
+    }
+
+    public static float getCurveScaleForInterpolation(float linearInterpolation) {
+        float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
+        return getCurveScaleForCurveInterpolation(curveInterpolation);
+    }
+
+    private static float getCurveScaleForCurveInterpolation(float curveInterpolation) {
+        return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
+    }
+
+    private void setCurveScale(float curveScale) {
+        mCurveScale = curveScale;
+        onScaleChanged();
+    }
+
+    public float getCurveScale() {
+        return mCurveScale;
+    }
+
+    public void setZoomScale(float adjacentScale) {
+        mZoomScale = adjacentScale;
+        onScaleChanged();
+    }
+
+    private void onScaleChanged() {
+        float scale = mCurveScale * mZoomScale;
+        setScaleX(scale);
+        setScaleY(scale);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        // TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
+        return false;
+    }
+
+    private static final class TaskOutlineProvider extends ViewOutlineProvider {
+
+        private final int mMarginTop;
+        private final float mRadius;
+
+        TaskOutlineProvider(Resources res) {
+            mMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+            mRadius = res.getDimension(R.dimen.task_corner_radius);
+        }
+
+        @Override
+        public void getOutline(View view, Outline outline) {
+            outline.setRoundRect(0, mMarginTop, view.getWidth(),
+                    view.getHeight(), mRadius);
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+
+        info.addAction(
+                new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task,
+                        getContext().getText(R.string.accessibility_close_task)));
+
+        final Context context = getContext();
+        final BaseDraggingActivity activity = fromContext(context);
+        for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
+            OnClickListener onClickListener = menuOption.getOnClickListener(activity, this);
+            if (onClickListener != null) {
+                info.addAction(new AccessibilityNodeInfo.AccessibilityAction(menuOption.labelResId,
+                        context.getText(menuOption.labelResId)));
+            }
+        }
+
+        final RecentsView recentsView = getRecentsView();
+        final AccessibilityNodeInfo.CollectionItemInfo itemInfo =
+                AccessibilityNodeInfo.CollectionItemInfo.obtain(
+                        0, 1, recentsView.getChildCount() - recentsView.indexOfChild(this) - 1, 1,
+                        false);
+        info.setCollectionItemInfo(itemInfo);
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (action == R.string.accessibility_close_task) {
+            getRecentsView().dismissTask(this, true /*animateTaskView*/,
+                    true /*removeTask*/);
+            return true;
+        }
+
+        for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
+            if (action == menuOption.labelResId) {
+                OnClickListener onClickListener = menuOption.getOnClickListener(
+                        fromContext(getContext()), this);
+                if (onClickListener != null) {
+                    onClickListener.onClick(this);
+                }
+                return true;
+            }
+        }
+
+        return super.performAccessibilityAction(action, arguments);
+    }
+
+    private RecentsView getRecentsView() {
+        return (RecentsView) getParent();
+    }
+
+    public void notifyTaskLaunchFailed(String tag) {
+        String msg = "Failed to launch task";
+        if (mTask != null) {
+            msg += " (task=" + mTask.key.baseIntent + " userId=" + mTask.key.userId + ")";
+        }
+        Log.w(tag, msg);
+        Toast.makeText(getContext(), R.string.activity_not_available, LENGTH_SHORT).show();
+    }
+}
diff --git a/res/animator-v23/discovery_bounce.xml b/res/animator-v23/discovery_bounce.xml
index 8d0e8fd..f554853 100644
--- a/res/animator-v23/discovery_bounce.xml
+++ b/res/animator-v23/discovery_bounce.xml
@@ -26,14 +26,14 @@
             android:fraction="0"
             android:value="1f" />
         <keyframe
-            android:fraction="0.346"
+            android:fraction="0.246"
             android:value="1f" />
         <keyframe
             android:fraction=".423"
             android:interpolator="@interpolator/disco_bounce"
-            android:value="0.9438f" />
+            android:value="0.9738f" />
         <keyframe
-            android:fraction="0.654"
+            android:fraction="0.754"
             android:interpolator="@interpolator/disco_bounce"
             android:value="1f" />
         <keyframe
diff --git a/res/drawable-v24/ic_info_shadow.xml b/res/drawable-v24/ic_setup_shadow.xml
similarity index 94%
rename from res/drawable-v24/ic_info_shadow.xml
rename to res/drawable-v24/ic_setup_shadow.xml
index 1fe2c46..10aeee6 100644
--- a/res/drawable-v24/ic_info_shadow.xml
+++ b/res/drawable-v24/ic_setup_shadow.xml
@@ -15,5 +15,5 @@
 -->
 <com.android.launcher3.graphics.ShadowDrawable
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_info_no_shadow"
+    android:src="@drawable/ic_setting"
     android:elevation="@dimen/drop_target_shadow_elevation" />
diff --git a/res/drawable/all_apps_search_divider.xml b/res/drawable/bg_all_apps_searchbox.xml
similarity index 78%
rename from res/drawable/all_apps_search_divider.xml
rename to res/drawable/bg_all_apps_searchbox.xml
index 99905e4..c324927 100644
--- a/res/drawable/all_apps_search_divider.xml
+++ b/res/drawable/bg_all_apps_searchbox.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2018 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.
@@ -13,8 +13,7 @@
      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="?android:attr/colorAccent" />
-    <size android:height="1dp" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="?attr/popupColorPrimary" />
+    <corners android:radius="2dp" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/all_apps_handle_landscape.xml b/res/drawable/drag_handle_indicator.xml
similarity index 77%
rename from res/drawable/all_apps_handle_landscape.xml
rename to res/drawable/drag_handle_indicator.xml
index 15518ff..b01b84a 100644
--- a/res/drawable/all_apps_handle_landscape.xml
+++ b/res/drawable/drag_handle_indicator.xml
@@ -15,25 +15,25 @@
 -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/dynamic_grid_min_page_indicator_size"
-    android:height="@dimen/dynamic_grid_min_page_indicator_size"
-    android:viewportWidth="48.0"
-    android:viewportHeight="48.0" >
+    android:width="@dimen/vertical_drag_handle_size"
+    android:height="@dimen/vertical_drag_handle_size"
+    android:viewportWidth="36.0"
+    android:viewportHeight="36.0" >
 
     <group
-        android:translateX="17.5"
-        android:translateY="17.5">
+        android:translateX="11.5"
+        android:translateY="11.5">
         <path
             android:pathData="M2 8.5L6.5 4L11 8.5"
             android:strokeColor="?attr/workspaceAmbientShadowColor"
-            android:strokeWidth="4"
+            android:strokeWidth="3.6"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
 
         <path
             android:pathData="M2 8.5L6.5 4L11 8.5"
             android:strokeColor="?attr/workspaceTextColor"
-            android:strokeWidth="2"
+            android:strokeWidth="1.8"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
         </group>
diff --git a/res/drawable/ic_close.xml b/res/drawable/ic_close.xml
index fc9ed49..8b2f55f 100644
--- a/res/drawable/ic_close.xml
+++ b/res/drawable/ic_close.xml
@@ -19,5 +19,5 @@
     android:viewportWidth="24.0">
   <path
       android:fillColor="@android:color/white"
-      android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+      android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41z" />
 </vector>
\ No newline at end of file
diff --git a/res/drawable/ic_info_no_shadow.xml b/res/drawable/ic_info_no_shadow.xml
index b5512c3..d816f12 100644
--- a/res/drawable/ic_info_no_shadow.xml
+++ b/res/drawable/ic_info_no_shadow.xml
@@ -16,12 +16,17 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="24dp"
         android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorPrimary" >
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?android:attr/textColorPrimary">
+
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,17L12,17c0.55,0,1-0.45,1-1v-4c0-0.55-0.45-1-1-1l0,0c-0.55,0-1,0.45-1,1v4C11,16.55,11.45,17,12,17z M12,2C6.48,
-        2,2,6.48,2,12s4.48,10,10,10s10-4.48,10-10S17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8s3.59-8,8-8s8,3.59,8,8S16.41,20,12,20zM12,
-        9.1L12,9.1c0.61,0,1.1-0.49,1.1-1.1l0,0c0-0.61-0.49-1.1-1.1-1.1l0,0c-0.61,0-1.1,0.49-1.1,1.1l0,0C10.9,8.61,11.39,9.1,12,9.1z"/>
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11 7 H 13 V 9 H 11 V 7 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M 11 11 H 13 V 17 H 11 V 11 Z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,2C6.48,2,2,6.48,2,12c0,5.52,4.48,10,10,10s10-4.48,10-10C22,6.48,17.52,2,12,2z M12,20c-4.41,0-8-3.59-8-8 c0-4.41,3.59-8,8-8s8,3.59,8,8C20,16.41,16.41,20,12,20z" />
 </vector>
diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml
index 08eba25..a83aab3 100644
--- a/res/drawable/ic_setting.xml
+++ b/res/drawable/ic_setting.xml
@@ -16,15 +16,28 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="@dimen/options_menu_icon_size"
         android:height="@dimen/options_menu_icon_size"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/textColorPrimary" >
     <path
-        android:fillColor="?android:attr/textColorPrimary"
-        android:pathData="M42.8,28.4l-3.88-2.9c0.06-0.5,0.08-1,0.08-1.52s-0.02-1.02-0.08-1.52l3.88-2.86c0.84-0.62,1.04-1.88,
-        0.48-2.82l-3.2-5.52c-0.56-0.96-1.76-1.4-2.72-1l-4.28,1.82c-0.96-0.74-2.02-1.36-3.14-1.84l-0.54-4.4C29.28,4.8,28.28,4,
-        27.18,4h-6.36c-1.1,0-2.1,0.8-2.22,1.84l-0.52,4.38c-1.14,0.48-2.2,1.1-3.16,1.84l-4.28-1.82c-0.96-0.4-2.16,0.04-2.72,
-        1l-3.2,5.52c-0.56,0.96-0.36,2.2,0.48,2.84l3.88,2.9C9.02,22.98,9,23.48,9,24s0.02,1.02,0.08,1.52L5.2,28.4c-0.84,0.62-1.04,
-        1.88-0.48,2.82l3.2,5.52c0.56,0.96,1.76,1.4,2.72,1l4.28-1.82c0.96,0.74,2.02,1.36,3.14,1.84l0.54,4.38C18.72,43.2,19.72,
-        44,20.82,44h6.36c1.1,0,2.08-0.8,2.22-1.84l0.54-4.38c1.12-0.48,2.18-1.1,3.14-1.84l4.28,1.82c0.96,0.4,2.16-0.04,
-        2.72-1l3.2-5.52C43.84,30.28,43.64,29.04,42.8,28.4z M24,31c-3.86,0-7-3.14-7-7s3.14-7,7-7s7,3.14,7,7S27.86,31,24,31z"/>
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.85,22.25h-3.7c-0.74,0-1.36-0.54-1.45-1.27l-0.27-1.89c-0.27-0.14-0.53-0.29-0.79-0.46l-1.8,0.72
+            c-0.7,0.26-1.47-0.03-1.81-0.65L2.2,15.53c-0.35-0.66-0.2-1.44,0.36-1.88l1.53-1.19c-0.01-0.15-0.02-0.3-0.02-0.46
+            c0-0.15,0.01-0.31,0.02-0.46l-1.52-1.19C1.98,9.9,1.83,9.09,2.2,8.47l1.85-3.19c0.34-0.62,1.11-0.9,1.79-0.63l1.81,0.73
+            c0.26-0.17,0.52-0.32,0.78-0.46l0.27-1.91c0.09-0.7,0.71-1.25,1.44-1.25h3.7c0.74,0,1.36,0.54,1.45,1.27l0.27,1.89
+            c0.27,0.14,0.53,0.29,0.79,0.46l1.8-0.72c0.71-0.26,1.48,0.03,1.82,0.65l1.84,3.18c0.36,0.66,0.2,1.44-0.36,1.88l-1.52,1.19
+            c0.01,0.15,0.02,0.3,0.02,0.46s-0.01,0.31-0.02,0.46l1.52,1.19c0.56,0.45,0.72,1.23,0.37,1.86l-1.86,3.22
+            c-0.34,0.62-1.11,0.9-1.8,0.63l-1.8-0.72c-0.26,0.17-0.52,0.32-0.78,0.46l-0.27,1.91C15.21,21.71,14.59,22.25,13.85,22.25z
+             M13.32,20.72c0,0.01,0,0.01,0,0.02L13.32,20.72z M10.68,20.7l0,0.02C10.69,20.72,10.69,20.71,10.68,20.7z M10.62,20.25h2.76
+            l0.37-2.55l0.53-0.22c0.44-0.18,0.88-0.44,1.34-0.78l0.45-0.34l2.38,0.96l1.38-2.4l-2.03-1.58l0.07-0.56
+            c0.03-0.26,0.06-0.51,0.06-0.78c0-0.27-0.03-0.53-0.06-0.78l-0.07-0.56l2.03-1.58l-1.39-2.4l-2.39,0.96l-0.45-0.35
+            c-0.42-0.32-0.87-0.58-1.33-0.77L13.75,6.3l-0.37-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7,8.84,6.95,8.38,7.3L7.93,7.63
+            L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47,6.06,11.74,6.06,12c0,0.26,0.02,0.53,0.06,0.78l0.07,0.56l-2.03,1.58
+            l1.38,2.4l2.39-0.96l0.45,0.35c0.43,0.33,0.86,0.58,1.33,0.77l0.53,0.22L10.62,20.25z M18.22,17.72c0,0.01-0.01,0.02-0.01,0.03
+            L18.22,17.72z M5.77,17.71l0.01,0.02C5.78,17.72,5.77,17.71,5.77,17.71z M3.93,9.47L3.93,9.47C3.93,9.47,3.93,9.47,3.93,9.47z
+             M18.22,6.27c0,0.01,0.01,0.02,0.01,0.02L18.22,6.27z M5.79,6.25L5.78,6.27C5.78,6.27,5.79,6.26,5.79,6.25z M13.31,3.28
+            c0,0.01,0,0.01,0,0.02L13.31,3.28z M10.69,3.26l0,0.02C10.69,3.27,10.69,3.27,10.69,3.26z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M8.5,12a3.5,3.5 0 1,0 7,0a3.5,3.5 0 1,0 -7,0"/>
 </vector>
diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml
index 2a86e10..37632d1 100644
--- a/res/drawable/ic_uninstall_no_shadow.xml
+++ b/res/drawable/ic_uninstall_no_shadow.xml
@@ -21,6 +21,11 @@
         android:tint="?android:attr/textColorPrimary" >
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6,19c0,1.1,0.9,2,2,2h8c1.1,0,2-0.9,2-2V7H6V19z M18,4h-2.5l-0.71-0.71C14.61,3.11,14.35,3,14.09,
-        3H9.9C9.64,3,9.38,3.11,9.2,3.29L8.49,4h-2.5c-0.55,0-1,0.45-1,1s0.45,1,1,1h12c0.55,0,1-0.45,1-1C19,4.45,18.55,4,18,4L18,4z"/>
+        android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4H15z M17,19H7V6h10V19z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M 9 8 H 11 V 17 H 9 V 8 Z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M 13 8 H 15 V 17 H 13 V 8 Z" />
 </vector>
diff --git a/res/drawable/ic_wallpaper.xml b/res/drawable/ic_wallpaper.xml
index 0c5a125..7fd9340 100644
--- a/res/drawable/ic_wallpaper.xml
+++ b/res/drawable/ic_wallpaper.xml
@@ -16,14 +16,11 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="@dimen/options_menu_icon_size"
         android:height="@dimen/options_menu_icon_size"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
     <path
         android:fillColor="?android:attr/textColorPrimary"
-        android:pathData="M8,8h13c0.56,0,1-0.44,1-1V5c0-0.56-0.44-1-1-1H8C5.8,4,4,5.8,4,8v13c0,0.56,0.44,1,1,1h2c0.56,0,1-0.44,
-        1-1V8zM18.44,27.96L12,36h24l-4.4-5.86c-0.8-1.06-2.4-1.06-3.2,0l-2.46,3.28l-4.38-5.46C20.76,26.96,19.24,26.96,18.44,27.96z M34,
-        17c0-1.66-1.34-3-3-3s-3,1.34-3,3s1.34,3,3,3S34,18.66,34,17z M40,4H27c-0.56,0-1,0.44-1,1v2c0,0.56,0.44,1,1,1h13v13c0,
-        0.56,0.44,1,1,1h2c0.56,0,1-0.44,1-1V8C44,5.8,42.2,4,40,4z M40,40H27c-0.56,0-1,0.44-1,1v2c0,0.56,0.44,1,1,1h13c2.2,
-        0,4-1.8,4-4V27c0-0.56-0.44-1-1-1h-2c-0.56,0-1,0.44-1,1V40z M7,26H5c-0.56,0-1,0.44-1,1v13c0,2.2,1.8,4,4,4h13c0.56,0,1-0.44,
-        1-1v-2c0-0.56-0.44-1-1-1H8V27C8,26.44,7.56,26,7,26z"/>
+        android:pathData="M9,12.71l2.14,2.58l3-3.87L18,16.57H6L9,12.71z M5,5h6V3H5C3.9,3,3,3.9,3,5v6h2V5z M19,19h-6v2h6c1.1,0,2-0.9,2-2v-6h-2V19z
+            M5,19v-6H3v6c0,1.1,0.9,2,2,2h6v-2H5z M19,5v6h2V5c0-1.1-0.9-2-2-2h-6v2H19z M16,9c0.55,0,1-0.45,1-1s-0.45-1-1-1
+            c-0.55,0-1,0.45-1,1S15.45,9,16,9z"/>
 </vector>
diff --git a/res/drawable/ic_widget.xml b/res/drawable/ic_widget.xml
index 4bb23b3..3ebbb68 100644
--- a/res/drawable/ic_widget.xml
+++ b/res/drawable/ic_widget.xml
@@ -16,11 +16,10 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="@dimen/options_menu_icon_size"
         android:height="@dimen/options_menu_icon_size"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
     <path
         android:fillColor="?android:attr/textColorPrimary"
-        android:pathData="M26,28v12c0,1,0.8,2,2,2h12c1,0,2-1,2-2V28c0-1.2-1-2-2-2H28C26.8,26,26,26.8,26,28z M8,42h12c1.2,0,2-1,2-2V28
-        c0-1.2-0.8-2-2-2H8c-1,0-2,0.8-2,2v12C6,41,7,42,8,42z M6,8v12c0,1.2,1,2,2,2h12c1.2,0,2-0.8,2-2V8c0-1-0.8-2-2-2H8C7,6,6,7,6,8z
-        M32.6,4.6l-8,8c-0.8,0.8-0.8,2,0,2.8l8,8c0.8,0.8,2,0.8,2.8,0l8-8c0.8-0.8,0.8-2,0-2.8l-8-8C34.6,3.8,33.4,3.8,32.6,4.6z"/>
+        android:pathData="M16.66,4.52l2.83,2.83l-2.83,2.83l-2.83-2.83L16.66,4.52 M9,5v4H5V5H9 M19,15v4h-4v-4H19 M9,15v4H5v-4H9 M16.66,1.69
+            L11,7.34L16.66,13l5.66-5.66L16.66,1.69L16.66,1.69z M11,3H3v8h8V7.34V3L11,3z M21,13h-4.34H13v8h8V13L21,13z M11,13H3v8h8V13L11,13z"/>
 </vector>
diff --git a/res/drawable/round_rect_primary.xml b/res/drawable/round_rect_primary.xml
index 9f8f4da..16310f8 100644
--- a/res/drawable/round_rect_primary.xml
+++ b/res/drawable/round_rect_primary.xml
@@ -17,5 +17,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <solid android:color="?android:attr/colorPrimary" />
-    <corners android:radius="8dp" />
+    <corners android:radius="@dimen/bg_round_rect_radius" />
 </shape>
diff --git a/res/drawable/all_apps_search_divider.xml b/res/drawable/top_round_rect_primary.xml
similarity index 67%
copy from res/drawable/all_apps_search_divider.xml
copy to res/drawable/top_round_rect_primary.xml
index 99905e4..1caaa02 100644
--- a/res/drawable/all_apps_search_divider.xml
+++ b/res/drawable/top_round_rect_primary.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2018 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.
@@ -15,6 +16,11 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
-    <solid android:color="?android:attr/colorAccent" />
-    <size android:height="1dp" />
-</shape>
\ No newline at end of file
+    <solid android:color="?android:attr/colorPrimary" />
+    <corners
+        android:topLeftRadius="@dimen/bg_round_rect_radius"
+        android:topRightRadius="@dimen/bg_round_rect_radius"
+        android:bottomLeftRadius="0dp"
+        android:bottomRightRadius="0dp"
+        />
+</shape>
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 2ce6b8c..02d793e 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -23,26 +23,16 @@
     android:layout_height="match_parent"
     android:clipChildren="true"
     android:clipToPadding="false"
-    android:focusable="true"
-    android:focusableInTouchMode="true"
+    android:focusable="false"
     android:saveEnabled="false" >
 
     <include layout="@layout/all_apps_rv_layout" />
 
-    <include layout="@layout/all_apps_fast_scroller" />
-
     <include layout="@layout/all_apps_floating_header" />
 
-    <!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
-     platform bug, which prevents using custom attributes in <include> tag -->
     <include
         android:id="@id/search_container_all_apps"
-        layout="?android:attr/keyboardLayout"/>
+        layout="@layout/search_container_all_apps"/>
 
-    <View
-        android:id="@+id/nav_bar_bg"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_alignParentBottom="true"
-        android:background="?attr/allAppsNavBarScrimColor" />
+    <include layout="@layout/all_apps_fast_scroller" />
 </com.android.launcher3.allapps.AllAppsContainerView>
\ No newline at end of file
diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml
index 3c19f8c..c353b36 100644
--- a/res/layout/all_apps_rv_layout.xml
+++ b/res/layout/all_apps_rv_layout.xml
@@ -22,5 +22,4 @@
     android:layout_below="@id/search_container_all_apps"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
-    android:focusable="true"
-    android:overScrollMode="never" />
+    android:focusable="true" />
diff --git a/res/layout/deep_shortcut.xml b/res/layout/deep_shortcut.xml
index 4a3db1f..4a2ad42 100644
--- a/res/layout/deep_shortcut.xml
+++ b/res/layout/deep_shortcut.xml
@@ -35,7 +35,6 @@
         android:textColor="?android:attr/textColorPrimary"
         android:fontFamily="sans-serif"
         launcher:layoutHorizontal="true"
-        launcher:deferShadowGeneration="true"
         launcher:iconDisplay="shortcut_popup"
         launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
 
diff --git a/res/layout/drop_target_bar.xml b/res/layout/drop_target_bar.xml
index d376bcf..2f21c60 100644
--- a/res/layout/drop_target_bar.xml
+++ b/res/layout/drop_target_bar.xml
@@ -32,18 +32,8 @@
         android:gravity="center"
         android:text="@string/remove_drop_target_label" />
 
-    <!-- App Info -->
-    <com.android.launcher3.InfoDropTarget
-        android:id="@+id/info_target_text"
-        style="@style/DropTargetButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="center"
-        android:text="@string/app_info_drop_target_label" />
-
     <!-- Uninstall target -->
-    <com.android.launcher3.UninstallDropTarget
+    <com.android.launcher3.SecondaryDropTarget
         android:id="@+id/uninstall_target_text"
         style="@style/DropTargetButton"
         android:layout_width="wrap_content"
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 73c0e52..00f0b5f 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -17,6 +17,7 @@
     android:theme="@style/HomeScreenElementTheme"
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto">
+
     <com.android.launcher3.CellLayout
         android:id="@+id/layout"
         android:layout_width="wrap_content"
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 314359b..304d012 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -18,7 +18,6 @@
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="?attr/workspaceStatusBarScrim"
     android:fitsSystemWindows="true">
 
     <com.android.launcher3.dragndrop.DragLayer
@@ -44,36 +43,35 @@
             layout="@layout/overview_panel"
             android:visibility="gone" />
 
-        <com.android.launcher3.views.AllAppsScrim
-            android:id="@+id/all_apps_scrim"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-
-        <!-- DO NOT CHANGE THE ID -->
-        <include
-            android:id="@+id/hotseat"
-            layout="@layout/hotseat"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-
         <!-- Keep these behind the workspace so that they are not visible when
          we go into AllApps -->
         <com.android.launcher3.pageindicators.WorkspacePageIndicator
             android:id="@+id/page_indicator"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/dynamic_grid_min_page_indicator_size"
+            android:layout_height="@dimen/vertical_drag_handle_size"
+            android:layout_gravity="bottom|center_horizontal"
             android:theme="@style/HomeScreenElementTheme" />
 
         <include
             android:id="@+id/drop_target_bar"
             layout="@layout/drop_target_bar" />
 
+        <include android:id="@+id/scrim_view"
+            layout="@layout/scrim_view" />
+
         <include
             android:id="@+id/apps_view"
             layout="@layout/all_apps"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
+
+        <!-- DO NOT CHANGE THE ID -->
+        <include
+            android:id="@+id/hotseat"
+            layout="@layout/hotseat"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
     </com.android.launcher3.dragndrop.DragLayer>
 
 </com.android.launcher3.LauncherRootView>
diff --git a/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml
new file mode 100644
index 0000000..20bb5b8
--- /dev/null
+++ b/res/layout/longpress_options_menu.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.OptionsPopupView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/deep_shortcuts_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:background="?attr/popupColorPrimary"
+    android:clipToPadding="false"
+    android:clipChildren="false"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:importantForAccessibility="yes"
+    android:orientation="vertical" />
diff --git a/res/layout/overview_panel.xml b/res/layout/overview_panel.xml
index c795b81..bdd5d23 100644
--- a/res/layout/overview_panel.xml
+++ b/res/layout/overview_panel.xml
@@ -14,61 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.uioverrides.OverviewPanel
+<Space
       xmlns:android="http://schemas.android.com/apk/res/android"
-      android:theme="@style/HomeScreenElementTheme"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_gravity="center_horizontal|bottom"
-      android:gravity="top"
-      android:orientation="horizontal">
-
-    <TextView
-        android:id="@+id/wallpaper_button"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:drawablePadding="4dp"
-        android:drawableTop="@drawable/ic_wallpaper"
-        android:drawableTint="?attr/workspaceTextColor"
-        android:fontFamily="sans-serif-condensed"
-        android:gravity="center_horizontal"
-        android:stateListAnimator="@animator/overview_button_anim"
-        android:text="@string/wallpaper_button_text"
-        android:textAllCaps="true"
-        android:textColor="?attr/workspaceTextColor"
-        android:textSize="12sp" />
-
-    <TextView
-        android:id="@+id/widget_button"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:drawablePadding="4dp"
-        android:drawableTop="@drawable/ic_widget"
-        android:drawableTint="?attr/workspaceTextColor"
-        android:fontFamily="sans-serif-condensed"
-        android:gravity="center_horizontal"
-        android:stateListAnimator="@animator/overview_button_anim"
-        android:text="@string/widget_button_text"
-        android:textAllCaps="true"
-        android:textColor="?attr/workspaceTextColor"
-        android:textSize="12sp" />
-
-    <TextView
-        android:id="@+id/settings_button"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:drawablePadding="4dp"
-        android:drawableTop="@drawable/ic_setting"
-        android:drawableTint="?attr/workspaceTextColor"
-        android:fontFamily="sans-serif-condensed"
-        android:gravity="center_horizontal"
-        android:stateListAnimator="@animator/overview_button_anim"
-        android:text="@string/settings_button_text"
-        android:textAllCaps="true"
-        android:textColor="?attr/workspaceTextColor"
-        android:textSize="12sp" />
-
-</com.android.launcher3.uioverrides.OverviewPanel>
\ No newline at end of file
+      android:layout_width="0dp"
+      android:layout_height="0dp" />
\ No newline at end of file
diff --git a/res/layout/widgets_bottom_sheet_scrim.xml b/res/layout/scrim_view.xml
similarity index 75%
copy from res/layout/widgets_bottom_sheet_scrim.xml
copy to res/layout/scrim_view.xml
index 6c6626c..a604d56 100644
--- a/res/layout/widgets_bottom_sheet_scrim.xml
+++ b/res/layout/scrim_view.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2018 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.
@@ -13,11 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<com.android.launcher3.graphics.GradientView
+<com.android.launcher3.views.ScrimView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/gradient_bg"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    launcher:layout_ignoreInsets="true" />
\ No newline at end of file
+    android:id="@+id/scrim_view" />
\ No newline at end of file
diff --git a/res/layout/search_container_all_apps.xml b/res/layout/search_container_all_apps.xml
index fc07002..fd9cb60 100644
--- a/res/layout/search_container_all_apps.xml
+++ b/res/layout/search_container_all_apps.xml
@@ -17,53 +17,22 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@id/search_container_all_apps"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/all_apps_search_bar_height"
-    android:layout_gravity="center|top"
-    android:layout_marginBottom="-8dp"
-    android:gravity="center|bottom"
-    android:paddingLeft="@dimen/dynamic_grid_edge_margin"
-    android:paddingRight="@dimen/dynamic_grid_edge_margin"
-    android:saveEnabled="false" >
-
-    <!--
-      Note: The following relation should always be true so that the shadows are aligned properly
-      search_box_input.layout_marginBottom
-            == search_divider.layout_marginBottom
-            == - (search_container.layout_marginBottom)
-            >= 5dp
-    -->
-    <com.android.launcher3.ExtendedEditText
-        android:id="@+id/search_box_input"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/all_apps_search_bar_field_height"
-        android:layout_gravity="bottom"
-        android:layout_marginBottom="8dp"
-        android:background="@android:color/transparent"
-        android:focusableInTouchMode="true"
-        android:gravity="center"
-        android:hint="@string/all_apps_search_bar_hint"
-        android:imeOptions="actionSearch|flagNoExtractUi"
-        android:inputType="text|textNoSuggestions|textCapWords"
-        android:maxLines="1"
-        android:saveEnabled="false"
-        android:scrollHorizontally="true"
-        android:singleLine="true"
-        android:textColor="?android:attr/textColorSecondary"
-        android:textColorHint="@drawable/all_apps_search_hint"
-        android:textSize="16sp" />
-
-    <!-- This needs to be a container with a view, to simulate a scrolling effect for the header.
-         We translate the header down, and its content up by the same amount, so that it gets
-         clipped by the parent, making it look like the divider was scrolled out of the view. -->
-    <FrameLayout
-        android:id="@+id/search_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_gravity="bottom"
-        android:layout_marginBottom="8dp" >
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="1dp"
-            android:background="@drawable/all_apps_search_divider"/>
-    </FrameLayout>
-</com.android.launcher3.allapps.search.AppsSearchContainerLayout>
\ No newline at end of file
+    android:layout_height="@dimen/all_apps_search_bar_field_height"
+    android:layout_centerHorizontal="true"
+    android:layout_gravity="top|center_horizontal"
+    android:background="@drawable/bg_all_apps_searchbox"
+    android:elevation="1dp"
+    android:focusableInTouchMode="true"
+    android:gravity="center"
+    android:hint="@string/all_apps_search_bar_hint"
+    android:imeOptions="actionSearch|flagNoExtractUi"
+    android:inputType="text|textNoSuggestions|textCapWords"
+    android:maxLines="1"
+    android:padding="8dp"
+    android:saveEnabled="false"
+    android:scrollHorizontally="true"
+    android:singleLine="true"
+    android:textColor="?android:attr/textColorSecondary"
+    android:textColorHint="@drawable/all_apps_search_hint"
+    android:textSize="16sp"
+    android:translationY="24dp" />
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 1888e22..04f3d02 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -34,7 +34,6 @@
         android:fontFamily="sans-serif"
         launcher:iconDisplay="shortcut_popup"
         launcher:layoutHorizontal="true"
-        launcher:deferShadowGeneration="true"
         android:focusable="false" />
 
     <View
diff --git a/res/layout/widgets_bottom_sheet.xml b/res/layout/widgets_bottom_sheet.xml
index e8c6961..6bf9048 100644
--- a/res/layout/widgets_bottom_sheet.xml
+++ b/res/layout/widgets_bottom_sheet.xml
@@ -20,7 +20,7 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:paddingTop="28dp"
-    android:background="?android:attr/colorPrimary"
+    android:background="@drawable/top_round_rect_primary"
     android:elevation="@dimen/deep_shortcuts_elevation"
     android:layout_gravity="bottom"
     android:theme="?attr/widgetsTheme">
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 1535299..f507a88 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -20,12 +20,7 @@
     android:orientation="vertical"
     android:theme="?attr/widgetsTheme" >
 
-    <com.android.launcher3.graphics.GradientView
-        android:id="@+id/gradient_bg"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <FrameLayout
+    <com.android.launcher3.views.TopRoundedCornerView
         android:id="@+id/container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -36,29 +31,22 @@
             android:id="@+id/widgets_list_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:clipToPadding="false"
-            />
+            android:clipToPadding="false" />
 
         <!-- Fast scroller popup -->
         <TextView
             android:id="@+id/fast_scroller_popup"
             style="@style/FastScrollerPopup"
-            android:layout_gravity="top|end"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentTop="true"
             android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
 
         <com.android.launcher3.views.RecyclerViewFastScroller
             android:id="@+id/fast_scroller"
             android:layout_width="@dimen/fastscroll_width"
             android:layout_height="match_parent"
-            android:layout_gravity="end"
+            android:layout_alignParentEnd="true"
+            android:layout_alignParentTop="true"
             android:layout_marginEnd="@dimen/fastscroll_end_margin" />
-
-        <View
-            android:id="@+id/nav_bar_bg"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_gravity="bottom"
-            android:background="?attr/allAppsNavBarScrimColor"
-            android:focusable="false"  />
-    </FrameLayout>
+    </com.android.launcher3.views.TopRoundedCornerView>
 </com.android.launcher3.widget.WidgetsFullSheet>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
index 4cd03ce..eec57a5 100644
--- a/res/layout/widgets_list_row_view.xml
+++ b/res/layout/widgets_list_row_view.xml
@@ -31,7 +31,6 @@
         android:layout_height="@dimen/widget_section_height"
         android:background="?android:attr/colorPrimary"
         android:drawablePadding="@dimen/widget_section_horizontal_padding"
-        android:ellipsize="end"
         android:focusable="true"
         android:gravity="start|center_vertical"
         android:paddingBottom="@dimen/widget_section_vertical_padding"
@@ -42,7 +41,6 @@
         android:textColor="?android:attr/textColorPrimary"
         android:textSize="16sp"
         android:textAlignment="viewStart"
-        launcher:deferShadowGeneration="true"
         launcher:iconDisplay="widget_section"
         launcher:iconSizeOverride="@dimen/widget_section_icon_size"
         launcher:layoutHorizontal="true" />
diff --git a/res/layout/work_tab_bottom_user_education_view.xml b/res/layout/work_tab_bottom_user_education_view.xml
index dc6854e..ba6a939 100644
--- a/res/layout/work_tab_bottom_user_education_view.xml
+++ b/res/layout/work_tab_bottom_user_education_view.xml
@@ -20,6 +20,7 @@
     android:layout_gravity="bottom"
     android:background="?android:attr/colorAccent"
     android:elevation="2dp"
+    android:focusable="true"
     android:orientation="horizontal">
 
   <ImageView
@@ -42,6 +43,7 @@
         android:layout_marginTop="12dp"
         android:layout_marginEnd="12dp"
         android:layout_gravity="right"
+        android:contentDescription="@string/bottom_work_tab_user_education_close_button"
         android:src="@drawable/ic_close"/>
 
     <TextView
diff --git a/res/layout/work_tab_footer.xml b/res/layout/work_tab_footer.xml
index 21ff55e..379e9d0 100644
--- a/res/layout/work_tab_footer.xml
+++ b/res/layout/work_tab_footer.xml
@@ -17,6 +17,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:focusable="true"
     android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_bottom_padding"
     android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
     android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 1ff9a2d..35539e3 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Kon geen programme kry wat by \"<xliff:g id="QUERY">%1$s</xliff:g>\" pas nie"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Soek meer programme"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Kennisgewings"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Raak en hou om \'n kortpad op te tel."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Niks meer spasie op die tuisskerm nie."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen plek meer in die Gunstelinge-laai nie"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Programmelys"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lys persoonlike programme"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lys werkprogramme"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Tuis"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwyder"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Vouer: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Legstukke"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Muurpapiere"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Home-instellings"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Tuis-instellings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gedeaktiveer deur jou administrateur"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Oorsig"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Laat toe dat tuisskerm gedraai word"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Wanneer foon gedraai word"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Huidige vertooninstelling laat nie rotasie toe nie"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Kennisgewingkolle"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Af"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Kennisgewingtoegang word benodig"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Skakel programkennisgewings vir <xliff:g id="NAME">%1$s</xliff:g> aan om kennisgewingkolle te sien"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Verander instellings"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Wys kennisgewingkolle"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Voeg ikoon by tuisskerm"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Vir nuwe programme"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Verander ikoon se vorm"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"op tuisskerm"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gebruik stelselverstek"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Sirkelvierkant"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laai tans af, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wag tans om te installeer"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-legstukke"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Legstukkelys"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Legstukkelys is toegemaak"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Voeg by tuisskerm"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Skuif item hierheen"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item is by tuisskerm gevoeg"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Skep vouer met: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Vouer geskep"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Skuif na tuisskerm"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Skuif skerm na links"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Skuif skerm na regs"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skerm is geskuif"</string>
     <string name="action_resize" msgid="1802976324781771067">"Verander grootte"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Vermeerder breedte"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Vermeerder hoogte"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Verminder hoogte"</string>
     <string name="widget_resized" msgid="9130327887929620">"Legstukgrootte is verander na breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Kortpaaie"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> kortpaaie vir <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> kortpaaie en <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> kennisgewings vir <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Kortpaaie en kennisgewings"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Maak toe"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Kennisgewing is toegemaak"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persoonlik"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Kry werkprogramme hier"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Elke werkprogram het \'n oranje kenteken en word deur jou organisasie veilig gehou. Skuif programme na jou Tuisskerm vir makliker toegang."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Elke werkprogram het \'n kenteken en word deur jou organisasie veilig gehou. Skuif programme na jou tuisskerm toe vir makliker toegang."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Bestuur deur jou organisasie"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Kennisgewings en programme is af"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Maak toe"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Toe"</string>
 </resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 67c26e7..921fbd9 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ተጨማሪ መተግበሪያዎች ይፈልጉ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ማሳወቂያዎች"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ።"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"</string>
     <string name="out_of_space" msgid="4691004494942118364">"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"የመተግበሪያዎች ዝርዝር"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"የግል መተግበሪያዎች ዝርዝር"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"የሥራ መተግበሪያዎች ዝርዝር"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"መነሻ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"አስወግድ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"አራግፍ"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"የግድግዳ ወረቀቶች"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"የመነሻ ቅንብሮች"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"በእርስዎ አስተዳዳሪ የተሰናከለ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"አጠቃላይ ዕይታ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"የመነሻ ማያ ገጽ ማሽከርከርን ይፍቀዱ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ስልኩ ሲዞር"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"የአሁኑ የማሳያ ቅንብር ማሽከርከርን አይፈቅድም"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"የማሳወቂያ ነጥቦች"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"በርቷል"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ጠፍቷል"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"የማሳወቂያ መዳረሻ ያስፈልጋል"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"የማሳወቂያ ነጥቦችን ለማሳየት የመተግብሪያ ማሳወቂያዎችን ለ<xliff:g id="NAME">%1$s</xliff:g> ያብሩ"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ቅንብሮችን ቀይር"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"የማሳወቂያ ነጥቦችን አሳይ"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"አዶ ወደ የመነሻ ማያ ገጽ አክል"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ለአዲስ መተግበሪያዎች"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"የአዶ ቅርፅ ለውጥ"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"በመነሻ ማያ ገጽ ላይ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"የሥርዓቱን ነባሪ ተጠቀም"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ካሬ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> በመውረድ ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቋል"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ለመጫን በመጠበቅ ላይ"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ንዑስ ፕሮግራሞች"</string>
+    <string name="widgets_list" msgid="796804551140113767">"የመግብሮች ዝርዝር"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"የመግብሮች ዝርዝር ተዘግቷል"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ወደ መነሻ ማያ ገጽ ያክሉ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ንጥልን ወደዚህ ውሰድ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ወደ መነሻ ማያ ገጽ ንጥል ታክሏል"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"አቃፊ ፍጠር ከዚህ ጋር፦ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"አቃፊ ተፈጥሮዋል"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ወደ መነሻ ማያ ገጽ አንቀሳቅስ"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"ማያ ገጽን ወደ ግራ አንቀሳቅስ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"ማያ ገጽን ወደ ቀኝ አንቀሳቅስ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ማያ ገጽ ተንቀሳቅሷል"</string>
     <string name="action_resize" msgid="1802976324781771067">"መጠን ቀይር"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"ስፋት ጨምር"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ቁመት ጨምር"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ቁመት ይቀንሱ"</string>
     <string name="widget_resized" msgid="9130327887929620">"የመግብር መጠን ወደ ስፋት <xliff:g id="NUMBER_0">%1$s</xliff:g> ቁመት <xliff:g id="NUMBER_1">%2$s</xliff:g> ተለውጧል"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"አቋራጮች"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> የ<xliff:g id="APP_NAME">%2$s</xliff:g> አቋራጮች"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> አቋራጮች እና <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ማሳወቂያዎች ለ<xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"አቋራጮች እና ማሳወቂያዎች"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"አሰናብት"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ማሳወቂያ ተሰናብቷል"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"የግል"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ሥራ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"የሥራ መገለጫ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"የስራ መተግበሪያዎችን እዚህ ያግኙ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"እያንዳንዱ የሥራ መተግበሪያ ብርቱካናማ ባጅ አለው እና በእርስዎ ድርጅት በኩል ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ያንቀሳቅሱ።"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"እያንዳንዱ የሥራ መተግበሪያ ባጅ አለው፣ እና በድርጅትዎ ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ይውሰዷቸው።"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"በእርስዎ ድርጅት የሚተዳደር"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ዝጋ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ዝግ"</string>
 </resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1b1d7ca..ecf32d4 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -24,13 +24,13 @@
     <string name="work_folder_name" msgid="3753320833950115786">"العمل"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"لم يتم تثبيت التطبيق."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"التطبيق ليس متاحًا"</string>
-    <string name="safemode_shortcut_error" msgid="9160126848219158407">"تم تعطيل التطبيق الذي تم تنزيله في الوضع الآمن"</string>
-    <string name="safemode_widget_error" msgid="4863470563535682004">"الأدوات معطلة في الوضع الآمن"</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"تم إيقاف التطبيق الذي تم تنزيله في الوضع الآمن"</string>
+    <string name="safemode_widget_error" msgid="4863470563535682004">"الأدوات غير مفعّلة في الوضع الآمن"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"الاختصار غير متاح"</string>
     <string name="home_screen" msgid="806512411299847073">"الشاشة الرئيسية"</string>
     <string name="custom_actions" msgid="3747508247759093328">"الإجراءات المخصّصة"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"المس مع الاستمرار لاختيار إحدى الأدوات."</string>
-    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"انقر نقرًا مزدوجًا مع الاستمرار لاختيار أداة أو استخدم الإجراءات المخصصة."</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"انقر مرّتين مع الاستمرار لاختيار أداة أو استخدم الإجراءات المخصصة."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏العرض %1$d الطول %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"انقر مع الاستمرار لإضافة العنصر يدويًا"</string>
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"لم يتم العثور على أي تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"البحث عن مزيد من التطبيقات"</string>
     <string name="notifications_header" msgid="1404149926117359025">"الإشعارات"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"انقر مع الاستمرار لاختيار اختصار."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"يمكنك النقر مرّتين مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"لا يوجد المزيد من الحقول في علبة المفضلة"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"قائمة التطبيقات"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"قائمة التطبيقات الشخصية"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"قائمة تطبيقات العمل"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"الرئيسية"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"إزالة"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"إلغاء التثبيت"</string>
@@ -59,7 +63,7 @@
     <string name="gadget_setup_text" msgid="8274003207686040488">"الإعداد"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"هذا تطبيق نظام وتتعذر إزالته."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"مجلد بدون اسم"</string>
-    <string name="disabled_app_label" msgid="6673129024321402780">"تم تعطيل <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="disabled_app_label" msgid="6673129024321402780">"تم إيقاف <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
       <item quantity="zero"><xliff:g id="APP_NAME_2">%1$s</xliff:g>، به <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> إشعار</item>
       <item quantity="two"><xliff:g id="APP_NAME_2">%1$s</xliff:g>، به إشعاران (<xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>)</item>
@@ -80,21 +84,21 @@
     <string name="widget_button_text" msgid="2880537293434387943">"الأدوات"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"الخلفيات"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"إعدادات الصفحة الرئيسية"</string>
-    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"عطَّل المشرف هذه الميزة"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"نظرة عامة"</string>
+    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"أوقف المشرف هذه الميزة"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"السماح بتدوير الشاشة الرئيسية"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"عند تدوير الهاتف"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"لا يسمح إعداد العرض الحالي بالتدوير"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"نقاط الإشعارات"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"قيد التشغيل"</string>
-    <string name="icon_badging_desc_off" msgid="5503319969924580241">"قيد الإيقاف"</string>
-    <string name="title_missing_notification_access" msgid="7503287056163941064">"يلزم تمكين الوصول إلى الإشعارات"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"غير مفعّل"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"يلزم تفعيل الوصول إلى الإشعارات"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"لعرض نقاط الإشعارات، يجب تشغيل إشعارات التطبيق في <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"تغيير الإعدادات"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"عرض نقاط الإشعارات"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"إضافة رمز إلى الشاشة الرئيسية"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"للتطبيقات الجديدة"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"تغيير شكل الرمز"</string>
-    <string name="icon_shape_system_default" msgid="1709762974822753030">"استخدام الإعداد الافتراضي للنظام"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"على الشاشة الرئيسية"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"استخدام الإعداد التلقائي للنظام"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"مربّع"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"رمز دائري مربّع"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"دائرة"</string>
@@ -108,6 +112,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"جارٍ تنزيل <xliff:g id="NAME">%1$s</xliff:g>، اكتمل <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> في انتظار التثبيت"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"أدوات <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"قائمة الأدوات"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"تم إغلاق قائمة الأدوات."</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"إضافة إلى الشاشة الرئيسية"</string>
     <string name="action_move_here" msgid="2170188780612570250">"نقل العنصر إلى هنا"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"تمت إضافة العنصر إلى الشاشة الرئيسية"</string>
@@ -123,9 +129,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"إنشاء مجلد يتضمن: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"تم إنشاء المجلد"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"نقل إلى الشاشة الرئيسية"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"نقل الشاشة إلى اليسار"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"نقل الشاشة إلى اليمين"</string>
-    <string name="screen_moved" msgid="266230079505650577">"تم نقل الشاشة"</string>
     <string name="action_resize" msgid="1802976324781771067">"تغيير حجم"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"زيادة العرض"</string>
     <string name="action_increase_height" msgid="459390020612501122">"زيادة الارتفاع"</string>
@@ -133,15 +136,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"تقليل الارتفاع"</string>
     <string name="widget_resized" msgid="9130327887929620">"تم تغيير حجم الأداة إلى العرض <xliff:g id="NUMBER_0">%1$s</xliff:g> والارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"الاختصارات"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> اختصار لتطبيق <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"هناك <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> اختصار و<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> إشعار عن <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"الاختصارات والإشعارات"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"تجاهل"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"تم تجاهل الإشعار"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصية"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"البحث عن تطبيقات العمل هنا"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"يحتوي كل تطبيق للعمل على شارة برتقالية اللون ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"يحتوي كل تطبيق للعمل على شارة ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول إليها."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"ملف شخصي للعمل تديره مؤسستك"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"الإشعارات والتطبيقات متوقفة."</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"إغلاق"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"تمّ الإغلاق"</string>
 </resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
new file mode 100644
index 0000000..b8e71a1
--- /dev/null
+++ b/res/values-as/strings.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
+    <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"কৰ্মস্থান"</string>
+    <string name="activity_not_found" msgid="8071924732094499514">"এপটো ইনষ্টল কৰা নহ\'ল।"</string>
+    <string name="activity_not_available" msgid="7456344436509528827">"এপটো নাই"</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনল\'ড কৰা এপটোক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ\'ল"</string>
+    <string name="safemode_widget_error" msgid="4863470563535682004">"ৱিজেটবোৰক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ\'ল"</string>
+    <string name="shortcut_not_available" msgid="2536503539825726397">"শ্বৰ্টকাট নাই"</string>
+    <string name="home_screen" msgid="806512411299847073">"গৃহ স্ক্ৰীণ"</string>
+    <string name="custom_actions" msgid="3747508247759093328">"উপযোগিতা অনুসৰি কৰা কাৰ্যবিলাক"</string>
+    <string name="long_press_widget_to_add" msgid="7699152356777458215">"কোনো ৱিজেট বাছনি কৰিবলৈ স্পৰ্শ কৰি থাকক।"</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"কোনো ৱিজেট বাছনি কৰিবলৈ অথবা উপযোগিতা অনুসৰি কাৰ্যবিলাক ব্য়ৱহাৰ কৰিবলৈ দুবাৰ টিপি থাকক।"</string>
+    <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d বহল x %2$d ওখ"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"মেনুৱেলভাৱে ৰাখিবলৈ স্পৰ্শ কৰি থাকক"</string>
+    <string name="place_automatically" msgid="8064208734425456485">"স্বয়ংক্ৰিয়ভাবে যোগ কৰক"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"এপসমূহ সন্ধান কৰক"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"এপসমূহ ল’ড কৰি থকা হৈছে…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"ৰ সৈতে মিলা কোনো এপ্ বিচাৰি পোৱা নগ\'ল"</string>
+    <string name="all_apps_search_market_message" msgid="1366263386197059176">"আৰু অধিক এপবোৰ সন্ধান কৰক"</string>
+    <string name="notifications_header" msgid="1404149926117359025">"জাননীসমূহ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ স্পৰ্শ কৰি হেঁচি ধৰক।"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"কোনো শ্বৰ্টকাট বাছনি কৰিবলৈ দুবাৰ টিপি হেঁচি ধৰক, বা নিজৰ উপযোগিতা অনুসৰি সৃষ্টি কৰা কাৰ্যসমূহ ব্যৱহাৰ কৰক।"</string>
+    <string name="out_of_space" msgid="4691004494942118364">"এই গৃহ স্ক্ৰীণত আৰু বেছি ঠাই নাই।"</string>
+    <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দৰ ট্ৰে\'ত আৰু বেছি ঠাই নাই"</string>
+    <string name="all_apps_button_label" msgid="8130441508702294465">"এপৰ সূচী"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ব্যক্তিগত এপৰ তালিকা"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"কৰ্মস্থানৰ এপৰ তালিকা"</string>
+    <string name="all_apps_home_button_label" msgid="252062713717058851">"গৃহপৃষ্ঠা"</string>
+    <string name="remove_drop_target_label" msgid="7812859488053230776">"আঁতৰাওক"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনষ্টল কৰক"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"এপ সম্পৰ্কীয় তথ্য"</string>
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"শ্বৰ্টকাট ইনষ্টল কৰিব পাৰে"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ব্য়ৱহাৰকাৰীৰ হস্তক্ষেপ অবিহনেই কোনো এপক শ্বৰ্টকাটবোৰ যোগ কৰাৰ অনুমতি দিয়ে।"</string>
+    <string name="permlab_read_settings" msgid="1941457408239617576">"গৃহ ছেটিং আৰু শ্বৰ্টকাটবোৰ পঢ়িব পাৰে"</string>
+    <string name="permdesc_read_settings" msgid="5833423719057558387">"এপটোক গৃহ পৃষ্ঠাত ছেটিং আৰু শ্বৰ্টকাটসমূহ পঢ়াৰ অনুমতি দিয়ে।"</string>
+    <string name="permlab_write_settings" msgid="3574213698004620587">"গৃহ ছেটিং আৰু শ্বৰ্টকাটবোৰ লিখিব পাৰে"</string>
+    <string name="permdesc_write_settings" msgid="5440712911516509985">"এপটোক গৃহ পৃষ্ঠাত ছেটিং আৰু শ্বৰ্টকাটসমূহ সলনি কৰাৰ অনুমতি দিয়ে।"</string>
+    <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক ফ\'ন কলবোৰ কৰাৰ অনুমতি দিয়া হোৱা নাই"</string>
+    <string name="gadget_error_text" msgid="6081085226050792095">"ৱিজেট ল\'ড কৰাত সমস্য়া"</string>
+    <string name="gadget_setup_text" msgid="8274003207686040488">"ছেটআপ কৰক"</string>
+    <string name="uninstall_system_app_text" msgid="4172046090762920660">"এইটো এটা ছিষ্টেম এপ আৰু ইয়াক আনইনষ্টল কৰিব নোৱৰি"</string>
+    <string name="folder_hint_text" msgid="6617836969016293992">"নামবিহীন ফ\'ল্ডাৰ"</string>
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> অক্ষম কৰা হ\'ল"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>ৰ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>টা জাননী আছে</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>ৰ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g>টা জাননী আছে</item>
+    </plurals>
+    <string name="default_scroll_format" msgid="7475544710230993317">"%2$dৰ %1$d পৃষ্ঠা"</string>
+    <string name="workspace_scroll_format" msgid="8458889198184077399">"গৃহ স্ক্ৰীণ %2$dৰ %1$d"</string>
+    <string name="workspace_new_page" msgid="257366611030256142">"গৃহ স্ক্ৰীণৰ নতুন পৃষ্ঠা"</string>
+    <string name="folder_opened" msgid="94695026776264709">"ফ’ল্ডাৰ খোলা হ\'ল, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"ফ\'ল্ডাৰ বন্ধ কৰিবলৈ টিপক"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"সলনি কৰা নাম ছেভ কৰিবলৈ টিপক"</string>
+    <string name="folder_closed" msgid="4100806530910930934">"ফ\'ল্ডাৰ বন্ধ কৰা হ\'ল"</string>
+    <string name="folder_renamed" msgid="1794088362165669656">"ফ\'ল্ডাৰৰ নাম সলনি কৰি <xliff:g id="NAME">%1$s</xliff:g> কৰা হৈছে"</string>
+    <string name="folder_name_format" msgid="6629239338071103179">"ফ’ল্ডাৰ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"ৱিজেটসমূহ"</string>
+    <string name="wallpaper_button_text" msgid="8404103075899945851">"ৱালপেপাৰসমূহ"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"গৃহ ছেটিংসমূহ"</string>
+    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"আপোনাৰ প্ৰশাসকে অক্ষম কৰি ৰাখিছে"</string>
+    <string name="allow_rotation_title" msgid="7728578836261442095">"গৃহ স্ক্ৰীণ ঘূৰোৱাৰ অনুমতি দিয়ক"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"ফ\'নটো যেতিয়া ঘূৰোৱা হয়"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"জাননী সম্পৰ্কীয় বিন্দুবোৰ"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"অন অৱস্থাত আছে"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"অফ অৱস্থাত আছে"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"জাননী চাবলৈ অনুমতিৰ প্ৰয়োজন"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"জাননী সম্পৰ্কীয় বিন্দুবোৰ দেখুৱাবলৈ <xliff:g id="NAME">%1$s</xliff:g>ৰ বাবে এপৰ জাননীসমূহ অন কৰক"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"ছেটিংসমূহ সলনি কৰক"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"জাননী বিন্দুসমূহ দেখুৱাওক"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"গৃহ স্ক্ৰীণত আইকনটো যোগ কৰক"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"নতুন এপসমূহৰ বাবে"</string>
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"আইকনৰ আকৃতি সলনি কৰক"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"গৃহ স্ক্ৰীণত"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"ছিষ্টেম ডিফ\'ল্ট ব্য়ৱহাৰ কৰক"</string>
+    <string name="icon_shape_square" msgid="633575066111622774">"বৰ্গাকাৰ"</string>
+    <string name="icon_shape_squircle" msgid="5658049910802669495">"বৰ্গবৃত্তাকাৰ"</string>
+    <string name="icon_shape_circle" msgid="6550072265930144217">"পৰিচিত মানুহৰ গোট"</string>
+    <string name="icon_shape_teardrop" msgid="4525869388200835463">"চকুপানীৰ টোপাল"</string>
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"আইকনৰ আকৃতিত কৰা পৰিবৰ্তনবোৰ প্ৰয়োগ কৰি থকা হৈছে"</string>
+    <string name="package_state_unknown" msgid="7592128424511031410">"অজ্ঞাত"</string>
+    <string name="abandoned_clean_this" msgid="7610119707847920412">"আঁতৰাওক"</string>
+    <string name="abandoned_search" msgid="891119232568284442">"সন্ধান কৰক"</string>
+    <string name="abandoned_promises_title" msgid="7096178467971716750">"এই এপটো ইনষ্টল কৰা হোৱা নাই"</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনৰ এপটো ইনষ্টল কৰা হোৱা নাই। আপুনি এইটো আঁতৰাব পাৰে অথবা এপটো বিচাৰি মেনুৱেলভাৱে ইনষ্টল কৰিব পাৰে।"</string>
+    <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল\'ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ\'ল"</string>
+    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string>
+    <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ৱিজেট"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ৱিজেটৰ তালিকা"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ৱিজেটৰ তালিকা বন্ধ কৰা হ\'ল"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"গৃহ স্ক্ৰীণত যোগ কৰক"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"বস্তুটো ইয়ালৈ স্থানান্তৰ কৰক"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"বস্তুটো গৃহ স্ক্ৰীণত যোগ কৰা হ\'ল"</string>
+    <string name="item_removed" msgid="851119963877842327">"বস্তুটো আঁতৰোৱা হ\'ল"</string>
+    <string name="action_move" msgid="4339390619886385032">"বস্তু স্থানান্তৰ কৰক"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"শাৰী <xliff:g id="NUMBER_0">%1$s</xliff:g> স্তম্ভ <xliff:g id="NUMBER_1">%2$s</xliff:g>লৈ স্থানান্তৰিত কৰক"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"পছন্দৰ অৱস্থান <xliff:g id="NUMBER">%1$s</xliff:g>লৈ স্থানান্তৰিত কৰক"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"পছন্দৰ অৱস্থান <xliff:g id="NUMBER">%1$s</xliff:g>লৈ স্থানান্তৰিত কৰক"</string>
+    <string name="item_moved" msgid="4606538322571412879">"বস্তুটো স্থানান্তৰ কৰা হ\'ল"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ফ\'ল্ডাৰত যোগ কৰক: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g>সহ ফ\'ল্ডাৰত যোগ কৰক"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"বস্তুটো ফ\'ল্ডাৰত যোগ কৰা হ\'ল"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g>: ৰ জৰিয়তে ফ\'ল্ডাৰ সৃষ্টি কৰক"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ফ\'ল্ডাৰ সৃষ্টি কৰা হ\'ল"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"হ\'ম স্ক্ৰীণলৈ স্থানান্তৰ কৰক"</string>
+    <string name="action_resize" msgid="1802976324781771067">"আকাৰ সলনি কৰক"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"প্ৰস্থ বৃদ্ধি কৰক"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"উচ্চতা বৃদ্ধি কৰক"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"প্ৰস্থ হ্ৰাস কৰক"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা হ্ৰাস কৰক"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ৱিজেটৰ আকাৰ সলনি কৰি প্ৰস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> আৰু উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> কৰা হ\'ল"</string>
+    <string name="action_deep_shortcut" msgid="2864038805849372848">"শ্বৰ্টকাটসমূহ"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"শ্বৰ্টকাট আৰু জাননীসমূহ"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"অগ্ৰাহ্য কৰক"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"জাননী অগ্ৰাহ্য কৰা হৈছে"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"ব্যক্তিগত"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"কৰ্মস্থান"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
+    <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ইয়াত কৰ্মস্থানৰ এপ্ বিচাৰি পাওক"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"কৰ্মস্থানৰ প্ৰতিটো এপৰে একোটা প্ৰতীক আছে আৰু তাক আপোনাৰ প্ৰতিষ্ঠানে সুৰক্ষিত কৰি ৰাখে। ব্যৱহাৰ কৰাত সুবিধা হ\'বলৈ এপসমূহ আপোনাৰ গৃহ স্ক্ৰীণলৈ স্থানান্তৰ কৰক।"</string>
+    <string name="work_mode_on_label" msgid="4781128097185272916">"আপোনাৰ প্ৰতিষ্ঠানৰ দ্বাৰা পৰিচালিত"</string>
+    <string name="work_mode_off_label" msgid="3194894777601421047">"জাননী আৰু এপসমূহ অফ হৈ আছে"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"বন্ধ কৰক"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"বন্ধ"</string>
+</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 00f71d0..3b36f37 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> sorğusuna uyğun tətbiq tapılmadı"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Daha çox tətbiq üçün axtarış edin"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Bildirişlər"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Qısayolu seçmək üçün basıb saxlayın."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Bu Əsas ekranda boş yer yoxdur."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritlər-də yer yoxdur"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Tətbiq siyahısı"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Şəxsi tətbiqlərin siyahısı"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"İş tətbiqlərinin siyahısı"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Əsas səhifə"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Silin"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sistemdən sil"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Divar kağızları"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home ayarları"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Admininiz tərəfindən deaktiv edilib"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"İcmal"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Əsas ekranın firlanmağına icazə verin"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon çevrilən zaman"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Cari Ekran ayarı fırlatmağa icazə vermir"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Bildiriş nişanı"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiv"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Deaktiv"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildiriş girişi tələb edilir"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildiriş Nöqtələrini göstərmək üçün <xliff:g id="NAME">%1$s</xliff:g> bildirişlərini aktiv edin"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Ayarları dəyişin"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Bildiriş nöqtələrini göstərin"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Əsas ekrana ikona əlavə edin"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yeni tətbiqlər üçün"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"İkona formasını dəyişin"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Əsas səhifə ekranında"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sistem defoltu istifadə edin"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kənarları dairəvi kvadrat"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> endirilir, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> yüklənmək üçün gözləyir"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> vidcetləri"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Vidcet siyahısı"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Vidcet siyahısı bağlandı"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Əsas ekrana əlavə edin"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Elementi bura köçürün"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element əsas ekrana əlavə edildi"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Qovluq yaradın: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Qovluq yaradıldı"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Əsas ekrana köçürün"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranı sola köçürün"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranı sağa köçürün"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran köçürülüb"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ölçüsünü dəyişin"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Eni artırın"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Hündürlüyü artırın"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Hündürlüyü azaldın"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidcetin eni <xliff:g id="NUMBER_0">%1$s</xliff:g> hündürlüyü <xliff:g id="NUMBER_1">%2$s</xliff:g> kimi ölçüləndirildi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Qısa yollar"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> üçün <xliff:g id="APP_NAME">%2$s</xliff:g> qısa yolu"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> üçün <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> qısayol və  <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> bildiriş"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Qısayol və bildirişlər"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Rədd edin"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Bildiriş rədd edildi"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Şəxsi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Burada iş tətbiqləri axtarın"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Hər bir iş tətbiqində təşkilat tərəfindən qorunduğunu göstərən narıncı nişan var. Tətbiqləri daha asan giriş üçün Əsas Səhifə Ekranına köçürün."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Hər bir iş tətbiqində təşkilat tərəfindən qorunduğunu göstərən narıncı nişan var. Tətbiqləri daha asan giriş üçün Əsas Səhifə Ekranına köçürün."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Təşkilatınız tərəfindən idarə olunur"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Bildiriş və tətbiqlər deaktivdir"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Bağlayın"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Bağlıdır"</string>
 </resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 0ee8b3a..3fb8bf5 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži još aplikacija"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obaveštenja"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Dodirnite i zadržite da biste izabrali prečicu."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nema više prostora na ovom početnom ekranu."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Omiljeno"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista aplikacija"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista ličnih aplikacija"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
@@ -78,19 +82,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadine"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Podešavanja početnog ekrana"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator je onemogućio"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Pregled"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Dozvoli rotaciju početnog ekrana"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon rotira"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Aktuelno podešavanje prikaza ne dozvoljava rotaciju"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Tačke za obaveštenja"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup za obaveštenja"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Promenite podešavanja"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Prikazuj tačke za obaveštenja"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni ekran"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Promenite oblik ikona"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na početnom ekranu"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Koristi podrazumevano sistemsko podešavanje"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
@@ -105,6 +109,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Vidžeti za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista vidžeta"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista vidžeta je zatvorena"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodaj na početni ekran"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Premesti stavku ovde"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodata na početni ekran"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Napravite direktorijum sa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Direktorijum je napravljen"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Premesti na početni ekran"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Pomeri ekran ulevo"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Pomeri ekran udesno"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran je pomeren"</string>
     <string name="action_resize" msgid="1802976324781771067">"Promeni veličinu"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Povećaj širinu"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Povećaj visinu"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> i visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> prečice(a) za <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Prečice (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) i obaveštenja (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) za <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obaveštenja"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Obaveštenje je odbačeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil za Work"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovde"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Svaka poslovna aplikacija ima narandžastu značku i štiti je vaša organizacija. Premestite aplikacije na početni ekran da biste im lakše pristupali."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Svaka poslovna aplikacija ima značku i štiti je vaša organizacija. Premestite aplikacije na početni ekran da biste im lakše pristupali."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Ovim upravlja organizacija"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Obaveštenja i aplikacije su isključeni"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 2f5eac7..59a8f1f 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Праграм, якія адпавядаюць запыту \"<xliff:g id="QUERY">%1$s</xliff:g>\", не знойдзена"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Шукаць іншыя праграмы"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Апавяшчэнні"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."</string>
     <string name="out_of_space" msgid="4691004494942118364">"На гэтым Галоўным экране больш няма месца."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"У латку \"Абранае\" больш няма месца"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Спіс праграм"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Спіс персанальных праграм"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Спіс працоўных праграм"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Галоўная"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Выдаліць"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Выдаліць"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Шпалеры"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Налады галоўнага экрана"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Адключаная адміністратарам"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Агляд"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Дазволіць паварот галоўнага экрана"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Бягучая налада дысплэя не прадугледжвае паварот"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Значкі апавяшчэнняў"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Уключана"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Выключана"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Змяніць налады"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Паказаць значкі апавяшчэнняў"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Дадаць значок на Галоўны экран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для новых праграм"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Змяніць форму значка"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на галоўным экране"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Выкарыстоўваць стандартныя формы"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Прамавугольнік са скругленымі вугламі"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Ідзе спампоўка <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завершана"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чакае ўсталёўкі"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Віджэты <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Спіс віджэтаў"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Спіс віджэтаў закрыты"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Дадаць на Галоўны экран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Перамясціць элемент сюды"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент дададзены на галоўны экран"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Стварыць папку з: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Папка створана"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Перамясціць на Галоўны экран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Перамясціць экран налева"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Перамясціць экран направа"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Экран перамешчаны"</string>
     <string name="action_resize" msgid="1802976324781771067">"Змяніць памер"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Павялічыць шырыню"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Павялічыць вышыню"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Паменшыць вышыню"</string>
     <string name="widget_resized" msgid="9130327887929620">"Памеры віджэта зменены на: шырыня <xliff:g id="NUMBER_0">%1$s</xliff:g>, вышыня <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыкі"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) для <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Ярлыкі (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) і апавяшчэнні (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) для <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлыкі і апавяшчэнні"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Адхіліць"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Апавяшчэнне адхілена"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Асабістыя"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Праца"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Знайдзіце працоўныя праграмы тут"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Кожная працоўная праграма мае аранжавы значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на свой Галоўны экран."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Кожная працоўная праграма мае значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на Галоўны экран."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Пад кіраваннем вашай арганізацыі"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Апавяшчэнні і праграмы выключаны"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрыць"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрытыя"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 94b7f13..47825f6 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Търсене на още приложения"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Известия"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Докоснете и задръжте за избор на пряк път."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."</string>
     <string name="out_of_space" msgid="4691004494942118364">"На този начален екран няма повече място."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Няма повече място в областта с любимите"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Списък с приложения"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Списък с лични приложения"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Списък със служебни приложения"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Начало"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Премахване"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталиране"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Папка: „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Приспособления"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Настройки за Google Home"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Настройки за началния екран"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Деактивирано от администратора ви"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Общ преглед"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Разрешаване на завъртането на началния екран"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"При завъртане на телефона"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Текущата настройка на екрана не разрешава завъртане"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Точки за известия"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Включено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Изключено"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Необходим е достъп до известията"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"За да се показват точки за известия, включете известията за приложението <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Промяна на настройките"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Показване на точките за известия"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавяне на икона към началния екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови приложения"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Промяна на формата на иконите"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на началния екран"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Използване на стандартната системна настройка"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Комбинация от кръг и квадрат"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се изтегля. Завършено: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> изчаква инсталиране"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Приспособления за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Списък с приспособления"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Списъкът с приспособления е затворен"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Добавяне към началния екран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Преместване на елемента тук"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Елементът е добавен към началния екран"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Създаване на папка с елемента „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="folder_created" msgid="6409794597405184510">"Папката е създадена"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Преместване към началния екран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Преместване на екрана наляво"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Преместване на екрана надясно"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Екранът е преместен"</string>
     <string name="action_resize" msgid="1802976324781771067">"Преоразмеряване"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Увеличаване на ширината"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Увеличаване на височината"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намаляване на височината"</string>
     <string name="widget_resized" msgid="9130327887929620">"Приспособлението е преоразмерено към ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> и височина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Преки пътища"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> преки пътища за <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> преки пътища и <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> известия за <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Преки пътища и известия"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Отхвърляне"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Известието е отхвърлено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лични"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Служебни"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Служебен потребителски профил"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Тук можете да намерите служебните приложения"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Всяко служебно приложение има оранжева значка и организацията ви се грижи за сигурността му. За по-лесен достъп преместете приложенията на началния си екран."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Всяко служебно приложение има значка и организацията ви се грижи за сигурността му. За по-лесен достъп преместете приложенията на началния си екран."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Управлява се от организацията ви"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Известията и приложенията са изключени"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затваряне"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
 </resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index d9c6033..8fb906f 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"আরও অ্যাপ্লিকেশানের জন্য খুঁজুন"</string>
     <string name="notifications_header" msgid="1404149926117359025">"বিজ্ঞপ্তি"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"কোনও শর্টকাট বেছে নিতে টাচ করে ধরে থাকুন।"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"কোনও শর্টকাট বেছে নিতে ডবল ট্যাপ করে ধরে থাকুন অথবা কাস্টম অ্যাকশন ব্যবহার করুন।"</string>
     <string name="out_of_space" msgid="4691004494942118364">"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"অ্যাপ্লিকেশানগুলির তালিকা"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ব্যক্তিগত অ্যাপের তালিকা"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"কাজের অ্যাপের তালিকা"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"হোম"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"সরান"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
@@ -73,23 +77,23 @@
     <string name="folder_closed" msgid="4100806530910930934">"ফোল্ডার বন্ধ করা হয়েছে"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"ফোল্ডারের নাম পাল্টে <xliff:g id="NAME">%1$s</xliff:g> করা হয়েছে"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"ফোল্ডার: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="widget_button_text" msgid="2880537293434387943">"উইজেটগুলি"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"উইজেট"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ওয়ালপেপারগুলি"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"হোম এর সেটিংস"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"হোম সেটিংস"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"আপনার প্রশাসক দ্বারা অক্ষম করা হয়েছে"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"এক নজরে"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"হোমস্ক্রীন ঘোরানোর অনুমতি দিন"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"যখন ফোনটি ঘোরানো হয়"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"বর্তমান প্রদর্শনের সেটিংস ঘোরানোর মঞ্জুরি দেয় না"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"বিজ্ঞপ্তি ডট"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"চালু হয়েছে"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"বন্ধ আছে"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"বিজ্ঞপ্তিতে অ্যাক্সেস প্রয়োজন"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"বিজ্ঞপ্তির ডটগুলি দেখানোর জন্য, <xliff:g id="NAME">%1$s</xliff:g> এর অ্যাপ বিজ্ঞপ্তি চালু করুন"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"সেটিংস পরিবর্তন করুন"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"বিজ্ঞপ্তির ডট দেখুন"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"হোম স্ক্রিনে আইকন যোগ করুন"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"নতুন অ্যাপ্লিকেশানগুলির জন্যে"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"আইকনের আকৃতি পরিবর্তন করুন"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"হোম স্ক্রিনে"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"সিস্টেমের ডিফল্ট মান ব্যবহার করুন"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"চৌকো"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"চৌকো-গোলাকার"</string>
@@ -98,12 +102,14 @@
     <string name="icon_shape_override_progress" msgid="3461735694970239908">"আইকনের আকৃতি পরিবর্তন করা হচ্ছে"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string>
-    <string name="abandoned_search" msgid="891119232568284442">"অনুসন্ধান"</string>
+    <string name="abandoned_search" msgid="891119232568284442">"সার্চ"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"এই অ্যাপ্লিকেশানটি ইন্সটল করা নাই"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি অনুসন্ধান করে এটি নিজে ইন্সটল করতে পারেন।"</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি সার্চ করে এটি নিজে ইন্সটল করতে পারেন।"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> উইজেট"</string>
+    <string name="widgets_list" msgid="796804551140113767">"উইজেটের তালিকা"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"উইজেটের তালিকা বন্ধ করা হয়েছে"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"হোম স্ক্রীনে যোগ করুন"</string>
     <string name="action_move_here" msgid="2170188780612570250">"এখানে আইটেম সরান"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"হোম স্ক্রীনে আইটেম যোগ করা হয়েছে"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"এর সাথে ফোল্ডার তৈরি করুন: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ফোল্ডার তৈরি করা হয়েছে"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"হোম স্ক্রীনে সরান"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"স্ক্রীন বাঁ দিকে সরান"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"স্ক্রীন ডান দিকে সরান"</string>
-    <string name="screen_moved" msgid="266230079505650577">"স্ক্রীন সরানো হয়েছে"</string>
     <string name="action_resize" msgid="1802976324781771067">"আবার আকার দিন"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"প্রস্থ বাড়ান"</string>
     <string name="action_increase_height" msgid="459390020612501122">"উচ্চতা বাড়ান"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা কমান"</string>
     <string name="widget_resized" msgid="9130327887929620">"উইজেটের আকার প্রস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> তে পরিবর্তন করা হয়েছে"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"শর্টকাট"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> এর <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>টি শর্টকার্ট"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> এর জন্য <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>টি শর্টকাট এবং <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>টি বিজ্ঞপ্তি"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"শর্টকাট এবং বিজ্ঞপ্তি"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"খারিজ করুন"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"বিজ্ঞপ্তি খারিজ করা হয়েছে"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ব্যক্তিগত"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"এখানে কাজের অ্যাপ্সগুলি খুঁজুন"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"প্রতিটি কাজের অ্যাপে একটি করে কমলা ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"প্রতিটি কাজের অ্যাপে একটি করে ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"বন্ধ করুন"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"বন্ধ"</string>
 </resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 84b2b78..848176d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -30,7 +30,7 @@
     <string name="home_screen" msgid="806512411299847073">"Početni ekran"</string>
     <string name="custom_actions" msgid="3747508247759093328">"Prilagođene akcije"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite &amp; i držite da biste uzeli dodatak."</string>
-    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dvaput dodirnite &amp; i držite da biste uzeli vidžet ili koristite prilagođene radnje."</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Dodirnite dvaput &amp; i držite da biste uzeli vidžet ili koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Dodirnite i držite da postavite ručno"</string>
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za upit \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pretraži više aplikacija"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obavještenja"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Dodirnite i držite da uzmete prečicu."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dodirnite dvaput i držite da uzmete prečicu ili koristite prilagođene akcije."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom ekranu nema više prostora."</string>
-    <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora u ladici Favoriti"</string>
+    <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora u ladici Omiljeno"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Spisak aplikacija"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista ličnih aplikacija"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
@@ -76,21 +80,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Dodaci"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadinske slike"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Postavke za Home"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Postavke početnog ekrana"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogućio vaš administrator"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Pregled"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Dozvoli rotiranje početnog ekrana"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon zarotira"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Trenutne postavke ekrana ne dozvoljavaju rotiranje"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Tačke za obavještenja"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup obavještenjima"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz tačaka obavještenja, uključite obavještenja za aplikacije za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Promijeni postavke"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Prikaži tačke za obavještenja"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni ekran"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Promjena oblika ikona"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na Početnom ekranu"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Koristite sistemski zadano"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
@@ -99,12 +103,14 @@
     <string name="icon_shape_override_progress" msgid="3461735694970239908">"Primjenjivanje promjena oblika ikona"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
-    <string name="abandoned_search" msgid="891119232568284442">"Traži"</string>
+    <string name="abandoned_search" msgid="891119232568284442">"Pretraži"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ova aplikacija nije instalirana"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za ovu ikonu nije instalirana. Možete je ukloniti ili potražiti aplikaciju i ručno je instalirati."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka da se instalira"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Vidžeti za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Spisak vidžeta"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Spisak vidžeta je zatvoren"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodaj na početni ekran"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na Početni ekran."</string>
@@ -112,7 +118,7 @@
     <string name="action_move" msgid="4339390619886385032">"Premjesti stavku"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"Pomjeri stavku u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="move_to_position" msgid="6750008980455459790">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
-    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g> među favoritima"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pomjeri stavku na poziciju <xliff:g id="NUMBER">%1$s</xliff:g> među omiljenim"</string>
     <string name="item_moved" msgid="4606538322571412879">"Stavka je premještena"</string>
     <string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder sa aplikacijom <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Kreirajte folder sa stavkom: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder je kreiran"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Pomjeri na početni ekran"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Pomjeri ekran ulijevo"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Pomjeri ekran udesno"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran je pomjeren"</string>
     <string name="action_resize" msgid="1802976324781771067">"Promijeni veličinu"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Povećaj širinu"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Povećaj visinu"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promijenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> prečica za aplikaciju <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Za aplikaciju <xliff:g id="APP_NAME">%3$s</xliff:g> broj prečica je <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>, a broj obavještenja je <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obavještenja"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Obavještenje je odbačeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pronađite poslovne aplikacije ovdje"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Svaka poslovna aplikacija ima narandžastu značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Svaka poslovna aplikacija ima značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikacije i aplikacije su isključene"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 1ca68eb..27f9c31 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -40,13 +40,17 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No s\'ha trobat cap aplicació que coincideixi amb \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca més aplicacions"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificacions"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Mantén premuda una drecera per seleccionar-la."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Ja no queda espai en aquesta pantalla d\'inici."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No hi ha més espai a la safata Preferits."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Llista d\'aplicacions"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Llista d\'aplicacions personals"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Llista d\'aplicacions per a la feina"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inici"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Suprimeix"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstal·la"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Dades de l\'aplicació"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Informació de l\'aplicació"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fons de pantalla"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Configuració de la pantalla d\'inici"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Configuració de pantalla d\'inici"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desactivada per l\'administrador"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Visió general"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permet la rotació de la pantalla d\'inici"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"En girar el telèfon"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuració actual de la pantalla no permet la rotació"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Punts de notificació"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivat"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Cal que tingui accés a les notificacions"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Per veure els punts de notificació, activa les notificacions de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Canvia la configuració"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostra els punts de notificació"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Afegeix la icona a la pantalla d\'inici"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per a les aplicacions noves"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Canvia la forma de les icones"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"a la pantalla d\'inici"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utilitza l\'opció predeterminada del sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrat arrodonit"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"S\'està baixant <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completat"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"S\'està esperant per instal·lar <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Llista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"S\'ha tancat la llista de widgets"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Afegeix a la pantalla d\'inici"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mou l\'element aquí"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"S\'ha afegit l\'element a la pantalla d\'inici"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Crea una carpeta amb: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Desplaça a la pantalla d\'inici"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Desplaça pantalla a l\'esquerra"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Desplaça pantalla a la dreta"</string>
-    <string name="screen_moved" msgid="266230079505650577">"S\'ha desplaçat la pantalla"</string>
     <string name="action_resize" msgid="1802976324781771067">"Canvia la mida"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Augmenta l\'amplada"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Augmenta l\'alçada"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Redueix l\'alçada"</string>
     <string name="widget_resized" msgid="9130327887929620">"S\'ha canviat la mida del widget a l\'amplada <xliff:g id="NUMBER_0">%1$s</xliff:g> i l\'alçada <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Dreceres"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> dreceres per a l\'aplicació <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> dreceres i <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificacions per a <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Dreceres i notificacions"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignora"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"S\'ha ignorat la notificació"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Feina"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil professional"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Cerca aplicacions per a la feina aquí"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Totes les aplicacions per a la feina tenen una insígnia taronja que indica que estan protegides per la teva organització. Mou les aplicacions a la pantalla d\'inici per poder-hi accedir més fàcilment."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Totes les aplicacions per a la feina tenen una insígnia que indica que estan protegides per la teva organització. Mou les aplicacions a la pantalla d\'inici per poder-hi accedir més fàcilment."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat per la teva organització"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Les notificacions i les aplicacions estan desactivades"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tanca"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"S\'ha tancat"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e5fde42..48adf44 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Vyhledat další aplikace"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Oznámení"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Zkratku vyberete podržením."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na této ploše již není místo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na panelu Oblíbené položky již není místo."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Seznam aplikací"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Seznam osobních aplikací"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Seznam pracovních aplikací"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Plocha"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstranit"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstalovat"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Nastavení plochy"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Zakázáno administrátorem"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Přehled"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Povolit otáčení plochy"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Při otočení telefonu"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Aktuální nastavení displeje neumožňuje otáčení"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Puntíky s oznámením"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuto"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuto"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Je třeba udělit přístup k oznámením"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Chcete-li zobrazovat puntíky s oznámením, zapněte oznámení z aplikace <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Změnit nastavení"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Zobrazovat puntíky s oznámením"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Přidat ikonu na plochu"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pro nové aplikace"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Změnit tvar ikony"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na ploše"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Použít výchozí nastavení systému"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Čtverec"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kruh/čtverec"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Stahování aplikace <xliff:g id="NAME">%1$s</xliff:g> (dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g> čeká na zahájení"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgety <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Seznam widgetů"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Seznam widgetů zavřen"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Přidat na plochu"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Přesunout položku sem"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Položka byla přidána na plochu"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Vytvořit složku s položkou <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Složka byla vytvořena"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Přesunout na plochu"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Přesunout obrazovku doleva"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Přesunout obrazovku doprava"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Obrazovka byla přesunuta"</string>
     <string name="action_resize" msgid="1802976324781771067">"Změnit velikost"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Zvýšit šířku"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Zvýšit výšku"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Snížit výšku"</string>
     <string name="widget_resized" msgid="9130327887929620">"Velikost widgetu upravena: šířka <xliff:g id="NUMBER_0">%1$s</xliff:g>, výška <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Zkratky"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Počet zkratek pro aplikaci <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Zkratky (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) a oznámení (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) aplikace <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Zkratky a oznámení"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Zavřít"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Oznámení bylo zavřeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobní"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovní profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Zde naleznete pracovní aplikace"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Každý pracovní profil má oranžový odznak a je zabezpečen vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Každá pracovní aplikace má odznak a je zabezpečena vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Spravováno vaší organizací"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Oznámení a aplikace jsou vypnuty"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zavřít"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zavřeno"</string>
 </resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 97d8a26..d141ad9 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Søg efter flere apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Underretninger"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Hold en genvej nede for at samle den op."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Tryk to gange, og hold en genvej nede for at samle den op eller bruge tilpassede handlinger."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Der er ikke mere plads i bakken Foretrukne"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Liste med apps"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste over personlige apps"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste over apps til arbejdet"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startskærm"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Baggrunde"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Indstillinger for startskærmen"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Deaktiveret af din administrator"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Oversigt"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Tillad rotation af startskærmen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Når telefonen roteres"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Den aktuelle indstilling for visning tillader ikke rotation"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Underretningscirkler"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Til"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Fra"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Kræver adgang til underretninger"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Hvis du vil se underretningscirkler, skal du aktivere appunderretninger for <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Skift indstillinger"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Vis underretningscirkler"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Føj ikon til startskærmen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Skift ikonform"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"på startskærmen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Brug systemstandarden"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrat med runde hjørner"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloades. <xliff:g id="PROGRESS">%2$s</xliff:g> er gennemført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> venter på at installere"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Liste med widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Listen med widgets blev lukket"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Føj til startskærm"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Flyt elementet hertil"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er føjet til startskærmen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Opret mappe med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mappen blev oprettet"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Flyt til startskærmen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Flyt skærmen til venstre"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Flyt skærmen til højre"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skærmen er flyttet"</string>
     <string name="action_resize" msgid="1802976324781771067">"Tilpas størrelse"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Øg bredden"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Øg højden"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducer højden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Størrelsen for widgetten er ændret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og højde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Genveje"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> genveje til <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> genveje og <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> underretninger for <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Genveje og underretninger"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Afvis"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Underretningen blev afvist"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personlige"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find arbejdsapps her"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Alle arbejdsapps har et orange badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Alle arbejdsapps har et badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Administreret af din organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Underretninger og apps er slået fra"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Luk"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lukket"</string>
 </resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 96acfba..c309a55 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Weitere Apps suchen"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tippen und halten, um eine Verknüpfung auszuwählen."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ablage \"Favoriten\" ist voll."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Liste der Apps"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste der privaten Apps"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste der geschäftlichen Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startseite"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Entfernen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Hintergründe"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Einstellungen für den Startbildschirm"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Von deinem Administrator deaktiviert"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Übersicht"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Drehung des Startbildschirms zulassen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Bei Drehung des Smartphones"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Die aktuelle \"Display\"-Einstellung verhindert eine Drehung der Anzeige"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"App-Benachrichtigungspunkte"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiviert"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Deaktiviert"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Benachrichtigungszugriff erforderlich"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Einstellungen ändern"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"App-Benachrichtigungspunkte anzeigen"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Symbol zu Startbildschirm hinzufügen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Für neue Apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Form des Symbols ändern"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"auf dem Startbildschirm"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Systemstandardeinstellung verwenden"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Superkreis"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wird heruntergeladen, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Warten auf Installation von <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-Widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgetliste"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetliste geschlossen"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Zum Startbildschirm hinzufügen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Element hierhin verschieben"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element zum Startbildschirm hinzugefügt"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Anhand von <xliff:g id="NAME">%1$s</xliff:g> Ordner erstellen"</string>
     <string name="folder_created" msgid="6409794597405184510">"Ordner erstellt"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Auf Startbildschirm verschieben"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Bildschirm nach links"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Bildschirm nach rechts"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Bildschirm verschoben"</string>
     <string name="action_resize" msgid="1802976324781771067">"Größe anpassen"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Breite vergrößern"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Höhe vergrößern"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Höhe verringern"</string>
     <string name="widget_resized" msgid="9130327887929620">"Größe des Widgets zu Breite <xliff:g id="NUMBER_0">%1$s</xliff:g> und Höhe <xliff:g id="NUMBER_1">%2$s</xliff:g> geändert"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Verknüpfungen"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> Verknüpfungen für <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> Verknüpfungen und <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> Benachrichtigungen für <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Verknüpfungen und Benachrichtigungen"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Schließen"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Benachrichtigung geschlossen"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privat"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbeitsprofil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hier findest du Apps für die Arbeit"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Jede App für die Arbeit hat ein orangefarbenes Logo. Deine Organisation kümmert sich um den entsprechenden Schutz. Damit du leichter auf Apps zugreifen kannst, verschiebe sie auf deinen Startbildschirm."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Jede App für die Arbeit ist mit einem Logo gekennzeichnet. Deine Organisation kümmert sich um den entsprechenden Schutz. Damit du leichter auf Apps zugreifen kannst, verschiebe sie auf deinen Startbildschirm."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Wird von deiner Organisation verwaltet"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Benachrichtigungen und Apps sind deaktiviert"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Schließen"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Geschlossen"</string>
 </resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 9328c5f..3208fcb 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Δεν βρέθηκαν εφαρμογές αντιστοίχισης για \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Αναζήτηση περισσότερων εφαρμογών"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Ειδοποιήσεις"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Αγγίξτε παρατεταμένα για επιλογή συντόμευσης."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Πατήσετε δύο φορές παρατεταμένα για επιλογή συντόμευσης ή χρήση προσαρμοσμένων ενεργειών."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Λίστα εφαρμογών"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Λίστα προσωπικών εφαρμογών"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Λίστα εφαρμογών εργασίας"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Αρχική οθόνη"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Κατάργηση"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Απεγκατάσταση"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Φάκελος: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Γραφικά στοιχεία"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ταπετσαρίες"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Ρυθμίσεις Αρχικής σελίδας"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Ρυθμίσεις Αρχ. Οθ."</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Απενεργοποιήθηκε από τον διαχειριστή σας"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Επισκόπηση"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Να επιτρέπεται η περιστροφή της αρχικής οθόνης"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Όταν το τηλέφωνο περιστρέφεται"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Η τρέχουσα ρύθμιση οθόνης δεν επιτρέπει την περιστροφή"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Κουκκίδες ειδοποίησης"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ενεργή"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Ανενεργή"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Απαιτείται πρόσβαση στις ειδοποιήσεις"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Για να εμφανιστούν οι Κουκκίδες ειδοποίησης, ενεργοποιήστε τις κουκκίδες εφαρμογής για την εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Αλλαγή ρυθμίσεων"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Εμφάνιση κουκκίδων ειδοποίησης"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Προσθήκη εικονιδίου στην Αρχική οθόνη"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Για νέες εφαρμογές"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Αλλαγή σχήματος εικονιδίου"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"στην Αρχική οθόνη"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Χρήση προεπιλογής συστήματος"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Τετράγωνο"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Στρογγυλεμένο τετράγωνο"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Λήψη <xliff:g id="NAME">%1$s</xliff:g>, ολοκληρώθηκε <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> σε αναμονή για εγκατάσταση"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Γραφικά στοιχεία <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Λίστα γραφικών στοιχείων"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Η λίστα γραφικών στοιχείων έκλεισε"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Προσθήκη στην αρχική οθόνη"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Μετακίνηση στοιχείου εδώ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Το στοιχείο προστέθηκε στην αρχική οθόνη"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Δημιουργία φακέλου με: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Δημιουργήθηκε φάκελος"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Μετακίνηση Αρχικής οθόνης"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Μετακίνηση οθόνης αριστερά"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Μετακίνηση οθόνης δεξιά"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Η οθόνη μετακινήθηκε"</string>
     <string name="action_resize" msgid="1802976324781771067">"Προσαρμογή μεγέθους"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Αύξηση του πλάτους"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Αύξηση του ύψους"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Μείωση του ύψους"</string>
     <string name="widget_resized" msgid="9130327887929620">"Έγινε προσαρμογή του μεγέθους του γραφικού στοιχείου σε <xliff:g id="NUMBER_0">%1$s</xliff:g> πλάτος και <xliff:g id="NUMBER_1">%2$s</xliff:g> ύψος"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Συντομεύσεις"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> συντομεύσεις για <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> συντομεύσεις και <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ειδοποιήσεις για την εφαρμογή <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Συντομεύσεις και ειδοποιήσεις"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Παράβλεψη"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Η ειδοποίηση παραβλέφθηκε"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Προσωπικές"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Βρείτε όλες τις εφαρμογές εργασίας εδώ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Κάθε εφαρμογή εργασίας φέρει ένα πορτοκαλί σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Κάθε εφαρμογή εργασίας φέρει ένα σήμα και διατηρείται ασφαλής από τον οργανισμό σας. Μετακινήστε τις εφαρμογές εργασίας στην Αρχική οθόνη, για να έχετε πιο εύκολη πρόσβαση."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Διαχειριζόμενο από τον οργανισμό σας"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Οι ειδοποιήσεις και οι εφαρμογές είναι απενεργοποιημένες"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Κλείσιμο"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Κλειστή"</string>
 </resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d7ab7d2..245ee43 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
     <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts for <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts and <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifications for <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
 </resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index d7ab7d2..245ee43 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
     <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts for <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts and <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifications for <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
 </resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index d7ab7d2..245ee43 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No apps found matching \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Search for more apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Touch &amp; hold to pick up a shortcut."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Double-tap &amp; hold to pick up a shortcut or use custom actions."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Apps list"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personal apps list"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Work apps list"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home settings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disabled by your admin"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Overview"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Allow Homescreen rotation"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"When phone is rotated"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Current display setting doesn\'t permit rotation"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Notification dots"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"On"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Off"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Notification access needed"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"To show Notification Dots, turn on app notifications for <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Change settings"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Show notification dots"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Add icon to Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For new apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Change icon shape"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"on Home screen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Use system default"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Square"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgets list"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgets list closed"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
     <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts for <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shortcuts and <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifications for <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Find work apps here"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Each work app has an orange badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Each work app has a badge and is kept secure by your organisation. Move apps to your Home screen for easier access."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Managed by your organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notifications and apps are off"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Close"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Closed"</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 11cfa2a..368e4ba 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No hay apps que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Mantén presionado para elegir un acceso directo."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No hay más espacio en esta pantalla principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está llena."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de apps"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de apps personales"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de apps del trabajo"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Pantalla principal"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -75,22 +79,22 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Configuración de Home"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Configuración de página principal"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"El administrador inhabilitó esta función"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Recientes"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir la rotación de la pantalla principal"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuración actual no permite la rotación de la pantalla"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar los puntos de notificación, activa las notificaciones de la app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Cambiar la configuración"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar puntos de notificación"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Agregar ícono a la pantalla principal"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los íconos"</string>
-    <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar el sistema predeterminado"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"en la pantalla principal"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar valores predeterminados del sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Círculo"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Se completó el <xliff:g id="PROGRESS">%2$s</xliff:g> de la descarga de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalación de <xliff:g id="NAME">%1$s</xliff:g> en espera"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Se cerró la lista de widgets"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Agregar a la pantalla principal"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Se agregó el elemento a la pantalla principal."</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Crear carpeta con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover a la pantalla principal"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla a la izquierda"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla a la derecha"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Se movió la pantalla."</string>
     <string name="action_resize" msgid="1802976324781771067">"Ajustar tamaño"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumentar el ancho"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumentar la altura"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir la altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Se cambió la dimensión del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> accesos directos para <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> accesos directos y <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificaciones de <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Accesos directos y notificaciones"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Descartar"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Se descartó la notificación"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personales"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Laborales"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Apps de trabajo"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada app de trabajo tiene una insignia naranja y está protegida por tu organización. Mueve las apps a la pantalla principal para acceder a ellas con mayor facilidad."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada app de trabajo tiene una insignia y está protegida por tu organización. Transfiere las apps a la pantalla principal para acceder a ellas con mayor facilidad."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Administrado por tu organización"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las apps están desactivadas"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Cerrar"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Cerrado"</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 39da94c..0829533 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar más aplicaciones"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificaciones"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Mantén pulsado para elegir un acceso directo."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Toca dos veces y mantén pulsado para elegir un acceso directo o utilizar acciones personalizadas."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está completa"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicaciones"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicaciones personales"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicaciones del trabajo"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Ajustes de Home"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Ajustes de la pantalla de inicio"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inhabilitada por el administrador"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Visión general"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotación de la pantalla de inicio"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"La configuración de pantalla actual no permite girar la pantalla"</string>
-    <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificación"</string>
-    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activada"</string>
-    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivada"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"Burbujas de notificación"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activado"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivado"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar burbujas de notificación, activa las notificaciones de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Cambiar ajustes"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar burbujas de notificación"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Añadir icono a la pantalla de inicio"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para aplicaciones nuevas"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma de los iconos"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"en la pantalla de inicio"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar opción predeterminada del sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Cuadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Cuadrado con esquinas redondeadas"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets cerrada"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Añadir a la pantalla de inicio"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento añadido a la pantalla de inicio"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Crear carpeta con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover a la pantalla de inicio"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla a la izquierda"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla a la derecha"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Pantalla movida"</string>
     <string name="action_resize" msgid="1802976324781771067">"Modificar tamaño"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Se ha modificado el tamaño del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> accesos directos de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> accesos directos y <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificaciones de <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Accesos directos y notificaciones"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorar"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notificación ignorada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplicaciones de trabajo"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada aplicación de trabajo tiene una insignia naranja y está protegida por tu organización. Mueve las aplicaciones a la pantalla de inicio para acceder a ellas más fácilmente."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada aplicación de trabajo tiene una insignia y está protegida por tu organización. Mueve las aplicaciones a la pantalla de inicio para acceder a ellas más fácilmente."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Administrada por tu organización"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Las notificaciones y las aplicaciones están desactivadas"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Cerrar"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Cerrada"</string>
 </resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 68a0429..1e5caa6 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Päringule „<xliff:g id="QUERY">%1$s</xliff:g>” ei vastanud ükski rakendus"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Otsi rohkem rakendusi"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Märguanded"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Otsetee valimiseks puudutage seda pikalt."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Sellel avaekraanil pole enam ruumi."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Salves Lemmikud pole rohkem ruumi"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Rakenduste loend"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Isiklike rakenduste loend"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Töörakenduste loend"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Avaekraan"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eemalda"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Kaust: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Vidinad"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustapildid"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Avalehe seaded"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Avaekraani seaded"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Keelas administraator"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Ülevaade"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Luba avaekraani pööramine"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kui telefoni pööratakse"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Praegune kuvaseade ei luba pööramist"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Märguandetäpid"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Sees"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Väljas"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Vaja on juurdepääsu märguannetele"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Märguandetäppide kuvamiseks lülitage sisse rakenduse <xliff:g id="NAME">%1$s</xliff:g> märguanded"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Seadete muutmine"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Kuva märguandetäpid"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisa ikoon avaekraanile"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uute rakenduste puhul"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikooni kuju muutmine"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"avaekraanil"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Kasuta süsteemi vaikeseadet"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Ruut"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Ümarate nurkadega ruut"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> allalaadimine, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> on installimise ootel"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Teenuse <xliff:g id="NAME">%1$s</xliff:g> vidinad"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Vidinate loend"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Vidinate loend on suletud"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Lisa avaekraanile"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Teisalda üksus siia"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Üksus lisati avaekraanile"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Kausta loomine nimega <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Kaust on loodud"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Teisalda avaekraanile"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Teisalda ekraan vasakule"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Teisalda ekraan paremale"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekraan teisaldati"</string>
     <string name="action_resize" msgid="1802976324781771067">"Muuda suurust"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Suurenda laiust"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Suurenda kõrgust"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Vähenda kõrgust"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidina suurust muudeti. Laius: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Kõrgus: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Otseteed"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed rakenduse <xliff:g id="APP_NAME">%2$s</xliff:g> jaoks"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> otseteed ja <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> märguannet rakendusele <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Otseteed ja märguanded"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Loobu"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Märguandest loobuti"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Isiklik"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Tööprofiil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Töörakendused leiate siit"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Igal töörakendusel on oranž märk ja teie organisatsioon tagab selle turvalisuse. Teisaldage rakendused avaekraanile, et neile oleks lihtsam juurde pääseda."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Igal töörakendusel on märk ja teie organisatsioon tagab selle turvalisuse. Teisaldage rakendused avaekraanile, et neile oleks lihtsam juurde pääseda."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Haldab teie organisatsioon"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Märguanded ja rakendused on välja lülitatud"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sule"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Suletud"</string>
 </resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 27a56dd..b69228a 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ez da aurkitu \"<xliff:g id="QUERY">%1$s</xliff:g>\" bilaketaren emaitzarik"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Bilatu aplikazio gehiago"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Jakinarazpenak"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Eduki sakatuta lasterbide bat aukeratzeko."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Hasierako pantaila honetan ez dago toki gehiago."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Aplikazioen zerrenda"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Aplikazio pertsonalen zerrenda"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Laneko aplikazioen zerrenda"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Hasiera"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Kendu"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalatu"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Horma-paperak"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Hasierako pantailaren ezarpenak"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratzaileak desgaitu du"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Ikuspegi orokorra"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Baimendu hasierako pantaila biratzea"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefonoa biratzen denean"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Uneko pantaila-ezarpenak ez du onartzen ikuspegia biratzea"</string>
-    <string name="icon_badging_title" msgid="874121399231955394">"Jakinarazteko biribiltxoak"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"Jakinarazpen-biribiltxoak"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktibatuta"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desaktibatuta"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Jakinarazpenetarako sarbidea behar da"</string>
-    <string name="msg_missing_notification_access" msgid="281113995110910548">"Jakinarazteko biribiltxoak ikusteko, aktibatu <xliff:g id="NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Jakinarazpen-biribiltxoak ikusteko, aktibatu <xliff:g id="NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Aldatu ezarpenak"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Erakutsi jakinarazpen-biribiltxoak"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Gehitu ikonoa hasierako pantailan"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Aplikazio berrietan"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Aldatu ikonoaren forma"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Hasierako pantailan"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Erabili sistemaren balio lehenetsiak"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Karratua"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Ertz biribilduko karratua"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgetak"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widget-zerrenda"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Itxi da widget-zerrenda"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Gehitu hasierako pantailan"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Ekarri elementua hona"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua hasierako pantailan"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Sortu karpeta <xliff:g id="NAME">%1$s</xliff:g> elementuarekin"</string>
     <string name="folder_created" msgid="6409794597405184510">"Karpeta sortu da"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Eraman hasierako pantailara"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Eraman pantaila ezkerrera"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Eraman pantaila eskuinera"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Mugitu da pantaila"</string>
     <string name="action_resize" msgid="1802976324781771067">"Aldatu tamaina"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Handitu zabalera"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Handitu altuera"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Txikitu altuera"</string>
     <string name="widget_resized" msgid="9130327887929620">"Aldatu da widgetaren tamaina. Zabalera: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Altuera: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Lasterbideak"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioaren <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> lasterbide"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> aplikazioaren <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> lasterbide eta <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> jakinarazpen"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Lasterbideak eta jakinarazpenak"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Baztertu"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Baztertu egin da jakinarazpena"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pertsonalak"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Laneko profila"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hemen dituzu laneko aplikazioak"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Laneko aplikazio bakoitzak bereizgarri laranja bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Laneko aplikazio bakoitzak bereizgarri bat dauka eta erakundeak babesten du. Aplikazioak errazago atzitzeko, eraman itzazu hasierako pantailara."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Erakundeak kudeatzen du"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Jakinarazpenak eta aplikazioak desaktibatuta daude"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Itxi"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Itxita"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 128af90..aa06188 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"هیچ برنامه‌ای در مطابقت با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"جستجوی برنامه‌های بیشتر"</string>
     <string name="notifications_header" msgid="1404149926117359025">"اعلان‌ها"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"برای انتخاب میان‌بر، لمس کنید و نگه‌دارید."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"برای انتخاب میان‌بر، دو ضربه سریع بزنید و نگه‌دارید یا از کنش‌های سفارشی استفاده کنید."</string>
     <string name="out_of_space" msgid="4691004494942118364">"فضای بیشتری در این صفحه اصلی موجود نیست."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"فضای بیشتری در سینی موارد دلخواه وجود ندارد"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"فهرست برنامه‌ها"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"فهرست برنامه‌های شخصی"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"فهرست برنامه‌های کاری"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"صفحه اصلی"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"برداشتن"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"حذف نصب"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"کاغذدیواری‌ها"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"تنظیمات صفحه اصلی"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"توسط سرپرست سیستم غیرفعال شده است"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"نمای کلی"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"امکان دادن به چرخش صفحه اصلی"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"وقتی تلفن چرخانده می‌شود"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"تنظیم نمایشگر کنونی اجازه چرخش نمی‌دهد"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"نقطه‌های اعلان"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"روشن"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"خاموش"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"دسترسی به اعلان نیاز است"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"برای نمایش «نقطه‌های اعلان»، اعلان‌های برنامه را برای <xliff:g id="NAME">%1$s</xliff:g> روشن کنید"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"تغییر تنظیمات"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"نمایش نقطه‌های اعلان"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"افزودن نماد به صفحه اصلی"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"برای برنامه‌های جدید"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"تغییر شکل نماد"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"در صفحه اصلی"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"استفاده از پیش‌فرض سیستم"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"مربع"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"مربع با گوشه‌های گرد"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"درحال بارگیری <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="PROGRESS">%2$s</xliff:g> کامل شد"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> درانتظار نصب"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ابزارک‌های <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"فهرست ابزارک‌ها"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"فهرست ابزارک‌ها بسته شد"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"افزودن به صفحه اصلی"</string>
     <string name="action_move_here" msgid="2170188780612570250">"انتقال مورد به اینجا"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"مورد به صفحه اصلی اضافه شد"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ایجاد پوشه با: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"پوشه ایجاد شد"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"انتقال به صفحه اصلی"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"انتقال صفحه به چپ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"انتقال صفحه به راست"</string>
-    <string name="screen_moved" msgid="266230079505650577">"صفحه منتقل شد"</string>
     <string name="action_resize" msgid="1802976324781771067">"تغییر اندازه"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"افزایش عرض"</string>
     <string name="action_increase_height" msgid="459390020612501122">"افزایش ارتفاع"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"کاهش ارتفاع"</string>
     <string name="widget_resized" msgid="9130327887929620">"اندازه ابزارک به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"میان‌برها"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> میانبر برای <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> میان‌بر و <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> اعلان برای <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"میان‌برها و اعلان‌ها"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"رد کردن"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"اعلان رد شد"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"اینجا برنامه‌های کاری را پیدا کنید"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"همه برنامه‌های کاری نشان نارنجی‌رنگی دارند و توسط سازمان شما امن نگه داشته می‌شود. برنامه‌های کاری را برای دسترسی آسان‌تر به صفحه اصلی انتقال دهید."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"همه برنامه‌های کاری نشانی دارند و توسط سازمانتان ایمن نگه داشته می‌شوند. برنامه‌های کاری را برای دسترسی آسان‌تر به صفحه اصلی انتقال دهید."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"توسط سازمانتان مدیریت می‌شود"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"اعلان‌ها و برنامه‌ها خاموش هستند"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"بستن"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"بسته‌شده"</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index f5b0817..4b361ac 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> ei palauttanut sovelluksia."</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Hae lisää sovelluksia"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Ilmoitukset"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Valitse pikakuvake painamalla sitä pitkään."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tässä aloitusruudussa ei ole enää tilaa."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Suosikit-valikossa ei ole enää tilaa"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Sovellusluettelo"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Omat sovellukset ‑luettelo"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Työsovellusluettelo"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Aloitusruutu"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Poista"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustakuvat"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Kotiasetukset"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Järjestelmänvalvoja on poistanut toiminnon käytöstä."</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Yleiskatsaus"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Salli aloitusnäytön kiertäminen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kun puhelinta kierretään"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Nykyiset näyttöasetukset eivät salli näytön kiertämistä."</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pistemerkit"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Käytössä"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Pois käytöstä"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Ilmoituksien käyttöoikeus tarvitaan"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"<xliff:g id="NAME">%1$s</xliff:g> tarvitsee ilmoitusten käyttöoikeuden, jotta pistemerkkejä voidaan näyttää."</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Muuta asetuksia"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Näytä ilmoituksista kertovat pistemerkit"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lisää kuvake aloitusruutuun"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Uusille sovelluksille"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Muuta kuvakkeen muotoa"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"aloitusnäytöllä"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Käytä järjestelmän oletusarvoa"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Neliö"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Ympyräneliö"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> latautuu, valmiina <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> odottaa asennusta"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgetit: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widget-luettelo"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widget-luettelo suljettu"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Lisää aloitusnäytölle"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Siirrä kohde tänne"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Kohde lisättiin aloitusnäytölle."</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Luo kansio, jossa on <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="folder_created" msgid="6409794597405184510">"Kansio on luotu."</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Siirrä aloitusnäytölle"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Siirrä näyttöä vasemmalle"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Siirrä näyttöä oikealle"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Näyttö siirrettiin."</string>
     <string name="action_resize" msgid="1802976324781771067">"Muuta kokoa"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Lisää leveyttä"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Lisää korkeutta"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Vähennä korkeutta"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetin kokoa muutettiin. Sen leveys on nyt <xliff:g id="NUMBER_0">%1$s</xliff:g> ja korkeus <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pikakuvakkeet"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Sovelluksella <xliff:g id="APP_NAME">%2$s</xliff:g> on <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pikakuvaketta."</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pikakuvaketta ja <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ilmoitusta"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pikakuvakkeet ja ilmoitukset"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hylkää"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Ilmoitus hylätty"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Henkilökohtaiset"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Työsovellukset"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Työprofiili"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Etsi työsovelluksia tästä"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kaikissa työsovelluksissa on oranssi merkki ja ne ovat organisaatiosi suojaamia. Voit siirtää työsovelluksia aloitusnäytölle käytön helpottamiseksi."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Kaikki työsovellukset on merkitty, ja organisaatiosi vastaa niiden suojaamisesta. Voit siirtää työsovelluksia aloitusnäytölle käytön helpottamiseksi."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Organisaatiosi hallinnoima"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Ilmoitukset ja sovellukset ovat poissa käytöstä"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sulje"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Suljettu"</string>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 4093535..29b003e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Maintenez un doigt sur le raccourci pour l\'ajouter"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur l\'écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Il n\'y a plus d\'espace dans la zone des favoris"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Liste des applications"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste des applications personnelles"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste des applications professionnelles"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Accueil"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Paramètres d\'accueil"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Cette fonction est désactivée par votre administrateur"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Présentation"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Le mode d\'affichage actuel ne permet pas le pivotement"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Points de notification"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"L\'accès aux notifications est requis"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les points de notification, activez les notifications d\'application pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Afficher les points de notification"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme de l\'icône"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"sur l\'écran d\'accueil"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser les valeurs système par défaut"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Carré aux coins ronds"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Téléchargement de <xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Liste des widgets fermée"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Ajouter à l\'écran d\'accueil"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Élément ajouté à l\'écran d\'accueil"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Créer un dossier avec : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Dossier créé"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Déplacer sur l\'écran d\'accueil"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Déplacer l\'écran à gauche"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Déplacer l\'écran à droite"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Écran déplacé"</string>
     <string name="action_resize" msgid="1802976324781771067">"Redimensionner"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Augmenter la largeur"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Augmenter la hauteur"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
     <string name="widget_resized" msgid="9130327887929620">"Le widget a été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Raccourcis"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> raccourcis pour <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> raccourcis et <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifications pour <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Raccourcis et notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorer"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notification ignorée"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personnel"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Trouvez ici des applications professionnelles"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Chaque application professionnelle comporte un badge orange, ce qui signifie qu\'elle est sécurisée par votre organisation. Vous pouvez déplacer vos applications vers l\'écran d\'accueil afin d\'y accéder plus facilement."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Chaque application professionnelle comporte un badge, ce qui signifie qu\'elle est sécurisée par votre organisation. Vous pouvez déplacer vos applications vers l\'écran d\'accueil afin d\'y accéder plus facilement."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fermer"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fermé"</string>
 </resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 520ad78..d47ab42 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Appui prolongé pour sélectionner un raccourci."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Appuyez 2X et maintenez la pression pour choisir un raccourci ou utilisez les actions personnalisées"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur cet écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Plus d\'espace disponible dans la zone de favoris."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Liste d\'applications"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste des applications personnelles"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste des applications professionnelles"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Accueil"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Dossier \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Paramètres de l\'écran d\'accueil"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Paramètres accueil"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Désactivé par votre administrateur"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Vue d\'ensemble"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Autoriser la rotation de l\'écran d\'accueil"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Lorsque vous faites pivoter le téléphone"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Le paramètre d\'affichage actuel n\'autorise pas la rotation."</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pastilles de notification"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activé"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Désactivé"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Accès aux notifications requis"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les pastilles de notification, activez les notifications de l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Afficher les pastilles de notification"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ajouter l\'icône à l\'écran d\'accueil"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Modifier la forme des icônes"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"sur l\'écran d\'accueil"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utiliser la valeur système par défaut"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Carré"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> en cours de téléchargement, <xliff:g id="PROGRESS">%2$s</xliff:g> effectué(s)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"La liste des widgets est fermée"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Ajouter à l\'écran d\'accueil"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"L\'élément a bien été ajouté à l\'écran d\'accueil."</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Créer un dossier avec \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="folder_created" msgid="6409794597405184510">"Dossier créé"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Déplacer vers l\'écran d\'accueil"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Déplacer l\'écran vers la gauche"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Déplacer l\'écran vers la droite"</string>
-    <string name="screen_moved" msgid="266230079505650577">"L\'écran a bien été déplacé."</string>
     <string name="action_resize" msgid="1802976324781771067">"Redimensionner"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Augmenter la largeur"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Augmenter la hauteur"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
     <string name="widget_resized" msgid="9130327887929620">"Le widget a bien été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Raccourcis"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> raccourcis pour <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> raccourcis et <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifications pour <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Raccourcis et notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorer"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notification ignorée"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personnelles"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Professionnelles"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Retrouvez ici vos applications professionnelles"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Les applications professionnelles sont accompagnées d\'un badge orange et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Les applications professionnelles sont accompagnées d\'un badge et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Géré par votre organisation"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Les notifications et les applications sont désactivées"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fermer"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fermé"</string>
 </resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9a842b1..b94d693 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar máis aplicacións"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificacións"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Mantén premido un atallo para seleccionalo."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Non hai máis espazo nesta pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Non hai máis espazo na bandexa de favoritos"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicacións"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicacións persoais"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicacións de traballo"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Cartafol: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Configuración de inicio"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Configuración da pantalla de Inicio"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Función desactivada polo administrador"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Visión xeral"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir xirar a pantalla de inicio"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Ao xirar o teléfono"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"A configuración de visualización actual non permite xirar a pantalla"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Puntos de notificacións"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activado"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desactivado"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Necesítase acceso ás notificacións"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para que se mostren os puntos de notificacións, activa as notificacións da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Cambiar configuración"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar puntos de notificación"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Engadir icona á pantalla de inicio"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicacións"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambiar forma das iconas"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na pantalla de inicio"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar valores predeterminados do sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Cadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Cadrado de bordos redondeados"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Pechouse a lista de widgets"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Engadir á pantalla de inicio"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Engadiuse o elemento á pantalla de inicio"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Crear cartafol con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Creouse o cartafol"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover á pantalla de inicio"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla á esquerda"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla á dereita"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Moveuse a pantalla"</string>
     <string name="action_resize" msgid="1802976324781771067">"Cambiar tamaño"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Cambiouse o tamaño do widget polo ancho <xliff:g id="NUMBER_0">%1$s</xliff:g> e a altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atallos"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atallos para <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atallos e <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificacións para a aplicación <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atallos e notificacións"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorar"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Ignorouse a notificación"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persoal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Traballo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de traballo"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Buscar aplicacións do traballo aquí"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"As aplicacións do traballo teñen unha insignia laranxa e están protexidas pola túa organización. Traslada as aplicacións á pantalla de inicio para acceder a elas de forma máis fácil."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"As aplicacións do traballo teñen unha insignia e están protexidas pola túa organización. Traslada as aplicacións á pantalla de inicio para acceder a elas de forma máis fácil."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Perfil xestionado pola túa organización"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"As notificacións e as aplicacións están desactivadas"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Pechar"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Pechada"</string>
 </resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index e030659..d4f6bbb 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"વધુ ઍપ્લિકેશનો શોધો"</string>
     <string name="notifications_header" msgid="1404149926117359025">"નોટિફિકેશનો"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"એક શૉર્ટકટ ચૂંટવા માટે સ્પર્શ કરી રાખો."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરીને દબાવી રાખો."</string>
     <string name="out_of_space" msgid="4691004494942118364">"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"મનપસંદ ટ્રે પર વધુ જગ્યા નથી"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ઍપ્લિકેશનોની સૂચિ"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"વ્યક્તિગત ઍપની સૂચિ"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"કાર્યસ્થળની ઍપની સૂચિ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"હોમ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"દૂર કરો"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટોલ કરો"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"વૉલપેપર્સ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"હોમ સેટિંગ્સ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ઝલક"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"જ્યારે ફોન ફેરવવામાં આવે ત્યારે"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"વર્તમાન પ્રદર્શન સેટિંગ ફેરવવાની પરવાનગી આપતી નથી"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"સૂચના બિંદુઓ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ચાલુ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"બંધ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"નોટિફિકેશનનો ઍક્સેસની જરૂરી છે"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"નોટિફિકેશન માટેનું ચિહ્ન બતાવવા હેતુ, <xliff:g id="NAME">%1$s</xliff:g> માટેની ઍપ્લિકેશન નોટિફિકેશન ચાલુ કરો"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"સેટિંગ્સ બદલો"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"નોટિફિકેશન માટેનું ચિહ્ન બતાવો"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"હોમ સ્ક્રીન પર આઇકન ઉમેરો"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"નવી ઍપ્લિકેશનો માટે"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"આઇકનનો આકાર બદલો"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"હોમ સ્ક્રીન પર"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"સિસ્ટમ ડિફૉલ્ટનો ઉપયોગ કરો"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ચોરસ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ચોરસ જેવું ગોળ"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> વિજેટ"</string>
+    <string name="widgets_list" msgid="796804551140113767">"વિજેટની સૂચિ"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"વિજેટની સૂચિ બંધ કરવામાં આવી છે"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"હોમ સ્ક્રીન પર ઉમેરો"</string>
     <string name="action_move_here" msgid="2170188780612570250">"આઇટમ અહીં ખસેડો"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"હોમ સ્ક્રીનમાં આઇટમ ઉમેરી"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"આની સાથે ફોલ્ડર બનાવો: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ફોલ્ડર બનાવ્યું"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"હોમ સ્ક્રીન પર ખસેડો"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"સ્ક્રીનને ડાબી બાજુ ખસેડો"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"સ્ક્રીનને જમણી બાજુ ખસેડો"</string>
-    <string name="screen_moved" msgid="266230079505650577">"સ્ક્રીન ખસેડી"</string>
     <string name="action_resize" msgid="1802976324781771067">"આકાર બદલો"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"પહોળાઈ વધારો"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ઊંચાઈ વધારો"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ઊંચાઈ ઘટાડો"</string>
     <string name="widget_resized" msgid="9130327887929620">"વિજેટનો આકાર બદલીને <xliff:g id="NUMBER_0">%1$s</xliff:g> પહોળાઈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ઊંચાઈ કર્યો"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"શૉર્ટકટ્સ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> માટે <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> શૉર્ટકટ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> માટે <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> શૉર્ટકટ અને <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> સૂચનાઓ"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"શૉર્ટકટ અને નોટિફિકેશનો"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"છોડી દો"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"કાર્યાલયની પ્રોફાઇલ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"કાર્ય ઍપને અહીંથી મેળવો"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"દરેક કાર્ય ઍપ પાસે એક નારંગી બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"દરેક કાર્ય ઍપ પાસે એક બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"નોટિફિકેશન અને ઍપ બંધ છે"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"બંધ કરો"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"બંધ"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index aa1e8dd..ee8e6e3 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"और ऐप सर्च करें"</string>
     <string name="notifications_header" msgid="1404149926117359025">"सूचनाएं"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"शॉर्टकट चुनने के लिए दबाकर रखें."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"शॉर्टकट चुनने या पसंद के मुताबिक कार्रवाई करने के लिए दो बार टैप करें और कुछ देर दबाए रखें."</string>
     <string name="out_of_space" msgid="4691004494942118364">"इस होम स्‍क्रीन पर जगह नहीं बची है"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"पसंदीदा ट्रे में और जगह नहीं है"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ऐप्लिकेशन सूची"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"निजी ऐप्लिकेशन की सूची"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"काम से जुड़े ऐप्लिकेशन की सूची"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"होम पेज"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"निकालें"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करें"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"होम पेज की सेटिंग"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपके एडमिन ने बंद किया हुआ है"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"खास जानकारी"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"होमस्क्रीन घुमाने की अनुमति दें"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फ़ोन घुुमाए जाने पर"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"इस डिसप्ले सेटिंग में रोटेशन (स्क्रीन पर सामग्री को घुमाकर देखने) की सुविधा काम नहीं करती"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"सूचना बिंदु"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"चालू"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"बंद"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के एक्सेस की ज़रूरत है"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीन में आइकॉन जोड़ें"</string>
-    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप के लिए"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"आइकॉन का आकार बदलें"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"होम स्‍क्रीन पर"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"सिस्टम डिफ़ॉल्ट का उपयोग करें"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"वर्ग"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"गोल कोनों वाला वर्ग"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड हो रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> के इंस्टॉल होने की प्रतीक्षा की जा रही है"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेट"</string>
+    <string name="widgets_list" msgid="796804551140113767">"विजेट की सूची"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"विजेट की सूची बंद हो गई है"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्‍क्रीन में जोड़ें"</string>
     <string name="action_move_here" msgid="2170188780612570250">"आइटम यहां ले जाएं"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"होम स्क्रीन में आइटम जोड़ा गया"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"इसके साथ फ़ोल्डर बनाएं: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"फ़ोल्डर बनाया गया"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"होम स्क्रीन पर ले जाएं"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रीन को बाएं ले जाएं"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रीन को दाएं ले जाएं"</string>
-    <string name="screen_moved" msgid="266230079505650577">"स्क्रीन ले जाई गई"</string>
     <string name="action_resize" msgid="1802976324781771067">"आकार बदलें"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"चौड़ाई बढ़ाएं"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ऊंचाई बढ़ाएं"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ऊंचाई घटाएं"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेट का आकार बदलकर उसकी चौड़ाई <xliff:g id="NUMBER_0">%1$s</xliff:g> और ऊंचाई <xliff:g id="NUMBER_1">%2$s</xliff:g> कर दी गई"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"शॉर्टकट"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> के लिए <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> के लिए <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट और <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचनाएं हैं"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"शॉर्टकट और सूचनाएं"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारिज करें"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना को खारिज किया गया"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"निजी ऐप"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"काम से जुड़े ऐप"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफ़ाइल"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"काम से जुड़े सभी ऐप्लिकेशन यहां पाएं"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"काम से जुड़े हर ऐप्लिकेशन पर एक नारंगी रंग का बैज (निशान) होता है जिसकी सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"काम से जुड़े हर ऐप्लिकेशन पर एक बैज (निशान) होता है और इन ऐप्लिकेशन की सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"आपका संगठन प्रबंधित कर रहा है"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"सूचनाएं और ऐप्लिकेशन बंद हैं"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करें"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद कर दिया गया"</string>
 </resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ec3c6b2..ea340d6 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Traži više aplikacija"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obavijesti"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Dodirnite i zadržite kako biste podigli prečac."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom zaslonu više nema mjesta."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Favoriti"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Popis aplikacija"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Popis osobnih aplikacija"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Popis radnih aplikacija"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
@@ -76,21 +80,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Mapa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgeti"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadine"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Postavke Homea"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Postavke početnog zaslona"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogućio administrator"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Pregled"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Dopusti zakretanje početnog zaslona"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon zakrene"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Trenutačna postavka zaslona ne dopušta zakretanje"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Točke obavijesti"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Uključeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Isključeno"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup obavijestima"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz točaka obavijesti uključite obavijesti aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Promjena postavki"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Prikaži točke obavijesti"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonu na početni zaslon"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Promijeni oblik ikona"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na početnom zaslonu"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Upotrijebi zadane postavke sustava"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljeni kvadrat"</string>
@@ -105,6 +109,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Preuzimanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, dovršeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Čekanje na instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgeti"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Popis widgeta"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Popis widgeta zatvoren"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodavanje na početni zaslon"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na početni zaslon"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Izrada mape pomoću stavke: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mapa izrađena"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Premještanje na početni zaslon"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Premještanje zaslona ulijevo"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Premještanje zaslona udesno"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Zaslon je premješten"</string>
     <string name="action_resize" msgid="1802976324781771067">"Promjena veličine"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Povećanje širine"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Povećanje visine"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanjenje visine"</string>
     <string name="widget_resized" msgid="9130327887929620">"Širina widgeta promijenjena je na <xliff:g id="NUMBER_0">%1$s</xliff:g>, a visina na <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečaci"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Prečaca za aplikaciju <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Za aplikaciju <xliff:g id="APP_NAME">%3$s</xliff:g> ima prečaca (ukupno <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) i obavijesti (ukupno <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>)"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečaci i obavijesti"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Obavijest je odbačena"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobno"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ovdje možete pronaći radne aplikacije"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Svaka radna aplikacija ima narančastu značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Svaka radna aplikacija ima značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Pod upravljanjem vaše organizacije"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Obavijesti i aplikacije isključeni su"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zatvori"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zatvoreno"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 697153a..7b87381 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nem található alkalmazás a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"További alkalmazások keresése"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Értesítések"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Felvételhez tartsa nyomva a parancsikont."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nincs több hely ezen a kezdőképernyőn."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nincs több hely a Kedvencek tálcán"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Alkalmazások listája"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Személyes alkalmazások listája"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Munkahelyi alkalmazások listája"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Főoldal"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Törlés"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Mappa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Modulok"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Háttérképek"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"A Home beállításai"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Kezdőoldal beállításai"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"A rendszergazda letiltotta"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Áttekintés"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"A kezdőképernyő elforgatásának engedélyezése"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"A telefon elforgatásakor"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"A jelenlegi kijelzőbeállítások nem teszik lehetővé az elforgatást"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Értesítési pöttyök"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Bekapcsolva"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kikapcsolva"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Értesítésekhez való hozzáférésre van szükség"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Az értesítési pöttyök megjelenítéséhez kapcsolja be a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazás értesítéseit"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Beállítások módosítása"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Értesítési pöttyök megjelenítése"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ikon hozzáadása a kezdőképernyőhöz"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Új alkalmazásoknál"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikon formájának módosítása"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"a kezdőképernyőn"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Alapértelmezett érték használata"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Négyzet"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"A(z) <xliff:g id="NAME">%1$s</xliff:g> letöltése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A(z) <xliff:g id="NAME">%1$s</xliff:g> telepítésre vár"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-modulok"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetlista bezárva"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Hozzáadás a kezdőképernyőhöz"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Elem áthelyezése ide"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elem hozzáadva a kezdőképernyőhöz"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Mappa létrehozása a következővel: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mappa létrehozva"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Áthelyezés a kezdőképernyőre"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Képernyő mozgatása balra"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Képernyő mozgatása jobbra"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Képernyő áthelyezve"</string>
     <string name="action_resize" msgid="1802976324781771067">"Átméretezés"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Szélesség növelése"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Magasság növelése"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Magasság csökkentése"</string>
     <string name="widget_resized" msgid="9130327887929620">"Modul átméretezve <xliff:g id="NUMBER_0">%1$s</xliff:g> szélességre és <xliff:g id="NUMBER_1">%2$s</xliff:g> magasságra"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Gyorsparancsok"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> gyorsparancs a(z) <xliff:g id="APP_NAME">%2$s</xliff:g> számára"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> parancsikon és <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> értesítés a következő alkalmazásnál: <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Parancsikonok és értesítések"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Elvetés"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Értesítés elvetve"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Személyes"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Munkahelyi"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Munkaprofil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Itt kereshet munkahelyi alkalmazásokat"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Az egyes munkahelyi alkalmazásokon narancs jelvény található, és biztonságukról az Ön szervezete gondoskodik. A könnyebb hozzáférés érdekében helyezze át az alkalmazásokat a kezdőképernyőre."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"A munkahelyi alkalmazásoknál jelvény található, és biztonságukról az Ön szervezete gondoskodik. A könnyebb hozzáférés érdekében helyezze át az alkalmazásokat a kezdőképernyőre."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Az Ön szervezete kezeli"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Az értesítések és az alkalmazások ki vannak kapcsolva"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Bezárás"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Bezárva"</string>
 </resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 02a561f..2b4a38b 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"«<xliff:g id="QUERY">%1$s</xliff:g>» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Որոնել այլ հավելվածներ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Ծանուցումներ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Այլևս տեղ չկա այս հիմնական էկրանին:"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ընտրյալների ցուցակում այլևս ազատ տեղ չկա"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Հավելվածների ցանկ"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Անձնական հավելվածների ցանկ"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Աշխատանքային հավելվածների ցանկ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Հիմնական"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Հեռացնել"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Հեռացնել"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Պաստառներ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Գլխավոր էջի կարգավորումներ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Անջատվել է ձեր ադմինիստրատորի կողմից"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Համատեսք"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Թույլ տալ հիմնական էկրանի պտտումը"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Հեռախոսը պտտելու դեպքում"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Ցուցադրման ընթացիկ կարգավորումներն արգելում են պտտումը"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Ծանուցումների կետիկներ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Միացված է"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Անջատված է"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Անհրաժեշտ է ծանուցման թույլտվություն"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները <xliff:g id="NAME">%1$s</xliff:g>-ի համար"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Փոխել կարգավորումները"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Ցուցադրել ծանուցումների կետիկները"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ավելացնել պատկերակը Հիմնական էկրանին"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Նոր հավելվածների համար"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Փոխել պատկերակների տեսքը"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"հիմնական էկրանին"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Օգտագործել համակարգի կանխադրված կարգավորումը"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Քառակուսի"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Քառանկյուն"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>–ի ներբեռնում (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>-ի տեղադրման սպասում"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> վիջեթներ"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Վիջեթների ցանկ"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Վիջեթների ցանկը փակվեց"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Ավելացնել Հիմնական էկրանին"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Տեղափոխել տարրն այստեղ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Տարրն ավելացվեց հիմնական էկրանին"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Ստեղծել թղթապանակ, օգտագործելով՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Պանակը ստեղծվեց"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Տեղափոխել Հիմնական էկրան"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Տեղափոխել էկրանը ձախ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Տեղափոխել էկրանը աջ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Էկրանը տեղափոխվեց"</string>
     <string name="action_resize" msgid="1802976324781771067">"Չափափոխել"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Ավելացնել լայնությունը"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Ավելացնել բարձրությունը"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Նվազեցնել բարձրությունը"</string>
     <string name="widget_resized" msgid="9130327887929620">"Վիջեթի լայնությունը փոխվել է <xliff:g id="NUMBER_0">%1$s</xliff:g>-ի, իսկ բարձրությունը՝ <xliff:g id="NUMBER_1">%2$s</xliff:g>-ի"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Դյուրանցումներ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> դյուրանցումներ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածի համար"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> դյուրացում և <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ծանուցում <xliff:g id="APP_NAME">%3$s</xliff:g>-ի համար"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Դյուրանցումներ և ծանուցումներ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Անտեսել"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Ծանուցումը մերժված է"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Անձնական"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Գտեք աշխատանքային հավելվածներ այստեղ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Աշխատանքային հավելվածները նշված են նարնջագույն նշանով, նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Աշխատանքային հավելվածները նշված են հատուկ նշանով: Նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Կառավարվում է ձեր կազմակերպության կողմից"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Ծանուցումներն ու հավելվածներն անջատված են"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Փակել"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Փակվեց"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index d115c73..78ffc96 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -30,7 +30,7 @@
     <string name="home_screen" msgid="806512411299847073">"Layar utama"</string>
     <string name="custom_actions" msgid="3747508247759093328">"Tindakan khusus"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh lama untuk memilih widget."</string>
-    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ketuk dua kalip &amp; tahan untuk mengambil widget atau menggunakan tindakan khusus."</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tap dua kalip &amp; tahan untuk mengambil widget atau menggunakan tindakan khusus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sentuh &amp; tahan untuk menempatkan secara manual"</string>
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Tidak ditemukan aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Telusuri aplikasi lainnya"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifikasi"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tap lama untuk memilih pintasan."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Tap dua kali &amp; tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tidak ada ruang tersisa di baki Favorit"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Daftar aplikasi"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Daftar aplikasi pribadi"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Daftar aplikasi kantor"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Layar Utama"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
@@ -68,8 +72,8 @@
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Halaman layar utama baru"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
-    <string name="folder_tap_to_close" msgid="4625795376335528256">"Ketuk untuk menutup folder"</string>
-    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketuk untuk menyimpan ganti nama"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"Tap untuk menutup folder"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Tap untuk menyimpan ganti nama"</string>
     <string name="folder_closed" msgid="4100806530910930934">"Folder ditutup"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"Folder diganti namanya menjadi <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpaper"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Setelan layar Utama"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dinonaktifkan oleh admin"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Ringkasan"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Izinkan layar Utama diputar"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Saat ponsel diputar"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Setelan Tampilan Saat Ini tidak memungkinkan putaran"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Titik notifikasi"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktif"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Nonaktif"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Perlu akses notifikasi"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Guna menampilkan Titik Notifikasi, aktifkan notifikasi aplikasi untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Ubah setelan"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Tampilkan titik notifikasi"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon ke Layar utama"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk aplikasi baru"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ubah bentuk ikon"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"di layar Utama"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan default sistem"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Persegi"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Persegi bundar"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> sedang didownload, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu dipasang"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widget <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Daftar widget"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Daftar widget ditutup"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Tambahkan ke Layar Utama"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Pindahkan item ke sini"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan ke layar utama"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Pindahkan ke layar Utama"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Pindahkan layar ke kiri"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Pindahkan layar ke kanan"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Layar dipindahkan"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ubah ukuran"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Tambahi lebar"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Tambahi tinggi"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Kurangi tinggi"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget diubah ukurannya menjadi lebar <xliff:g id="NUMBER_0">%1$s</xliff:g> tinggi <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan untuk <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan dan <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifikasi untuk <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pintasan dan notifikasi"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Tutup"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notifikasi ditutup"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pribadi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kantor"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temukan aplikasi kerja di sini"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Setiap aplikasi kerja memiliki badge oranye dan dibuat tetap aman oleh organisasi. Pindahkan aplikasi ke Layar utama untuk memudahkan akses."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Setiap aplikasi kerja memiliki badge dan dibuat tetap aman oleh organisasi. Pindahkan aplikasi ke Layar utama untuk memudahkan akses."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Dikelola oleh organisasi"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notifikasi dan aplikasi nonaktif"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tutup"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Ditutup"</string>
 </resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index ba9a47d..04842e4 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ekki fundust forrit sem samsvara „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Leita að fleiri forritum"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Tilkynningar"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Haltu fingri á flýtileið til að grípa hana."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Ekki meira pláss á þessum heimaskjá."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ekki meira pláss í bakka fyrir uppáhald"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Forritalisti"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Listi yfir eigin forrit"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Listi yfir vinnuforrit"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Heim"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjarlægja"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Veggfóður"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Heimastillingar"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gert óvirkt af kerfisstjóra"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Yfirlit"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Leyfa snúning fyrir heimaskjá"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Þegar símanum er snúið"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Núverandi skjástilling leyfir ekki snúning"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Tilkynningapunktar"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Kveikt"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Slökkt"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Aðgangs að tilkynningum er krafist"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Breyta stillingum"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Sýna tilkynningapunkta"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Bæta tákni á heimaskjáinn"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Fyrir ný forrit"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Breyta formi tákns"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"á heimaskjá"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Nota sjálfgildi kerfis"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Ferningur"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Ferhringur"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> í niðurhali, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> bíður uppsetningar"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-græjur"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Græjulisti"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Græjulista lokað"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Bæta á heimaskjá"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Færa atriði hingað"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Atriði bætt á heimaskjáinn"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Búa til möppu með: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mappa búin til"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Færa á heimaskjá"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Færa skjá til vinstri"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Færa skjá til hægri"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skjár færður"</string>
     <string name="action_resize" msgid="1802976324781771067">"Breyta stærð"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Auka breidd"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Auka hæð"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Minnka hæð"</string>
     <string name="widget_resized" msgid="9130327887929620">"Stærð græju breytt í <xliff:g id="NUMBER_0">%1$s</xliff:g> á breidd og <xliff:g id="NUMBER_1">%2$s</xliff:g> á hæð"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Flýtileiðir"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> flýtileiðir fyrir <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> flýtileiðir og <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> tilkynningar fyrir <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Flýtileiðir og tilkynningar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hunsa"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Tilkynningu lokað"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persónulegt"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Hér finnurðu vinnuforrit"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Öll vinnuforrit eru með appelsínugulu merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn fyrir auðveldari aðgang að þeim."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Öll vinnuforrit eru með merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn til að fá auðveldari aðgang að þeim."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Stjórnað af fyrirtækinu þínu"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Slökkt er á tilkynningum og forritum"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Loka"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lokað"</string>
 </resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 6c98d3e..28a8f93 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cerca altre app"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notifiche"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tocca e tieni premuto per scegliere la scorciatoia"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spazio esaurito nella barra dei Preferiti"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Elenco di app"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Elenco di app personali"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Elenco di app di lavoro"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home page"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Rimuovi"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Sfondi"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Impostazioni Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Disattivata dall\'amministratore"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Panoramica"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Consenti rotazione della schermata Home"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Con il telefono ruotato"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"L\'impostazione corrente del display non consente la rotazione"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Indicatori notifica"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Attiva"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Non attiva"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Accesso alle notifiche necessario"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Per mostrare gli indicatori di notifica, attiva le notifiche per l\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Modifica impostazioni"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostra indicatori di notifica"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Aggiungi icone alla schermata Home"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Per le nuove app"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Cambia la forma delle icone"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"nella schermata Home"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usa impostazione predefinita di sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrato"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Supercerchio"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Download di <xliff:g id="NAME">%1$s</xliff:g> in corso, <xliff:g id="PROGRESS">%2$s</xliff:g> completato"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> in attesa di installazione"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widget di <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Elenco di widget"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Elenco di widget chiuso"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Aggiungi a schermata Home"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Sposta elemento qui"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento aggiunto alla schermata Home"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Crea cartella con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Cartella creata"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Sposta nella schermata Home"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Sposta schermata a sinistra"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Sposta schermata a destra"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Schermata spostata"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ridimensiona"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumenta larghezza"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumenta altezza"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Riduci altezza"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget ridimensionato a larghezza <xliff:g id="NUMBER_0">%1$s</xliff:g>, altezza <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Scorciatoie"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> scorciatoie per <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> scorciatoie e <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notifiche relative a <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Scorciatoie e notifiche"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignora"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notifica ignorata"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personali"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Qui puoi trovare le tue app di lavoro"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ogni app di lavoro è contrassegnata da un badge arancione e viene tenuta al sicuro dalla tua organizzazione. Sposta le app nella schermata Home per accedervi più facilmente."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ogni app di lavoro è contrassegnata da un badge e viene tenuta al sicuro dalla tua organizzazione. Sposta le app nella schermata Home per accedervi più facilmente."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Gestito dalla tua organizzazione"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Le notifiche e le app non sono attive"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Chiudi"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Chiusa"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 43c8520..d4302c6 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"חפש אפליקציות נוספות"</string>
     <string name="notifications_header" msgid="1404149926117359025">"הודעות"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"כדי להוסיף קיצור דרך, יש לגעת בו ולהחזיק אותו."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, יש להקיש על קיצור הדרך פעמיים ולהחזיק אותו."</string>
     <string name="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"אין עוד מקום במגש המועדפים"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"רשימת אפליקציות"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"רשימת אפליקציות אישיות"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"רשימת אפליקציות עבודה"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"דף הבית"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"הסר"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"הסר התקנה"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"טפטים"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"הגדרות דף הבית"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"הושבת על ידי מנהל המערכת שלך"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"סקירה"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"אפשרות סיבוב של מסך דף הבית"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"כאשר הטלפון מסובב"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"הגדרת התצוגה הנוכחית אינה מאפשרת סיבוב"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"סימני הודעות"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"מופעלת"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"כבויה"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"נדרשת גישה להודעות"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"כדי להציג את סימני ההודעות, יש להפעיל הודעות מהאפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"שנה את ההגדרות"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"הצגה של סימן ההודעות"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"הוספת סמל במסך דף הבית"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"לאפליקציות חדשות"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"שינוי הצורה של הסמלים"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"במסך דף הבית"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"השתמש בברירת המחדל של המערכת"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ריבוע"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ריבוע בעל פינות מעוגלות"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"מוריד את <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"מחכה להתקנה של <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ווידג\'טים של <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"רשימת ווידג\'טים"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"רשימת הווידג\'טים נסגרה"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"הוסף למסך דף הבית"</string>
     <string name="action_move_here" msgid="2170188780612570250">"העבר את הפריט לכאן"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"הפריט הועבר אל מסך דף הבית"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"צור תיקייה עם: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"התיקייה נוצרה"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"העבר אל מסך דף הבית"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"הזז את המסך שמאלה"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"הזז את המסך ימינה"</string>
-    <string name="screen_moved" msgid="266230079505650577">"המסך הועבר"</string>
     <string name="action_resize" msgid="1802976324781771067">"שנה גודל"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"הגדל רוחב"</string>
     <string name="action_increase_height" msgid="459390020612501122">"הגדל גובה"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"הקטן גובה"</string>
     <string name="widget_resized" msgid="9130327887929620">"גודל הווידג\'ט שונה - רוחב <xliff:g id="NUMBER_0">%1$s</xliff:g> גובה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"קיצורי דרך"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> קיצורי דרך עבור <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> קיצורי דרך ו-<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> הודעות של <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"קיצורי דרך והודעות"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"סגור"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ההודעה נסגרה"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"אישיות"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"פרופיל עבודה"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ניתן למצוא כאן את אפליקציות העבודה"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"לכל אפליקציית עבודה יש תג כתום ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"לכל אפליקציית עבודה יש תג ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"מנוהל בידי הארגון"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"הודעות ואפליקציות כבויות"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"סגירה"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"סגור"</string>
 </resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 36f3c5e..2598d18 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"他のアプリを検索"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ショートカットを追加するには押し続けます。"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"</string>
     <string name="out_of_space" msgid="4691004494942118364">"このホーム画面に空きスペースがありません。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"お気に入りトレイに空きスペースがありません"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"アプリのリスト"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"個人用アプリのリスト"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"仕事用アプリのリスト"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ホーム"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"削除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"アンインストール"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"壁紙"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ホームの設定"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"管理者により無効にされています"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"概要"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ホーム画面の回転を許可"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"スマートフォンが回転したとき"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"現在の [ディスプレイ] 設定では回転を使用できません"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"通知ドット"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ON"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"OFF"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"通知へのアクセス権限が必要"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"通知ドットを表示するには、「<xliff:g id="NAME">%1$s</xliff:g>」のアプリ通知を ON にしてください"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"設定を変更"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"通知ドットの表示"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ホーム画面にアイコンを追加"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"新しいアプリをダウンロードしたとき"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"アイコンの形の変更"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ホーム画面上"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"システムのデフォルトを使用"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"スクエア"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"スクワークル"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>をダウンロード中、<xliff:g id="PROGRESS">%2$s</xliff:g>完了"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>のインストール待ち"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>のウィジェット"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ウィジェット リスト"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ウィジェット リストを閉じました"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ホーム画面に追加"</string>
     <string name="action_move_here" msgid="2170188780612570250">"アイテムをここに移動"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"アイテムをホーム画面に追加しました"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"「<xliff:g id="NAME">%1$s</xliff:g>」フォルダを作成"</string>
     <string name="folder_created" msgid="6409794597405184510">"フォルダを作成しました"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ホーム画面に移動"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"画面を左に移動"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"画面を右に移動"</string>
-    <string name="screen_moved" msgid="266230079505650577">"画面を移動しました"</string>
     <string name="action_resize" msgid="1802976324781771067">"サイズを変更"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"幅を広くする"</string>
     <string name="action_increase_height" msgid="459390020612501122">"高さを高くする"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"高さを低くする"</string>
     <string name="widget_resized" msgid="9130327887929620">"ウィジェットのサイズを幅<xliff:g id="NUMBER_0">%1$s</xliff:g>、高さ<xliff:g id="NUMBER_1">%2$s</xliff:g>に変更しました"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ショートカット"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>用の <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 件のショートカット"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個のショートカットと <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 件の通知"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ショートカットと通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"表示しない"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"通知を非表示にしました"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人用"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"仕事用"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ここには仕事用アプリが表示されます"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"仕事用アプリにはオレンジのバッジが表示され、組織によって安全に保護されています。仕事用アプリをホーム画面に移動すると、簡単にアクセスできます。"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"仕事用アプリにはバッジが表示され、組織によって安全に保護されています。仕事用アプリをホーム画面に移動すると、簡単にアクセスできます。"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"組織によって管理されています"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"通知とアプリは OFF です"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"閉じる"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"終了"</string>
 </resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index b6d7877..3bdbab7 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"„<xliff:g id="QUERY">%1$s</xliff:g>“-ის თანხვედრი აპები არ მოიძებნა"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"მეტი აპის პოვნა"</string>
     <string name="notifications_header" msgid="1404149926117359025">"შეტყობინებები"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ამ მთავარ ეკრანზე ადგილი აღარ არის."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"რჩეულების თაროზე ადგილი არ არის"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"აპების სია"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"პერსონალური აპების სია"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"სამსახურის აპების სია"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"მთავარი"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ამოშლა"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ფონები"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"მთავარი გვერდის პარამეტრები"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"გათიშულია თქვენი ადმინისტრატორის მიერ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"მიმოხილვა"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"მთავარი ეკრანის შეტრიალების დაშვება"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ტელეფონის შეტრიალებისას"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ბრუნვა დაუშვებელია ჩვენების მიმდინარე პარამეტრებით"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"შეტყობინების ნიშნულები"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ჩართული"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"გამორთული"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"საჭიროა შეტყობინებებზე წვდომა"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"შეტყობინებათა ნიშნულების საჩვენებლად, ჩართეთ აპის შეტყობინებები <xliff:g id="NAME">%1$s</xliff:g>-ისთვის"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"პარამეტრების შეცვლა"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"შეტყობინების ნიშნულების ჩვენება"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ხატულას მთავარ ეკრანზე დამატება"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ახალი აპებისთვის"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ხატულას ფორმის შეცვლა"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"მთავარ ეკრანზე"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ნაგულისხმევი სისტემური პარამეტრების გამოყენება"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"კვადრატი"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"წრეკუთხედი"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"მიმდინარეობს <xliff:g id="NAME">%1$s</xliff:g>-ის ჩამოტვირთვა, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულდა"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ელოდება ინსტალაციას"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-ის ვიჯეტები"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ვიჯეტების სია"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ვიჯეტების სია დაიხურა"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"მთავარ ეკრანზე დამატება"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ერთეულის გადაადგილება აქ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ერთეული დაემატა მთავარ ეკრანს"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"საქაღალდის შექმნა ერთეულით: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"საქაღალდე შექმნილია"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"მთავარ ეკრანზე გადატანა"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"ეკრანის გადატანა მარცხნივ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"ეკრანის გადატანა მარჯვნით"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ეკრანი გადაადგილდა"</string>
     <string name="action_resize" msgid="1802976324781771067">"ზომის შეცვლა"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"სიგანის გაზრდა"</string>
     <string name="action_increase_height" msgid="459390020612501122">"სიმაღლის გაზრდა"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"სიმაღლის შემცირება"</string>
     <string name="widget_resized" msgid="9130327887929620">"ვიჯეტის ზომები შეიცვალა: სიგანე <xliff:g id="NUMBER_0">%1$s</xliff:g> სიმაღლე <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"მალსახმობები"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>-ს აქვს <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> მალსახმობი"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>-ის <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> მალსახმობი და <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> შეტყობინება"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"მალსახმობები და შეტყობინებები"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"დახურვა"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"შეტყობინება დაიხურა"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"პირადი"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"სამსახური"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"აქ თავმოყრილია სამსახურის აპები"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"სამსახურის აპები მონიშნულია სტაფილოსფერი ბეჯით, რაც ნიშნავს, რომ მათ უსაფრთხოებას თქვენი ორგანიზაცია უზრუნველყოფს. მარტივი წვდომისთვის, შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"სამსახურის თითოეულ აპს აქვს ბეჯი, რაც ნიშნავს, რომ მათ უსაფრთხოებას თქვენი ორგანიზაცია უზრუნველყოფს. მარტივი წვდომისთვის, შეგიძლიათ სამსახურის აპები მთავარი ეკრანზე გადაიტანოთ."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"იმართება თქვენი ორგანიზაციის მიერ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"შეტყობინებები და აპები გამორთულია"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"დახურვა"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"დახურული"</string>
 </resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 6c4deec..98afccc 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" сұрауына сәйкес келетін қолданбалар жоқ"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Қосымша қолданбалар іздеу"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Хабарландырулар"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Таңбашаны таңдау үшін оны басып, ұстап тұрыңыз."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Екі рет басып, ұстап тұрып, таңбашаны таңдаңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Бұл Негізгі экранда орын қалмады."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Қалаулылар науасында орын қалмады"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Қолданбалар тізімі"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Жеке қолданбалар тізімі"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Жұмыс қолданбаларының тізімі"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Негізгі"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Жою"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тұсқағаздар"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Негізгі экран параметрлері"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Әкімші өшірді"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Шолу"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Негізгі экранның бұрылуына рұқсат ету"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон бұрылғанда"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Экранның ағымдағы параметрі айналуға рұқсат бермейді"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Хабарландыру белгілері"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Қосулы"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Өшірулі"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Хабарландыруға кіру рұқсаты қажет"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Хабарландыру белгілерін көрсету үшін <xliff:g id="NAME">%1$s</xliff:g> қолданбасының қолданба хабарландыруларын қосыңыз"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Параметрлерді өзгерту"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Хабарландыру белгілерін көрсету"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Негізгі экранға белгіше енгізу"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Жаңа қолданбаларға арналған"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Белгіше пішінін өзгерту"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Негізгі экранда"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Жүйенің әдепкі параметрін пайдалану"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Шаршы"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Жұмыр төртбұрыш"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктелуде, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнату күтілуде"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> виджеті"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Виджеттер тізімі"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Видджеттер тізімі жабылды"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Негізгі экранға қосу"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Элементті мұнда жылжыту"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент негізгі экранға қосылды"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Мына бар қалтаны жасау: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Қалта жасалды"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Негізгі экранға жылжыту"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Экранды солға жылжыту"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Экранды оңға жылжыту"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Экран жылжытылды"</string>
     <string name="action_resize" msgid="1802976324781771067">"Өлшемін өзгерту"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Енін арттыру"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Биіктігін арттыру"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Биіктігін азайту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджет өлшемінің ені <xliff:g id="NUMBER_0">%1$s</xliff:g>, биіктігі <xliff:g id="NUMBER_1">%2$s</xliff:g> болып өзгертілді"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Таңбашалар"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына арналған <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> таңбаша"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> қолданбасының <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> таңбашасы мен <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> хабарландыруы"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Таңбашалар мен хабарландырулар"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Бас тарту"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Хабарландырудан бас тартылды"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Жұмыс"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жұмыс профилі"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жұмыс қолданбалары осы жерде берілген"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Әрбір жұмыс қолданбасында қызғылт сары танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Әрбір жұмыс қолданбасында танымбелгі бар. Ол оның қауіпсіздігі ұйым арқылы қамтамасыз етілетінін білдіреді. Жұмыс қолданбаларына оңай кіру үшін, оларды Негізгі экранға жылжытуға болады."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Ұйым арқылы басқарылады"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Хабарландырулар мен қолданбалар өшірулі"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабу"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабық"</string>
 </resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index d588bc1..ba8d775 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"រកមិនឃើញកម្មវិធី​ដែលត្រូវគ្នាជាមួយ \"<xliff:g id="QUERY">%1$s</xliff:g>\" ទេ"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ស្វែងរកកម្មវិធីច្រើនទៀត"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ការ​ជូនដំណឹង"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ចុច​ឱ្យ​ជាប់​ដើម្បី​ជ្រើស​រើស​ផ្លូវកាត់​មួយ។"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ចុច​ពីរ​ដង ហើយ​ចុច​ឱ្យ​ជាប់​ដើម្បី​ជ្រើសរើស​ផ្លូវកាត់​មួយ ឬ​ប្រើ​សកម្មភាព​ផ្ទាល់ខ្លួន។"</string>
     <string name="out_of_space" msgid="4691004494942118364">"គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​នេះ​ទៀត​ទេ។"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"គ្មាន​បន្ទប់​​ក្នុង​ថាស​និយម​ប្រើ"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"បញ្ជីកម្មវិធី"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"បញ្ជី​កម្មវិធី​ផ្ទាល់ខ្លួន"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"បញ្ជី​កម្មវិធី​ការងារ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ដើម"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"យកចេញ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុបការដំឡើង"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ផ្ទាំង​រូបភាព"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ការកំណត់​ទំព័រដើម"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"សង្ខេប"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"អនុញ្ញាតការបងិ្វលអេក្រង់ដើម"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"នៅពេលដែលបង្វិលទូរស័ព្ទរបស់អ្នក"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ការកំណត់អេក្រង់បច្ចុប្បន្នមិនអនុញ្ញាតការបង្វិលទេ"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"ស្លាកជូនដំណឹង"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"បើក"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"បិទ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"តម្រូវ​ឲ្យមាន​សិទ្ធិចូល​ប្រើប្រាស់​ការជូនដំណឹង"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"ដើម្បីបង្ហាញស្លាកជូនដំណឹង សូមបើកការជូនដំណឹងកម្មវិធីសម្រាប់ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ប្ដូរ​ការកំណត់"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"បង្ហាញ​ស្លាក​ជូនដំណឹង"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"បញ្ចូល​រូបតំណាង​ទៅ​អេក្រង់​ដើម"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"សម្រាប់កម្មវិធីថ្មី"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ប្តូររូបរាងរូបតំណាង"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"នៅ​លើ​អេក្រង់​ដើម"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ប្រើលំនាំដើមរបស់ប្រព័ន្ធ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ការ៉េ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ការ៉េជ្រុងកោង"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"កំពុងដោនឡូត <xliff:g id="NAME">%1$s</xliff:g> បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងរង់ចាំការដំឡើង"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ធាតុ​ក្រាហ្វិក <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"បញ្ជីធាតុ​ក្រាហ្វិក"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"បាន​បិទ​បញ្ជីធាតុ​ក្រាហ្វិក"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"បន្ថែមទៅអេក្រង់ដើម"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ផ្លាស់ធាតុមកទីនេះ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ធាតុដែលត្រូវបានបន្ថែមទៅអេក្រង់ដើម"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"បង្កើតថតឯកសារជាមួយ៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"បានបង្កើតថតឯកសារ"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ផ្លាស់ទៅអេក្រង់ដើម"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"រំកិលអេក្រង់ទៅខាងឆ្វេង"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"រំកិលអេក្រង់ទៅខាងស្តាំ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"អេក្រង់ដែលបានផ្លាស់ទី"</string>
     <string name="action_resize" msgid="1802976324781771067">"ប្ដូរទំហំ"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"បង្កើនទទឹង"</string>
     <string name="action_increase_height" msgid="459390020612501122">"បង្កើនកម្ពស់"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"បន្ថយកម្ពស់"</string>
     <string name="widget_resized" msgid="9130327887929620">"ធាតុក្រាហ្វិកដែលបានប្តូរទំហំទៅទទឹងប្រវែង <xliff:g id="NUMBER_0">%1$s</xliff:g> កម្ពស់ប្រវែង <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ផ្លូវកាត់"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ផ្លូវកាត់សម្រាប់ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"ផ្លូវកាត់ចំនួន <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> និង​ការជូនដំណឹងចំនួន <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> សម្រាប់ <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ផ្លូវកាត់ និង​ការជូនដំណឹង"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"បដិសេធ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"បាន​បដិសេធ​ការជូនដំណឹង"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ផ្ទាល់ខ្លួន"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ការងារ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"កម្រងព័ត៌មានការងារ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ស្វែង​រក​កម្មវិធី​ការងារ​នៅទីនេះ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"កម្មវិធី​ការងារ​នីមួយៗ​មាន​ស្លាក​​ពណ៌​ទឹកក្រូច និងត្រូវ​បានរក្សាទុក​យ៉ាងមានសុវត្ថិភាព​ដោយស្ថាប័ន​របស់អ្នក។ សូម​ផ្លាស់ទី​កម្មវិធី​ទៅកាន់​អេក្រង់​ដើម​របស់អ្នក​ ដើម្បី​ងាយស្រួល​ចូលប្រើជាងមុន។"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"កម្មវិធី​ការងារ​នីមួយៗ​មាន​ស្លាកមួយ និងត្រូវ​បានរក្សាទុក​យ៉ាងមានសុវត្ថិភាព​ដោយស្ថាប័ន​របស់អ្នក។ សូម​ផ្លាស់ទី​កម្មវិធី​ទៅកាន់​អេក្រង់​ដើម​របស់អ្នក​ ដើម្បី​ងាយស្រួល​ចូលប្រើជាងមុន។"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"គ្រប់គ្រងដោយ​ស្ថាប័ន​របស់អ្នក"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ការជូនដំណឹង​ និងកម្មវិធី​ត្រូវបានបិទ"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"បិទ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"បានបិទ"</string>
 </resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index a8f9784..5182fd2 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಹುಡುಕಿ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ವೈಯಕ್ತಿಕ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ಮುಖಪುಟ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ವಾಲ್‌ಪೇಪರ್‌ಗಳು"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ಮುಖಪುಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ಅವಲೋಕನ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ಮುಖಪುಟ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ಫೋನ್‌ ತಿರುಗಿಸಿದಾಗ"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ಪ್ರಸ್ತುತ ಪ್ರದರ್ಶನ ಸೆಟ್ಟಿಂಗ್ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"ಅಧಿಸೂಚನೆ ಡಾಟ್‌ಗಳು"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ಆನ್"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ಆಫ್"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"ಅಧಿಸೂಚನೆ ಪ್ರವೇಶ ಅಗತ್ಯವಿದೆ"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"ಅಧಿಸೂಚನೆ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"ಅಧಿಸೂಚನೆ ಡಾಟ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ಮುಖಪುಟದ ಪರದೆಗೆ ಐಕಾನ್ ಸೇರಿಸಿ"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ಐಕಾನ್ ಆಕಾರವನ್ನು ಬದಲಿಸಿ"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ಮುಖಪುಟ ಪರದೆಯಲ್ಲಿ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ಸಿಸ್ಟಂ ಡಿಫಾಲ್ಟ್ ಬಳಸಿ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ಚೌಕ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ಚೌಕವೃತ್ತ"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ವಿಜೆಟ್‌ಗಳು"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ವಿಜೆಟ್ ಪಟ್ಟಿ"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ವಿಜೆಟ್ ಪಟ್ಟಿಯನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಲ್ಡರ್ ರಚಿಸಿ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ಫೋಲ್ಡರ್ ರಚಿಸಲಾಗಿದೆ"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ಮುಖಪುಟಕ್ಕೆ ಸರಿಸಿ"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"ಪರದೆಯನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"ಪರದೆಯನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ಪರದೆ ಸರಿಸಲಾಗಿದೆ"</string>
     <string name="action_resize" msgid="1802976324781771067">"ಮರುಗಾತ್ರ"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"ಅಗಲವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ಎತ್ತರವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ವಿಜೆಟ್ ಅನ್ನು <xliff:g id="NUMBER_0">%1$s</xliff:g> ಅಗಲ <xliff:g id="NUMBER_1">%2$s</xliff:g> ಎತ್ತರಕ್ಕೆ ಮರುಗಾತ್ರಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ಗಾಗಿ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ಅಧಿಸೂಚನೆಯನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ವೈಯಕ್ತಿಕ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ಕೆಲಸ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಇಲ್ಲಿ ಹುಡುಕಿ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಕಿತ್ತಳೆ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸರಿಸಿ."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸರಿಸಿ."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಆಫ್ ಆಗಿವೆ"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ಮುಚ್ಚಿ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ಮುಚ್ಚಲಾಗಿದೆ"</string>
 </resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 0ebbbe7..5e68b17 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'과(와) 일치하는 앱이 없습니다."</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"더 많은 앱 검색"</string>
     <string name="notifications_header" msgid="1404149926117359025">"알림"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"바로가기를 선택하려면 길게 터치하세요."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 동작을 사용하세요."</string>
     <string name="out_of_space" msgid="4691004494942118364">"홈 화면에 더 이상 공간이 없습니다."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"즐겨찾기 트레이에 더 이상 공간이 없습니다."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"앱 목록"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"개인 앱 목록"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"업무용 앱 목록"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"홈"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"삭제"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"배경화면"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"홈 설정"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"관리자가 사용 중지함"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"개요"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"홈 화면 회전 허용"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"휴대전화 회전 시"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"현재 표시 설정에는 회전 기능이 허용되지 않습니다."</string>
     <string name="icon_badging_title" msgid="874121399231955394">"알림 표시 점"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"사용"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"사용 안함"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"알림 액세스 권한 필요"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"알림 표시점을 표시하려면 <xliff:g id="NAME">%1$s</xliff:g>의 앱 알림을 사용 설정하세요."</string>
     <string name="title_change_settings" msgid="1376365968844349552">"설정 변경"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"알림 표시 점 보기"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"홈 화면에 아이콘 추가"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"새로 설치한 앱에 적용"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"아이콘 모양 변경"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"홈 화면에 표시"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"시스템 기본값 사용"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"정사각형"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"모서리가 둥근 정사각형"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> 다운로드 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> 설치 대기 중"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> 위젯"</string>
+    <string name="widgets_list" msgid="796804551140113767">"위젯 목록"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"위젯 목록 닫힘"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"홈 화면에 추가"</string>
     <string name="action_move_here" msgid="2170188780612570250">"여기에 항목을 이동"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"홈 화면에 항목 추가됨"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"다음이 포함된 폴더 만들기: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"폴더를 만들었습니다."</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"홈 화면으로 이동"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"화면을 왼쪽으로 이동"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"화면을 오른쪽으로 이동"</string>
-    <string name="screen_moved" msgid="266230079505650577">"화면 이동됨"</string>
     <string name="action_resize" msgid="1802976324781771067">"크기 조정"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"폭 늘리기"</string>
     <string name="action_increase_height" msgid="459390020612501122">"높이 늘리기"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"높이 줄이기"</string>
     <string name="widget_resized" msgid="9130327887929620">"폭 <xliff:g id="NUMBER_0">%1$s</xliff:g>, 높이 <xliff:g id="NUMBER_1">%2$s</xliff:g>로 위젯 크기 조정됨"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"바로가기"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>에 사용 가능한 단축키 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>개"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"바로가기 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>개 및 <xliff:g id="APP_NAME">%3$s</xliff:g> 알림 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>개"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"바로가기 및 알림"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"닫기"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"알림이 해제되었습니다."</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"개인"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"직장"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"직장 프로필"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"여기에서 업무용 앱 찾기"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"각 업무용 앱에는 주황색 배지가 있으며 업무용 앱은 조직에서 안전하게 보호됩니다. 앱을 홈 화면으로 이동하여 더 간편하게 사용하세요."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"각 업무용 앱에는 배지가 있으며 업무용 앱은 조직에서 안전하게 보호됩니다. 앱을 홈 화면으로 이동하여 더 간편하게 사용하세요."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"조직에서 관리"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"알림 및 앱 사용 중지됨"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"닫기"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"종료됨"</string>
 </resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 05652fc..da7813e 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -39,10 +39,14 @@
     <string name="all_apps_loading_message" msgid="5813968043155271636">"Колдонмолор жүктөлүүдө…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" сурамына дал келген колдонмолор табылган жок"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Көбүрөөк колдонмолорду издөө"</string>
-    <string name="notifications_header" msgid="1404149926117359025">"Эскертмелер"</string>
+    <string name="notifications_header" msgid="1404149926117359025">"Билдирмелер"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Кыска жолду тандоо үчүн басып туруңуз."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Бул Үй экранында бош орун жок."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Тандамалдар тайпасында орун калган жок"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Колдонмолор тизмеси"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Жеке колдономолордун тизмеси"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Жумуш колдонмолорунун тизмеси"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Үйгө"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Алып салуу"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Чыгарып салуу"</string>
@@ -77,20 +81,20 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тушкагаздар"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Башкы беттин жөндөөлөрү"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администраторуңуз өчүрүп койгон"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Көз жүгүртүү"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Башкы экранды айлантууга уруксат берүү"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Телефон айланганда"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Экранды айлантуу параметри өчүрүлгөн"</string>
-    <string name="icon_badging_title" msgid="874121399231955394">"Эскертме белгилери"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"Билдирмелер белгилери"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Күйүк"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Өчүк"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Эскертмелерге уруксат берилиши керек"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Эскертме белгилерин көрсөтүү максатында, <xliff:g id="NAME">%1$s</xliff:g> үчүн колдонмонун эскертмелерин күйгүзүү керек"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Жөндөөлөрдү өзгөртүү"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Эскертме белгилерин көрсөтүү"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Башкы экранга сүрөтчө кошуу"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Жаңы колдонмолор үчүн"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Сүрөтчөнүн формасын өзгөртүү"</string>
-    <string name="icon_shape_system_default" msgid="1709762974822753030">"Тутум сушунтаган демейкисин колдонуу"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Башкы экранда"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Демейки тутум жөндөөлөрү колдонулат"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Чарчы"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Бурчтары жумуру төрт бурчтук"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Тегерек"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктөлүп алынууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяктады"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнотулушу күтүлүүдө"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> виджеттери"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Виджеттердин тизмеси"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Виджеттердин тизмеси жабык"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Башкы экранга кошуу"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Бул нерсени бул жерге жылдыруу"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Башкы экранга кошулду"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Төмөнкү менен куржун түзүү: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Куржун түзүлдү"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Башкы экранга жылдыруу"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Экранды солго жылдыруу"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Экранды оңго жылдыруу"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Экран жылдырылды"</string>
     <string name="action_resize" msgid="1802976324781771067">"Өлчөмүн өзгөртүү"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Кеңейтүү"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Бийиктетүү"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Жапыздатуу"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджеттин кеңдиги <xliff:g id="NUMBER_0">%1$s</xliff:g> бийиктиги <xliff:g id="NUMBER_1">%2$s</xliff:g> болду"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Кыска жолдор"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосуна <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кыска жол бар"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> колдонмосу үчүн <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кыска жол жана <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> эскертме бар"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Кыска жолдор жана билдирмелер"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Этибарга албоо"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Эскертме көз жаздымда калтырылды"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке колдонмолор"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Жумуш колдонмолору"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жумуш профили"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Жумуш колдонмолорун бул жерден таап алыңыз"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ар бир жумуш колдонмосунун кызгылт сары бейджиги бар жана ал уюмуңуз тарабынан коопсуз сакталат. Колдонмолорго тез өтүү үчүн аларды Башкы экранга кошуп алыңыз."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ар бир жумуш колдонмосунун бейджиги бар жана ал уюмуңуз тарабынан коопсуз сакталат. Колдонмолорго тез өтүү үчүн аларды Башкы экранга кошуп алыңыз."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Уюмуңуз тарабынан башкарылат"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Билдирүүлөр жана колдонмолор өчүрүлгөн"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Жабуу"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Жабык"</string>
 </resources>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 40ffffe..f002195 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -25,16 +25,11 @@
     <dimen name="fastscroll_popup_text_size">24dp</dimen>
 
     <!-- Dynamic grid -->
-    <dimen name="dynamic_grid_overview_bar_item_width">120dp</dimen>
-    <dimen name="dynamic_grid_min_page_indicator_size">48dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
 
     <dimen name="dynamic_grid_cell_layout_padding">0dp</dimen>
     <dimen name="dynamic_grid_cell_layout_bottom_padding">5.5dp</dimen>
 
-    <!-- Folders -->
-    <dimen name="folder_preview_padding">2dp</dimen>
-
     <!-- Hotseat -->
     <!-- Will be set to equal the hotseat icon size. -->
     <dimen name="dynamic_grid_hotseat_size">0dp</dimen>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index e446e7c..d0d127f 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"ບໍ່ພົບແອັບທີ່ກົງກັບ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ຊອກຫາແອັບເພີ່ມເຕີມ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ການແຈ້ງເຕືອນ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ລາຍຊື່ແອັບ"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ລາຍຊື່ແອັບສ່ວນຕົວ"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"ລາຍຊື່ແອັບເຮັດວຽກ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ໜ້າຫຼັກ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ເອົາ​ອອກ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ຖອນ​ການ​ຕິດ​ຕັ້ງ"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ພາບພື້ນຫຼັງ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ການຕັ້ງຄ່າ Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ຖືກປິດການນຳໃຊ້ໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ພາບຮວມ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ອະນຸຍາດໃຫ້ໝຸນໜ້າຈໍທຳອິດໄດ້"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ເມື່ອໝຸນໂທລະສັບ"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ການຕັ້ງຄ່າສະແດງຜົນປັດຈຸບັນບໍ່ອະນຸຍາດໃຫ້ໝຸນໄດ້"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"ຈຸດການແຈ້ງເຕືອນ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ເປີດ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ປິດ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"ຕ້ອງໃຊ້ການເຂົ້າເຖິງການແຈ້ງເຕືອນ"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"ເພື່ອສະແດງຈຸດການແຈ້ງເຕືອນ, ໃຫ້ເປີດການແຈ້ງເຕືອນສຳລັບ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ບັນທຶກການຕັ້ງຄ່າ"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"ສະແດງຈຸດການແຈ້ງເຕືອນ"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ເພີ່ມໄອຄອນໃສ່ໜ້າຈໍຫຼັກ"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ສຳລັບແອັບໃໝ່"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ປ່ຽນຮູບຮ່າງໄອຄອນ"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ຢູ່ໜ້າຈໍຫຼັກ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ໃຊ້ຄ່າເລີ່ມຕົ້ນລະບົບ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ສີ່ຫຼ່ຽມຈັດຕຸລັດ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ສີ່ຫຼ່ຽມຂອບມົນ"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ດາວ​ໂຫຼດ, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳ​ເລັດ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ລໍ​ຖ້າ​ຕິດ​ຕັ້ງ"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"ວິດເຈັດ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ລາຍຊື່ວິດເຈັດ"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ປິດລາຍຊື່ວິດເຈັດແລ້ວ"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ເພີ່ມໃສ່ໜ້າຈໍຫຼັກ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ເພີ່ມ​ລາຍ​ການ​ໃສ່​ໜ້າ​ຈໍ​ຫຼັກ​ແລ້ວ"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ສ້າງ​ໂຟ​ລ​ເດີ​ກັບ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ສ້າງ​ໂຟ​ລ​ເດີ​ແລ້ວ"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ຍ້າຍ​ໄປ​ໃສ່​ໜ້າ​ຈໍ​ຫຼັກ"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"ຍ້າຍ​ໜ້າ​ຈໍ​ໄປ​ທາງ​ຊ້າຍ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"ຍ້າຍ​ໜ້າ​ຈໍ​ໄປ​ທາງ​ຂວາ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ຍ້າຍ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
     <string name="action_resize" msgid="1802976324781771067">"ປັບຂະໜາດ"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"ເພີ່ມ​ລວງ​ກ້​ວາງ​ຂຶ້ນ"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ເພີ່ມ​ລວງ​ສູງ​ຂຶ້ນ"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ຫຼຸດ​ລວງ​ສູງ​ລົງ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ປ່ຽນ​ຂະ​ໜາດ​ວິດ​ເຈັດ​ເປັນ​ລວງ​ກ້​ວາງ <xliff:g id="NUMBER_0">%1$s</xliff:g> ລວງ​ສູງ <xliff:g id="NUMBER_1">%2$s</xliff:g> ແລ້ວ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ທາງລັດ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ທາງລັດສຳລັບ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ທາງລັດ ແລະ <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ການແຈ້ງເຕືອນສຳລັບ <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ປຸ່ມລັດ ແລະ ການແຈ້ງເຕືອນ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ປິດໄວ້"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ປິດການແຈ້ງເຕືອນແລ້ວ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ສ່ວນຕົວ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ວຽກ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ຊອກຫາແອັບວຽກຢູ່ບ່ອນນີ້"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ແຕ່ລະແອັບວຽກຈະມີປ້າຍສີສົ້ມ ແລະ ຖືກຈັດເກັບໄວ້ຢ່າງປອດໄພໂດຍອົງກອນຂອງທ່ານ. ທ່ານສາມາດຍ້າຍແອັບໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອໃຫ້ເຂົ້າໃຊ້ງ່າຍຂຶ້ນໄດ້."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ແຕ່ລະແອັບວຽກຈະມີປ້າຍ ແລະ ຖືກຈັດເກັບໄວ້ຢ່າງປອດໄພໂດຍອົງກອນຂອງທ່ານ. ທ່ານສາມາດຍ້າຍແອັບໄປໃສ່ໜ້າຈໍຫຼັກເພື່ອໃຫ້ເຂົ້າໃຊ້ງ່າຍຂຶ້ນໄດ້."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"ຈັດການໂດຍອົງກອນຂອງທ່ານ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ການແຈ້ງເຕືອນ ແລະ ແອັບຖືກປິດໄວ້"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ປິດ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ປິດແລ້ວ"</string>
 </resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 2e37e98..c323fd8 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Ieškoti daugiau programų"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Pranešimai"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Paliesk. ir palaikyk., kad pasirinkt. spart. klav."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šiame pagrindiniame ekrane vietos nebėra."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Mėgstamiausių dėkle nebėra vietos"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Programų sąrašas"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Asmeninių programų sąrašas"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Darbo programų sąrašas"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Pagrindinis"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ištrinti"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Pašalinti"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ekrano fonai"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"„Home“ nustatymai"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Išjungė administratorius"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Apžvalga"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Leisti pasukti pagrindinį ekraną"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kai telefonas pasukamas"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Naudojant dabartinį pateikties nustatymą neleidžiama pasukti"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pranešimų taškai"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Įjungta"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Išjungta"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Reikalinga prieiga prie pranešimų"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Kad būtų rodomi pranešimų taškai, įjunkite programos „<xliff:g id="NAME">%1$s</xliff:g>“ pranešimus."</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Keisti nustatymus"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Rodyti pranešimų taškus"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridėti piktogr. prie pagrindinio ekrano"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Skirta naujoms programoms"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Pakeisti piktogramos formą"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"pagrindiniame ekrane"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Naudoti numatytuosius sistemos nustatymus"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadratas"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadratais suapvalintais kampais"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Atsisiunčiama programa „<xliff:g id="NAME">%1$s</xliff:g>“, <xliff:g id="PROGRESS">%2$s</xliff:g> baigta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Laukiama, kol bus įdiegta programa „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"„<xliff:g id="NAME">%1$s</xliff:g>“ valdikliai"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Valdiklių sąrašas"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Valdiklių sąrašas uždarytas"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Pridėti prie pagrind. ekrano"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Perkelti elementą čia"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementas pridėtas prie pagrindinio ekrano"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Kurti aplanką naudojant: „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="folder_created" msgid="6409794597405184510">"Aplankas sukurtas"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Perkelti į pagrindinį ekraną"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Perkelti ekraną į kairę"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Perkelti ekraną į dešinę"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekranas perkeltas"</string>
     <string name="action_resize" msgid="1802976324781771067">"Pakeisti dydį"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Padidinti plotį"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Padidinti aukštį"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Sumažinti aukštį"</string>
     <string name="widget_resized" msgid="9130327887929620">"Valdiklio dydis pakeistas: plotis – <xliff:g id="NUMBER_0">%1$s</xliff:g>, aukštis – <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Spartieji klavišai"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Programos „<xliff:g id="APP_NAME">%2$s</xliff:g>“ spartieji klavišai (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>)"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"„<xliff:g id="APP_NAME">%3$s</xliff:g>“ spartieji klavišai (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) ir pranešimai (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>)"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Spartieji klavišai ir pranešimai"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Atsisakyti"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Pranešimo atsisakyta"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Asmeninės"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Darbo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Darbo profilis"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Darbo programas rasite čia"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kiekvienai darbo programai priskirtas oranžinis ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite darbo programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Kiekvienai darbo programai priskirtas ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Tvarko jūsų organizacija"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Programos ir pranešimai išjungti"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Uždaryti"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Uždaryta"</string>
 </resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 3b96ffa..be03811 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Meklēt citas lietotnes"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Paziņojumi"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Lai atlasītu saīsni, pieskarieties un turiet to."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to. Varat arī veikt pielāgotas darbības."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šajā sākuma ekrānā vairs nav vietas."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Izlases joslā vairs nav vietas."</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lietotņu saraksts"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personīgo lietotņu saraksts"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Darba lietotņu saraksts"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Sākums"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Noņemt"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
@@ -78,19 +82,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fona tapetes"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Sākumlapas iestatījumi"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Atspējojis administrators"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Kopsavilkums"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Atļaut sākuma ekrāna pagriešanu"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Pagriežot tālruni"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Pašreizējā displeja iestatījumā nav atļauta pagriešana."</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Paziņojumu punkti"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ieslēgts"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Izslēgts"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Nepieciešama piekļuve paziņojumiem"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Mainīt iestatījumus"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Rādīt paziņojumu punktus"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pievienot ikonu sākuma ekrānā"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Jaunām lietotnēm"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Mainīt ikonu formu"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"sākuma ekrānā"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Izmantot sistēmas noklusējumu"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrāts"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvadrāts ar noapaļotiem stūriem"</string>
@@ -105,6 +109,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> lejupielāde (<xliff:g id="PROGRESS">%2$s</xliff:g> pabeigti)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Notiek <xliff:g id="NAME">%1$s</xliff:g> instalēšana"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> logrīki"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Logrīku saraksts"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Logrīku saraksts aizvērts"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Pievienot sākuma ekrānam"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Pārvietot vienumu šeit"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Vienums pievienots sākuma ekrānam"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Izveidot mapi ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mape izveidota"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Pārvietot uz sākuma ekrānu"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Pārvietot ekrānu pa kreisi"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Pārvietot ekrānu pa labi"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekrāns pārvietots"</string>
     <string name="action_resize" msgid="1802976324781771067">"Mainīt lielumu"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Palielināt platumu"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Palielināt augstumu"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Samazināt augstumu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Logrīka lielums mainīts — platums: <xliff:g id="NUMBER_0">%1$s</xliff:g>, augstums: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Saīsnes"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> saīsnes lietotnei <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> saīsnes un <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> paziņojumi lietotnei <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Saīsnes un paziņojumi"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Nerādīt"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Paziņojums netiek rādīts"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personīgās lietotnes"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Darba lietotnes"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Darba profils"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Meklējiet darba lietotnes šeit"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Katrai darba lietotnei ir oranža emblēma, un jūsu organizācija aizsargā šīs lietotnes. Ērtākai piekļuvei pārvietojiet darba lietotnes uz sākuma ekrānu."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Katrai darba lietotnei ir emblēma, un jūsu organizācija aizsargā šīs lietotnes. Lai varētu ērtāk piekļūt lietotnēm, pārvietojiet tās uz sākuma ekrānu."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Pārvalda jūsu organizācija"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Paziņojumi un lietotnes ir izslēgtas"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Aizvērt"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Aizvērta"</string>
 </resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 3a0fc2b..e5dd027 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Не се најдени апликации што одговараат на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Пребарај други апликации"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Известувања"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Допрете двапати и задржете за избор на кратенка."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Допрете двапати и задржете за избор на кратенка или користете приспособени дејства."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Нема повеќе простор на овој екран на почетната страница."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема повеќе простор на лентата „Омилени“"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Список со апликации"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Список со лични апликации"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Список со апликации за работа"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна страница"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Отстрани"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Поставки за Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Оневозможено од администраторот"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Краток преглед"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Дозволете ротација на Почетниот екран"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Кога телефонот се ротира"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Тековната поставка на Екранот не дозволува ротација"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Точки за известување"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Вклучено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Исклучено"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребен е пристап до известувањата"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Промени ги поставките"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Прикажи точки за известување"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додај икона на почетниот екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нови апликации"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Променете ја формата на иконата"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на „Почетен екран“"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Користи ја стандардната поставка на системот"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Заоблен квадрат"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Се презема <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека да се инсталира"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Виџети за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Список со виџети"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Списокот со виџети е затворен"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Додај на Почетен екран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Премести ја ставката овде"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставката е додадена на почетниот екран"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Создај папка со: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Папката е создадена"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Премести на Почетен екран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Движи го екранот налево"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Движи го екранот надесно"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Екранот е преместен"</string>
     <string name="action_resize" msgid="1802976324781771067">"Промени големина"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Зголеми ширина"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Зголеми висина"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намали висина"</string>
     <string name="widget_resized" msgid="9130327887929620">"Големината на виџетот е променета на ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> висина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Кратенки"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кратенки за <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> кратенки и <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> известувања за <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Кратенки и известувања"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Отфрли"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Известувањето е отфрлено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лично"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"За работа"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Работен профил"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Најдете апликации за работа тука"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Секоја апликација за работа има портокалова значка и е обезбедена од вашата организација. За полесен пристап, апликациите за работа преместете ги на почетниот екран."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Секоја апликација за работа има значка, а организацијата се грижи за нејзината безбедност. За полесен пристап, преместете ги апликациите на почетниот екран."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Управувано од вашата организација"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Известувањата и апликациите се исклучени"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затвори"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
 </resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 84f769b..ed3bde6 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക"</string>
     <string name="notifications_header" msgid="1404149926117359025">"അറിയിപ്പുകൾ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"തിരഞ്ഞെടുക്കുന്നതിന് കുറുക്കുവഴി സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്‌ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ 2 തവണ ടാപ്പ് ചെയ്‌ത് പിടിക്കുക."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ഈ ഹോം സ്‌ക്രീനിൽ ഒഴിവൊന്നുമില്ല."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"അപ്ലിക്കേഷനുകളുടെ ലിസ്‌റ്റ്"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"വ്യക്തിഗത ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"ഔദ്യോഗിക ആപ്പുകളുടെ ലിസ്റ്റ്"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ഹോം"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"നീക്കംചെയ്യുക"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"വാൾപേപ്പർ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ഹോം ക്രമീകരണം"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"അവലോകനം"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ഹോം സ്ക്രീൻ തിരിക്കൽ അനുവദിക്കുക"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ഫോൺ തിരിച്ച നിലയിലായിരിക്കുമ്പോൾ"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"നിലവിലെ ഡിസ്പ്ലേ ക്രമീകരണം തിരിക്കൽ അനുവദിക്കുന്നില്ല"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"അറിയിപ്പ് ഡോട്ടുകൾ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ഓൺ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ഓഫ്"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"അറിയിപ്പിനായുള്ള ആക്‌സസ് ആവശ്യമാണ്"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുന്നതിന്, <xliff:g id="NAME">%1$s</xliff:g> എന്നയാളിനായുള്ള ആപ്പ് അറിയിപ്പുകൾ ഓണാക്കുക"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ക്രമീകരണം മാറ്റുക"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുക"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ഹോം സ്ക്രീനിലേക്ക് ഐക്കൺ ചേർക്കുക"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"പുതിയ ആപ്പുകൾക്ക്"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ഐക്കണിന്റെ ആകാരം മാറ്റുക"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ഹോം സ്‌ക്രീനിൽ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"സിസ്‌റ്റം ഡിഫോൾട്ട് ഉപയോഗിക്കുക"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ചതുരം"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ചതുരവൃത്തം"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> വിജറ്റുകൾ"</string>
+    <string name="widgets_list" msgid="796804551140113767">"വിജറ്റുകളുടെ ലിസ്‌റ്റ്"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"വിജറ്റുകളുടെ ലിസ്‌റ്റ് അവസാനിപ്പിച്ചു"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ഇനം ഇവിടേക്ക് നീക്കുക"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ഹോം സ്‌ക്രീനിൽ ഇനം ചേർത്തു"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ഇതുപയോഗിച്ച് ഫോൾഡർ സൃഷ്‌ടിക്കുക: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ഫോൾഡർ സൃഷ്‌ടിച്ചു"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"സ്‌ക്രീൻ ഇടത്തേക്ക് നീക്കുക"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"സ്‌ക്രീൻ വലത്തേക്ക് നീക്കുക"</string>
-    <string name="screen_moved" msgid="266230079505650577">"സ്‌ക്രീൻ നീക്കി"</string>
     <string name="action_resize" msgid="1802976324781771067">"വലുപ്പംമാറ്റുക"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"വീതി കൂട്ടുക"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ഉയരം കൂട്ടുക"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ഉയരം കുറയ്‌ക്കുക"</string>
     <string name="widget_resized" msgid="9130327887929620">"വീതി <xliff:g id="NUMBER_0">%1$s</xliff:g> ഉയരം <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് വിഡ്‌ജെറ്റിന്റെ വലുപ്പം മാറ്റി"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"കുറുക്കുവഴികൾ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ആപ്പിനുള്ള <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> കുറുക്കുവഴികൾ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ആപ്പിനായുള്ള <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> കുറുക്കുവഴികളും <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> അറിയിപ്പുകളും"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"കുറുക്കുവഴികളും അറിയിപ്പുകളും"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"നിരസിക്കുക"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"അറിയിപ്പ് നിരസിച്ചു"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"വ്യക്തിപരം"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ജോലി"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ഔദ്യോഗിക ആപ്പുകൾ ഇവിടെ കണ്ടെത്തുക"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഓറഞ്ച് നിറത്തിലുള്ള ഒരു ബാഡ്‌ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഒരു ബാഡ്‌ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"അടയ്ക്കുക"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"അടച്ചു"</string>
 </resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 5e91a46..9fbb1e5 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"-д тохирох апп олдсонгүй"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Бусад апп-г хайх"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Мэдэгдэл"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Товчлол авах бол удаан дарна уу."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Товчлол авах эсвэл тохируулсан үйлдлийг ашиглахын тулд давхар товшоод хүлээнэ үү."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Энэ Нүүр дэлгэц зайгүй."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"\"Дуртай\" трей дээр өөр зай байхгүй байна"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Апп-н жагсаалт"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Хувийн аппын жагсаалт"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ажлын аппын жагсаалт"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Нүүр"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Арилгах"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Устгах"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ханын зураг"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Нүүр хуудасны тохиргоо"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Таны админ идэвхгүй болгосон"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Тойм"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Нүүр дэлгэцийг эргүүлэхийг зөвшөөрөх"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Утсыг эргүүлсэн үед"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Дэлгэцийн одоогийн тохиргоогоор эргүүлэх боломжгүй"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Мэдэгдлийн цэг"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Асаалттай"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Унтраалттай"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Мэдэгдлийн хандалт шаардлагатай"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Мэдэгдлийн цэгийг харуулахын тулд <xliff:g id="NAME">%1$s</xliff:g>-д аппын мэдэгдлийг асаана уу"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Тохиргоог өөрчлөх"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Мэдэгдлийн цэгийг харуулах"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Нүүр хуудаст дүрс тэмдэг нэмэх"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Шинэ аппад зориулсан"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Дүрс тэмдгийн хэлбэрийг өөрчлөх"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Үндсэн нүүр хэсэгт"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Системийн өгөгдмөл тохиргоог ашиглах"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Дөрвөлжин"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Мохоо өнцөгтэй дөрвөлжин"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>-г татаж байна, <xliff:g id="PROGRESS">%2$s</xliff:g> татсан"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> нь суулгахыг хүлээж байна"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> жижиг хэрэгсэл"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Жижиг хэрэгслийн жагсаалт"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Жижиг хэрэгслийн жагсаалтыг хаасан"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Нүүр дэлгэц нэмэх"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Энд байршуулах"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Нүүр дэлгэцэнд нэмсэн зүйл"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Хавтсыг: <xliff:g id="NAME">%1$s</xliff:g> нэрээр үүсгэ"</string>
     <string name="folder_created" msgid="6409794597405184510">"Үүсгэсэн хавтас"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Нүүр дэлгэц рүү зөөх"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Дэлгэцийг зүүн тийш зөөх"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Дэлгэцийг баруун тийш зөөх"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Дэлгэцийг зөөсөн"</string>
     <string name="action_resize" msgid="1802976324781771067">"Хэмжээг өөрчлөх"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Өргөсгөх"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Өндөрсгөх"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намсгах"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджэтийн өргөн <xliff:g id="NUMBER_0">%1$s</xliff:g>, өндөр <xliff:g id="NUMBER_1">%2$s</xliff:g> болсон"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Товчлол"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>-н <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> товчлол"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> товчлол болон <xliff:g id="APP_NAME">%3$s</xliff:g>-н <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> мэдэгдэл"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Товчлол болон мэдэгдэл"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Хаах"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Мэдэгдлийг хаасан"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Хувийн"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Ажил"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ажлын профайл"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ажлын аппыг эндээс олно уу"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ажлын апп тус бүр улбар шар тэмдэгтэй ба эдгээрийг танай байгууллагаас аюулгүй байлгадаг. Аппуудад хялбараар хандахын тулд тэдгээрийг Үндсэн Нүүрэнд зөөнө үү."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ажлын апп тус бүр тэмдэгтэй ба эдгээрийг танай байгууллагаас аюулгүй байлгадаг. Аппуудад хялбар хандахын тулд тэдгээрийг Үндсэн нүүр хэсэгт зөөнө үү."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Танай байгууллагаас удирддаг"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Мэдэгдэл, апп унтраалттай байна"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Хаах"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Хаасан"</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 94b75d7..a297e06 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -28,9 +28,9 @@
     <string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोडमध्ये अक्षम झाले"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नाही"</string>
     <string name="home_screen" msgid="806512411299847073">"होम स्क्रीन"</string>
-    <string name="custom_actions" msgid="3747508247759093328">"सानुकूल क्रिया"</string>
+    <string name="custom_actions" msgid="3747508247759093328">"कस्टम क्रिया"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
-    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"एक विजेट निवडण्यासाठी दोनदा टॅप करा आणि धरून ठेवा किंवा सानुकूल क्रिया वापरा."</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"एक विजेट निवडण्यासाठी दोनदा टॅप करा आणि धरून ठेवा किंवा कस्टम क्रिया वापरा."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
     <string name="add_item_request_drag_hint" msgid="5899764264480397019">"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"अधिक अॅप्स शोधा"</string>
     <string name="notifications_header" msgid="1404149926117359025">"सूचना"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
     <string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"अॅप्स सूची"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"वैयक्तिक अॅप्स सूची"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"कामाच्या ठिकाणी वापरली जाणाऱ्या अॅप्सची सूची"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"होम"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"काढा"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करा"</string>
@@ -69,7 +73,7 @@
     <string name="workspace_new_page" msgid="257366611030256142">"नवीन मुख्य स्क्रीन पृष्ठ"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"फोल्डर बंद करण्यासाठी टॅप करा"</string>
-    <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे जतन करण्यासाठी टॅप करा"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"पुनर्नामित करणे सेव्ह करण्यासाठी टॅप करा"</string>
     <string name="folder_closed" msgid="4100806530910930934">"फोल्डर बंद"</string>
     <string name="folder_renamed" msgid="1794088362165669656">"फोल्डरचे नाव बदलून <xliff:g id="NAME">%1$s</xliff:g> असे ठेवले"</string>
     <string name="folder_name_format" msgid="6629239338071103179">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"होम सेटिंग्‍ज"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"अवलोकन"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"मुख्यस्क्रीन फिरविण्‍यास अनुमती द्या"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरविला जातो तेव्हा"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"वर्तमान डिस्प्ले सेटिंग रोटेशनला परवानगी देत नाही"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"सूचना बिंदू"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"चालू"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"बंद"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनांच्या अ‍ॅक्सेसची आवश्यकता आहे"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदू दाखवण्यासाठी, <xliff:g id="NAME">%1$s</xliff:g> साठी अ‍ॅप सूचना चालू करा"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"सेटिंग्ज बदला"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"सूचना बिंदू दाखवा"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"होम स्क्रीनवर आयकन जोडा"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नवीन अॅप्ससाठी"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"चिन्हाचा आकार बदला"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"होम स्क्रीनवर"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"सिस्‍टमचे डीफॉल्‍ट वापरा"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"चौरस"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"गोलाकार चौरस"</string>
@@ -100,10 +104,12 @@
     <string name="abandoned_clean_this" msgid="7610119707847920412">"काढा"</string>
     <string name="abandoned_search" msgid="891119232568284442">"शोधा"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"हा अॅप इंस्टॉल केलेला नाही"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. आपण ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप इंस्टॉल केलेला नाही. तुम्ही ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे इंस्टॉल करू शकता."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेट"</string>
+    <string name="widgets_list" msgid="796804551140113767">"विजेट सूची"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"विजेट सूची बंद केली"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्क्रीनवर जोडा"</string>
     <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"यासह फोल्‍डर तयार करा: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"फोल्‍डर तयार केले"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"मुख्य स्क्रीनवर हलवा"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रीन डावीकडे हलवा"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रीन उजवीकडे हलवा"</string>
-    <string name="screen_moved" msgid="266230079505650577">"स्क्रीन हलविली"</string>
     <string name="action_resize" msgid="1802976324781771067">"आकार बदला"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"रूंदी वाढवा"</string>
     <string name="action_increase_height" msgid="459390020612501122">"उंची वाढवा"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"उंची कमी करा"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेटचा आकार रुंदी <xliff:g id="NUMBER_0">%1$s</xliff:g> उंची <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये बदलला"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"शॉर्टकट"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> साठी <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>साठी <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> शॉर्टकट आणि <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचना"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"शॉर्टकट आणि सूचना"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"डिसमिस करा"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना डिसमिस केली"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"वैयक्तिक"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यालय"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कामाची अ‍ॅप्स येथे मिळवा"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"प्रत्येक कार्य अ‍ॅपमध्ये नारिंगी बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अ‍ॅक्सेससाठी अ‍ॅप्स तुमच्या होम स्क्रीनवर हलवा."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"प्रत्येक कार्य अ‍ॅपला एक बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अ‍ॅक्सेससाठी अ‍ॅप्स तुमच्या होम स्क्रीनवर हलवा."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"तुमच्या संस्थेकडून व्यवस्थापित"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करा"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद केले"</string>
 </resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 6e19421..71047fb 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Tiada apl yang ditemui sepadan dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Cari lagi apl"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Pemberitahuan"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Sentuh &amp; tahan untuk mengambil pintasan."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ketik dua kali &amp; tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tiada lagi ruang pada skrin Laman Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tiada ruang dalam dulang Kegemaran lagi"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Senarai apl"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Senarai apl peribadi"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Senarai apl kerja"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Laman Utama"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Tetapan laman utama"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dilumpuhkan oleh pentadbir anda"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Ikhtisar"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Benarkan putaran Skrin Utama"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Apabila telefon diputar"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Tetapan Paparan semasa tidak membenarkan putaran"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Titik pemberitahuan"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Hidup"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Mati"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Akses pemberitahuan diperlukan"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Untuk menunjukkan Titik Pemberitahuan, hidupkan pemberitahuan apl untuk <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Tukar tetapan"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Tunjukkan titik pemberitahuan"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Tambahkan ikon pada Skrin Utama"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Untuk apl baharu"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Tukar bentuk ikon"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"pada Skrin Utama"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gunakan lalai sistem"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Segi empat sama"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Segi empat berbucu bulat"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> memuat turun, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu untuk dipasang"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widget <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Senarai widget"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Senarai widget ditutup"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Tambahkan pada Skrin Utama"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Alihkan item ke sini"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan pada skrin utama"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Alihkan ke Skrin Utama"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Alihkan skrin ke kiri"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Alihkan skrin ke kanan"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skrin dialihkan"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ubah saiz"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Tambahkan kelebaran"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Tambahkan ketinggian"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Kurangkan ketinggian"</string>
     <string name="widget_resized" msgid="9130327887929620">"Saiz widget diubah menjadi <xliff:g id="NUMBER_0">%1$s</xliff:g> lebar <xliff:g id="NUMBER_1">%2$s</xliff:g> tinggi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan untuk <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> pintasan dan <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> pemberitahuan untuk <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pintasan dan pemberitahuan"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ketepikan"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Pemberitahuan diketepikan"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Peribadi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Temui apl kerja di sini"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Setiap apl kerja terdapat lencana berwarna oren dan dilindungi oleh organisasi anda. Alihkan apl ke Skrin Utama untuk akses yang lebh mudah."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Setiap apl kerja terdapat lencana dan dilindungi oleh organisasi anda. Alihkan apl ke Skrin Utama untuk akses yang lebih mudah."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Diurus oleh organisasi anda"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Pemberitahuan dan apl dimatikan"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Tutup"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Ditutup"</string>
 </resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 3cf9208..6c26185 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"နောက်ထပ် အက်ပ်များကို ရှာပါ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"အကြောင်းကြားချက်များ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ဖြတ်လမ်းလင့်ခ်တစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ။"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ဖြတ်လမ်းလင့်ခ်ကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"အက်ပ်စာရင်း"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"တစ်ကိုယ်ရေသုံး အက်ပ်စာရင်း"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"အလုပ်သုံး အက်ပ်စာရင်း"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ထုတ်မည်"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ပင်မဆက်တင်များ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"သင့်စီမံခန့်ခွဲသူက ပိတ်လိုက်ပါသည်"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ခြုံငုံသုံးသပ်ချက်"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ပင်မစာမျက်နှာလှည့်ခြင်းကို ခွင့်ပြုပါ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ဖုန်းကိုလှည့်ထားစဉ်"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"လက်ရှိ မြင်ကွင်းဆက်တင်တွင် မြင်ကွင်းကို လှည့်ခွင့်မပေးပါ"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"အကြောင်းကြားချက်အမှတ်အသားများ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ဖွင့်ထားသည်"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ပိတ်ထားသည်"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"အကြောင်းကြားချက် အသုံးပြုခွင့် လိုအပ်သည်"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"အကြောင်းကြားချက် အစက်များကို ပြသရန် <xliff:g id="NAME">%1$s</xliff:g> အတွက် အက်ပ်အကြောင်းကြားချက်များကို ဖွင့်ပါ"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ဆက်တင်များ ပြောင်းရန်"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"အကြောင်းကြားချက် အမှတ်အသားများကို ပြရန်"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ပင်မစာမျက်နှာသို့ သင်္ကေတပုံ ထည့်ရန်"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"အက်ပ်အသစ်များအတွက်"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"သင်္ကေတပုံစံကို ပြောင်းရန်"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"\'ပင်မမျက်နှာပြင်\' ပေါ်တွင်"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"စနစ်၏ မူရင်းပုံကို အသုံးပြုရန်"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"လေးထောင့်"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"စတုရန်းမကျ စက်ဝိုင်းမကျပုံ"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ဒေါင်းလုဒ်လုပ်နေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ကိုထည့်သွင်းရန်စောင့်နေသည်"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ဝိဂျက်များ"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ဝိဂျက်စာရင်း"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ဝိဂျက်စာရင်းကို ပိတ်ထားသည်"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ပင်မမျက်နှာစာသို့ ထည့်ပါ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ဖိုလ်ဒါ ပြုလုပ်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ဖိုလ်ဒါ ပြုလုပ်ပြီး"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"မျက်နှာပြင် ဘယ်ဘက်သို့ ရွှေ့ပါ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"မျက်နှာပြင် ညာဘက်သို့ ရွှေ့ပါ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ဖန်မျက်နှာပြင် ပြောင်းရွှေ့ပြီး၏"</string>
     <string name="action_resize" msgid="1802976324781771067">"အရွယ်အစားပြောင်းပါ"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"အကျယ်အား တိုးပါ"</string>
     <string name="action_increase_height" msgid="459390020612501122">"အမြင့်အား တိုးပါ"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"အမြင့်အား လျှော့ပါ"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget အား အကျယ် <xliff:g id="NUMBER_0">%1$s</xliff:g> အမြင့် <xliff:g id="NUMBER_1">%2$s</xliff:g> အရွယ်အစားပြန်လည်ချိန်ညှိပြီး၏"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ဖြတ်လမ်းများ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> အတွက် အမြန်နည်း <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ခု"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> အတွက် ဖြတ်လမ်းလင့်ခ် <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> နှင့် အကြောင်းကြားချက် <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ခု"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ဖြတ်လမ်းလင့်ခ်နှင့် အကြောင်းကြားချက်များ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ပယ်ရန်"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"အသိပေးချက်ကို ဖယ်ထုတ်ပြီးပါပြီ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ကိုယ်ပိုင်"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"အလုပ်"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"အလုပ်ပရိုဖိုင်"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"အလုပ်အက်ပ်များကို ဤနေရာတွင်ရှာဖွေပါ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"အလုပ်အက်ပ်တိုင်းတွင် လိမ္မော်ရောင်တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"အလုပ်အက်ပ်တိုင်းတွင် တံဆိပ် တစ်ခုစီရှိပြီး သင်၏ အဖွဲ့အစည်းက လုံခြုံအောင် ထားရှိပါသည်။ အသုံးပြုရ ပိုမိုလွယ်ကူစေရန် အက်ပ်များကို သင်၏ ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ။"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"သင်၏ အဖွဲ့အစည်းက စီမံခန့်ခွဲထားပါသည်"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"အကြောင်းကြားချက်များနှင့် အက်ပ်များကို ပိတ်ထားသည်"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ပိတ်ရန်"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ပိတ်ထားသည်"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2bdd6ce..67a912b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Søk etter flere apper"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Varsler"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Trykk og hold for å velge en snarvei."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Denne startsiden er full."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritter-skuffen er full"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"App-liste"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Personlige apper-liste"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Jobbapper-liste"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startside"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstaller"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunner"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Startsideinnstillinger"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratoren har slått av funksjonen"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Oversikt"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Tillat rotasjon av startskjermen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Når telefonen roteres"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Med den nåværende skjerminnstillingen støttes ikke rotasjon"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Varselsprikker"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Tilgang til varsler er nødvendig"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Slå på appvarsler for <xliff:g id="NAME">%1$s</xliff:g> for å vise varselsprikker"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Endre innstillingene"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Vis varselsprikker"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Legg til ikon på startsiden"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"For nye apper"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Endre formen på ikonet"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"på startskjermen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Bruk systemstandard"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Superellipse"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Laster ned <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Venter på å installere <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-moduler"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Modulliste"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Modullisten er lukket"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Legg til på startskjermen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Flytt elementet hit"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er lagt til på startskjermen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Opprett mappe med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mappen er opprettet"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Flytt til startskjermen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Flytt skjermen til venstre"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Flytt skjermen til høyre"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skjermen er flyttet"</string>
     <string name="action_resize" msgid="1802976324781771067">"Endre størrelse"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Øk bredden"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Øk høyden"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reduser høyden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Størrelsen på modulen er endret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og høyde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Snarveier"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> snarveier for <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> snarveier og <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> varsler for <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Snarveier og varsler"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Avvis"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Varselet ble avvist"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personlig"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Jobb"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Finn jobbapper her"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Alle jobbapper har et oransje merke og sikres av organisasjonen din. Flytt apper til startskjermen for å gjøre det enklere å finne dem."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Alle jobbapper har et merke og sikres av organisasjonen din. Flytt apper til startskjermen for å gjøre det enklere å finne dem."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Administreres av organisasjonen din"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Varsler og apper er slått av"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Lukk"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Lukket"</string>
 </resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index d15e8b2..139ac59 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"थप अनुप्रयोगहरू खोज्नुहोस्"</string>
     <string name="notifications_header" msgid="1404149926117359025">"सूचनाहरू"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
     <string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string>
-    <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string>
+    <string name="hotseat_out_of_space" msgid="7448809638125333693">"मन पर्ने ट्रे अब कुनै ठाँउ छैन"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"अनुप्रयोगको सूची"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत अनुप्रयोगहरूको सूची"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी अनुप्रयोगहरूको सूची"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"गृह"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"हटाउनुहोस्"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"विस्थापित गर्नुहोस्"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वालपेपरहरु"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"गृहपृष्ठका सेटिङहरू"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"तपाईँको प्रशासकद्वारा असक्षम गरिएको"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"परिदृश्य"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"गृह स्क्रिनलाई घुम्ने अनुमति दिनुहोस्"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फोनलाई घुमाइँदा"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"हालको प्रदर्शन सम्बन्धी सेटिङले घुमाउने सुविधालाई अनुमति दिँदैन"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"सूचनाको प्रतीक जनाउने थोप्लोहरू"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"सक्रिय छ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"निष्क्रिय छ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनासम्बन्धी पहुँच आवश्यक हुन्छ"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउन <xliff:g id="NAME">%1$s</xliff:g> को अनुप्रयोगसम्बन्धी सूचनाहरूलाई सक्रिय गर्नुहोस्"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"सेटिङहरू बदल्नुहोस्"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउनुहोस्"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"गृह स्क्रिनमा आइकन थप्नुहोस्"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नयाँ अनुप्रयोगका लागि"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"आइकनको आकार परिवर्तन गर्नुहोस्"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"गृह स्क्रिनमा"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"प्रणालीको पूर्वनिर्धारित सेटिङ प्रयोग गर्नुहोस्"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"वर्ग"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"वर्गाकार वृत्त"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्‍न"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> विजेटहरू"</string>
+    <string name="widgets_list" msgid="796804551140113767">"विजेटहरूको सूची"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"विजेटहरूको सूची बन्द गरियो"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"गृह स्क्रिनमा थप्नुहोस्"</string>
     <string name="action_move_here" msgid="2170188780612570250">"वस्तु यहाँ सार्नुहोस्"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"वस्तु गृह स्क्रिनमा थपियो"</string>
@@ -111,7 +117,7 @@
     <string name="action_move" msgid="4339390619886385032">"वस्तु सार्नुहोस्"</string>
     <string name="move_to_empty_cell" msgid="2833711483015685619">"पङ्क्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तम्भ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा सार्नुहोस्"</string>
     <string name="move_to_position" msgid="6750008980455459790">"स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
-    <string name="move_to_hotseat_position" msgid="6295412897075147808">"मनपर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"मन पर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
     <string name="item_moved" msgid="4606538322571412879">"वस्तु सारियो"</string>
     <string name="add_to_folder" msgid="9040534766770853243">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g> मा थप्नुहोस्"</string>
     <string name="add_to_folder_with_app" msgid="4534929978967147231">"फोल्डरमा <xliff:g id="NAME">%1$s</xliff:g> सँग थप्नुहोस्"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g>: मार्फत फोल्डर सिर्जना गर्नुहोस्"</string>
     <string name="folder_created" msgid="6409794597405184510">"फोल्डर सिर्जना गरियो"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"गृह स्क्रिनमा सार्नुहोस्"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रिनलाई बायाँ सार्नुहोस्"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रिनलाई दायाँ सार्नुहोस्"</string>
-    <string name="screen_moved" msgid="266230079505650577">"स्क्रिन सारियो"</string>
     <string name="action_resize" msgid="1802976324781771067">"पुनःआकार मिलाउनुहोस्"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"चौडाइ बढाउनुहोस्"</string>
     <string name="action_increase_height" msgid="459390020612501122">"उँचाइ बढाउनुहोस्"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"उँचाइ घटाउनुहोस्"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेट चौडाइ <xliff:g id="NUMBER_0">%1$s</xliff:g> उचाइ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा पुनः आकार मिलाइयो"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"सर्टकटहरू"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> का <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> सर्टकटहरू"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> का <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> सर्टकट र <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> सूचनाहरू"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"सर्टकट तथा सूचनाहरू"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारेज गर्नुहोस्"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"सूचना खारेज गरियो"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"व्यक्तिगत"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्यसम्बन्धी"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कार्यसम्बन्धी अनुप्रयोगहरू यहाँ प्राप्त गर्नुहोस्"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा सुन्तला रङको ब्याज छ र यसलाई तपाईंको संगठनद्वारा सुरक्षित राखिएको छ । अझ सजिलो गरी पहुँच राख्नका लागि कार्यसम्बन्धी अनुप्रयोगहरूलाई तपाईंको गृहस्क्रिनमा सार्नुहोस्‌।"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा ब्याज छ र तपाईंको संगठनले यसलाई सुरक्षित राखेको छ । अझ सजिलो गरी पहुँच राख्नका लागि अनुप्रयोगहरूलाई आफ्नो गृहस्क्रिनमा सार्नुहोस्‌।"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"तपाईंको सङ्गठनले व्यवस्थापन गरेको"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"सूचना र अनुप्रयोगहरू निष्क्रिय छन्‌"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बन्द गर्नुहोस्"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बन्द गरियो"</string>
 </resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 38c24a5..64f4d79 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Zoeken naar meer apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Meldingen"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tik en houd vast om snelkoppeling toe te voegen."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Er is geen ruimte meer op dit startscherm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen ruimte meer in het vak \'Favorieten\'"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lijst met apps"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lijst met persoonlijke apps"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lijst met werk-apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Homepage"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwijderen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleren"</string>
@@ -50,9 +54,9 @@
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
-    <string name="permlab_read_settings" msgid="1941457408239617576">"instellingen en snelkoppelingen op de homepage lezen"</string>
+    <string name="permlab_read_settings" msgid="1941457408239617576">"instellingen en snelkoppelingen op startscherm lezen"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"De app toestaan de instellingen en snelkoppelingen op de homepage te lezen."</string>
-    <string name="permlab_write_settings" msgid="3574213698004620587">"instellingen en snelkoppelingen op de homepage schrijven"</string>
+    <string name="permlab_write_settings" msgid="3574213698004620587">"instellingen en snelkoppelingen op startscherm zetten"</string>
     <string name="permdesc_write_settings" msgid="5440712911516509985">"De app toestaan de instellingen en snelkoppelingen op de homepage te wijzigen."</string>
     <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> mag niet bellen"</string>
     <string name="gadget_error_text" msgid="6081085226050792095">"Probleem bij het laden van widget"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Map: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Achtergrond"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Instellingen voor homepage"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Instellingen startscherm"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Uitgeschakeld door je beheerder"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Overzicht"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Draaien van startscherm toestaan"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Wanneer de telefoon gedraaid is"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Huidige scherminstelling staat draaien niet toe"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Meldingsstipjes"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aan"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Uit"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Toegang tot meldingen vereist"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Als je meldingsstipjes wilt weergeven, schakel je app-meldingen in voor <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Instellingen wijzigen"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Meldingsstipjes weergeven"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pictogram toevoegen aan startscherm"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Voor nieuwe apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Vorm van pictogram wijzigen"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"op het startscherm"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Systeemstandaard gebruiken"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Vierkant"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wordt gedownload, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wacht op installatie"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>-widgets"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lijst met widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lijst met widgets gesloten"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Toevoegen aan startscherm"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Item hier naartoe verplaatsen"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item toegevoegd aan startscherm"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Map maken met: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Map gemaakt"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Verplaatsen naar startscherm"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Scherm naar links verplaatsen"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Scherm naar rechts verplaatsen"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Scherm verplaatst"</string>
     <string name="action_resize" msgid="1802976324781771067">"Formaat aanpassen"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Breedte vergroten"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Hoogte vergroten"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Hoogte verkleinen"</string>
     <string name="widget_resized" msgid="9130327887929620">"Formaat van widget gewijzigd in breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> en hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Snelkoppelingen"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> snelkoppelingen voor <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> snelkoppelingen en <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> meldingen voor <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Snelkoppelingen en meldingen"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Sluiten"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Melding gesloten"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privé"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Zoek hier naar werk-apps"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Elke werk-app heeft een oranje badge en wordt beveiligd door je organisatie. Verplaats apps naar je startscherm om gemakkelijker toegang te krijgen."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Elke werk-app heeft een badge en wordt beveiligd door je organisatie. Verplaats apps naar je startscherm voor snelle toegang."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Beheerd door je organisatie"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Meldingen en apps zijn uitgeschakeld"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Sluiten"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Gesloten"</string>
 </resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
new file mode 100644
index 0000000..cb1cea9
--- /dev/null
+++ b/res/values-or/strings.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="649227358658669779">"ଲଞ୍ଚର୍3"</string>
+    <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"କାମ"</string>
+    <string name="activity_not_found" msgid="8071924732094499514">"ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ ହୋଇନାହିଁ"</string>
+    <string name="activity_not_available" msgid="7456344436509528827">"ଆପ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"ନିରାପଦ ମୋଡରେ ଡାଉନଲୋଡ୍‌ ହେଇଥିବା ଆପ୍‌ ଅକ୍ଷମ କରାଗଲା"</string>
+    <string name="safemode_widget_error" msgid="4863470563535682004">"ନିରାପଦ ମୋଡରେ ୱିଜେଟ୍‌ ଅକ୍ଷମ କରାଗଲା"</string>
+    <string name="shortcut_not_available" msgid="2536503539825726397">"ଶର୍ଟକଟ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="home_screen" msgid="806512411299847073">"ହୋମ୍‌ ସ୍କ୍ରୀନ୍‌"</string>
+    <string name="custom_actions" msgid="3747508247759093328">"କାର୍ଯ୍ୟ କଷ୍ଟମ୍ କରନ୍ତୁ"</string>
+    <string name="long_press_widget_to_add" msgid="7699152356777458215">"ୱିଜେଟ୍‌ ନେବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଧରି ରଖନ୍ତୁ।"</string>
+    <string name="long_accessible_way_to_add" msgid="4289502106628154155">"ଡବଲ୍‌-ଟାପ୍‌ କରନ୍ତୁ ଏବଂ ଏକ ୱିଜେଟ୍‌ ନେବାକୁ ଧରି ରଖନ୍ତୁ କିମ୍ୱା କଷ୍ଟମ୍ କାର୍ଯ୍ୟପ୍ରକ୍ରିୟା ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+    <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
+    <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ଓସାର ଓ %2$d ଉଚ୍ଚ"</string>
+    <string name="add_item_request_drag_hint" msgid="5899764264480397019">"ମାନୁଆଲ୍‌ ଭାବରେ ରଖିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଧରି ରଖନ୍ତୁ"</string>
+    <string name="place_automatically" msgid="8064208734425456485">"ସ୍ୱଚାଳିତ ଭାବେ ଯୋଡ଼ନ୍ତୁ"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ଆପ୍‌ ଖୋଜନ୍ତୁ"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"ଆପ୍‌ ଲୋଡ୍‌ ହେଉଛି..."</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ସହିତ ମେଳ ହେଉଥିବା କୌଣସି ଆପ୍‌ ମିଳିଲା ନାହିଁ"</string>
+    <string name="all_apps_search_market_message" msgid="1366263386197059176">"ଅଧିକ ଆପ୍‌ ଖୋଜନ୍ତୁ"</string>
+    <string name="notifications_header" msgid="1404149926117359025">"ବିଜ୍ଞପ୍ତି"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ଡବଲ୍‌-ଟାପ୍‌ କରନ୍ତୁ ଏବଂ ଏକ ଶର୍ଟକଟ୍ ଚୟନ କରିବାକୁ ଧରି ରଖନ୍ତୁ କିମ୍ୱା କଷ୍ଟମ୍ ପ୍ରକ୍ରିୟା ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+    <string name="out_of_space" msgid="4691004494942118364">"ହୋମ୍‌ ସ୍କ୍ରୀନ ପାଇଁ ଆଉ କୋଠରୀ ନାହିଁ"</string>
+    <string name="hotseat_out_of_space" msgid="7448809638125333693">"ମନପସନ୍ଦ ଟ୍ରେରେ ଆଉ କୋଠରୀ ନାହିଁ"</string>
+    <string name="all_apps_button_label" msgid="8130441508702294465">"ଆପ୍‌ ତାଲିକା"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ବ୍ୟକ୍ତିଗତ ଆପ୍ ତାଲିକା"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"କାର୍ଯ୍ୟକାରୀ ଆପ୍‌ ତାଲିକା"</string>
+    <string name="all_apps_home_button_label" msgid="252062713717058851">"ହୋମ୍"</string>
+    <string name="remove_drop_target_label" msgid="7812859488053230776">"ବାହାର କରନ୍ତୁ"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ୍‌ ସୂଚନା"</string>
+    <string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"ଶର୍ଟକଟ୍‍ ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"ୟୁଜରଙ୍କ ବିନା ହସ୍ତକ୍ଷେପରେ ଶର୍ଟକଟ୍‌ ଯୋଡ଼ିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
+    <string name="permlab_read_settings" msgid="1941457408239617576">"ହୋମ୍‌ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ପଢ଼ନ୍ତୁ"</string>
+    <string name="permdesc_read_settings" msgid="5833423719057558387">"ହୋମରେ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ ଏବଂ ଶର୍ଟକଟକୁ ଅନୁମତି ଦିଏ।"</string>
+    <string name="permlab_write_settings" msgid="3574213698004620587">"ହୋମ୍‌ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ଲେଖନ୍ତୁ"</string>
+    <string name="permdesc_write_settings" msgid="5440712911516509985">"ହୋମରେ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
+    <string name="msg_no_phone_permission" msgid="9208659281529857371">"ଫୋନ୍‌ କଲ୍‌ କରିବାକୁ <xliff:g id="APP_NAME">%1$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
+    <string name="gadget_error_text" msgid="6081085226050792095">"ୱିଜେଟ୍‌ ଲୋଡ୍‌ ହେବାରେ ସମସ୍ୟା ଅଛି"</string>
+    <string name="gadget_setup_text" msgid="8274003207686040488">"ସେଟ୍ ଅପ୍ କରନ୍ତୁ"</string>
+    <string name="uninstall_system_app_text" msgid="4172046090762920660">"ଏହା ଏକ ସିଷ୍ଟମ୍‌ ଆପ୍‌ ଅଟେ ଏବଂ ଏହା ଅନଇନଷ୍ଟଲ୍‌ କରାଯାଇ ପାରିବ ନାହିଁ।"</string>
+    <string name="folder_hint_text" msgid="6617836969016293992">"ବେନାମୀ ଫୋଲ୍ଡର୍‌"</string>
+    <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଅକ୍ଷମ କରାଗଲା"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ରେ <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଅଛି</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ରେ <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ବିଜ୍ଞପ୍ତି ଅଛି</item>
+    </plurals>
+    <string name="default_scroll_format" msgid="7475544710230993317">"ମୋଟ %2$dରୁ %1$d ନମ୍ବର ପୃଷ୍ଠା"</string>
+    <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$dରୁ %1$d ହୋମ୍‌ ସ୍କ୍ରୀନ୍"</string>
+    <string name="workspace_new_page" msgid="257366611030256142">"ନୂଆ ହୋମ୍‌ ସ୍କ୍ରୀନ୍‌ ପୃଷ୍ଠା"</string>
+    <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="HEIGHT">%2$d</xliff:g> / <xliff:g id="WIDTH">%1$d</xliff:g>ର ଫୋଲ୍ଡର ଖୋଲାଗଲା"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"ଫୋଲ୍ଡର୍‌ ବନ୍ଦ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"ନାମ ବଦଳାଇବା ସେଭ୍ କରିବାକୁ ଟାପ୍‌ କରନ୍ତୁ"</string>
+    <string name="folder_closed" msgid="4100806530910930934">"ଫୋଲ୍ଡର ବନ୍ଦ କରାଗଲା"</string>
+    <string name="folder_renamed" msgid="1794088362165669656">"ଫୋଲ୍ଡରର ନାମ <xliff:g id="NAME">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
+    <string name="folder_name_format" msgid="6629239338071103179">"ଫୋଲ୍ଡର: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"ୱିଜେଟ୍‌"</string>
+    <string name="wallpaper_button_text" msgid="8404103075899945851">"ୱାଲପେପର୍‌"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"ହୋମ୍‌ ସେଟିଙ୍ଗ"</string>
+    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
+    <string name="allow_rotation_title" msgid="7728578836261442095">"ହୋମ୍‌ ସ୍କ୍ରୀନ୍ ବୁଲାଇବା ଅନୁମତି ଦିଅନ୍ତୁ"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ"</string>
+    <string name="icon_badging_title" msgid="874121399231955394">"ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁଗୁଡ଼ିକ"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"ଅନ୍"</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"ଅଫ୍‌"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"ବିଜ୍ଞପ୍ତି ଆକ୍ସେସ୍‌ ଆବଶ୍ୟକ ଅଟେ"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"ବିଜ୍ଞପ୍ତି ବିନ୍ଦୁ ଦେଖାଇବାକୁ, <xliff:g id="NAME">%1$s</xliff:g> ପାଇଁ ଆପ୍‌ ବିଜ୍ଞପ୍ତି ଅନ୍‌ କରନ୍ତୁ"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"ସେଟିଙ୍ଗ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"ବିଜ୍ଞପ୍ତି ଡଟ୍‌ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ହୋମ୍‌ ସ୍କ୍ରୀନରେ ଆଇକନ୍‌କୁ ଯୋଡ଼ନ୍ତୁ"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ନୂଆ ଆପ୍‌ ପାଇଁ"</string>
+    <string name="icon_shape_override_label" msgid="2977264953998281004">"ଆଇକନ୍‌ର ଆକାର ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ହୋମ୍ ସ୍କ୍ରୀନ୍ ଉପରେ"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"ସିଷ୍ଟମ ଡିଫଲ୍ଟ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="icon_shape_square" msgid="633575066111622774">"ବର୍ଗାକାର"</string>
+    <string name="icon_shape_squircle" msgid="5658049910802669495">"ବର୍ଗାକାରର ବୃତ୍ତ"</string>
+    <string name="icon_shape_circle" msgid="6550072265930144217">"ବୃତ୍ତ"</string>
+    <string name="icon_shape_teardrop" msgid="4525869388200835463">"ଟିଅରଡ୍ରପ୍‌"</string>
+    <string name="icon_shape_override_progress" msgid="3461735694970239908">"ଆଇକନ୍‌ ଆକାର ପରିବର୍ତ୍ତନ ଲାଗୁ କରୁଛି"</string>
+    <string name="package_state_unknown" msgid="7592128424511031410">"ଅଜଣା"</string>
+    <string name="abandoned_clean_this" msgid="7610119707847920412">"ବାହାର କରନ୍ତୁ"</string>
+    <string name="abandoned_search" msgid="891119232568284442">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <string name="abandoned_promises_title" msgid="7096178467971716750">"ଏହି ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ ହୋଇନାହିଁ"</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ଏହି ଆଇକନ୍‌ ପାଇଁ ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ ହୋଇନାହିଁ। ଏହାକୁ ଆପଣ ଆପ୍‌ ପାଇଁ ବାହାର କରିପାରିବେ କିମ୍ୱା ସର୍ଚ୍ଚ କରି ପାରିବେ ଏବଂ ଏହାକୁ ମାନୁଆଲ୍‌ ଭାବରେ ଇନଷ୍ଟଲ୍‌ କରିପାରିବେ।"</string>
+    <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍‌ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
+    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍‌ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
+    <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ୱିଜେଟ୍‌"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ୱିଜେଟ୍ ତାଲିକା"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ୱିଜେଟ୍ ତାଲିକା ବନ୍ଦ ହୋଇଛି"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ହୋମ୍‌ ସ୍କ୍ରୀନରେ ଯୋଡ଼ନ୍ତୁ"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ଆଇଟମ୍‌କୁ ଏଠାକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ହୋମ୍‌ ସ୍କ୍ରୀନରେ ଆଇଟମ୍‌ ଯୋଡ଼ାଗଲା"</string>
+    <string name="item_removed" msgid="851119963877842327">"ଆଇଟମ୍‌ ବାହାର କରାଗଲା"</string>
+    <string name="action_move" msgid="4339390619886385032">"ଆଇଟମ୍‌ ଘୁଞ୍ଚାନ୍ତୁ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ଧାଡ଼ି <xliff:g id="NUMBER_0">%1$s</xliff:g> ସ୍ତମ୍ଭ <xliff:g id="NUMBER_1">%2$s</xliff:g>କୁ ନିଅନ୍ତୁ"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ସ୍ଥିତିକୁ ନିଅନ୍ତୁ"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ପସନ୍ଦର ସ୍ଥିତି <xliff:g id="NUMBER">%1$s</xliff:g>କୁ ନିଅନ୍ତୁ"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ଆଇଟମ୍‌ ଘୁଞ୍ଚେଇ ଦିଆଗଲା"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ଏହି ଫୋଲ୍ଡରରେ ଯୋଡ଼ନ୍ତୁ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ସହିତ ଫୋଲ୍ଡରରେ ଯୋଡ଼ନ୍ତୁ"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ଫୋଲ୍ଡରରେ ଆଇଟମ୍‌ ଯୋଡ଼ାଗଲା"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ଏହି ନାମରେ ଫୋଲ୍ଡର ତିଆରି କରନ୍ତୁ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ଫୋଲ୍ଡର ତିଆରି କରାଗଲା"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ହାମ୍‌ ସ୍କ୍ରୀନକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ଆକାର ବଦଳାନ୍ତୁ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"ଚଉଡ଼ା ବଢ଼ାନ୍ତୁ"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ଉଚ୍ଚତା ବଢ଼ାନ୍ତୁ"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ଚଉଡ଼ା କମ୍‌ କରନ୍ତୁ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ଉଚ୍ଚତା କମ୍‌ କରନ୍ତୁ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ୱିଜେଟକୁ <xliff:g id="NUMBER_0">%1$s</xliff:g> ଓସାର ଓ <xliff:g id="NUMBER_1">%2$s</xliff:g> ଉଚ୍ଚରେ ପୁନଃଆକାର ଦିଆଗଲା"</string>
+    <string name="action_deep_shortcut" msgid="2864038805849372848">"ଶର୍ଟକଟ୍‍"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ଶର୍ଟକଟ୍ ଓ ବିଜ୍ଞପ୍ତି"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"ଖାରଜ କରନ୍ତୁ"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"ବ୍ୟକ୍ତିଗତ"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"କାମ"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
+    <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ଏଠାରେ କାମ ଆପ୍‌ ଖୋଜନ୍ତୁ"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ପ୍ରତ୍ୟେକ କାଯ୍ୟକାରୀ ଆପ୍‌ର ଗୋଟିଏ ବ୍ୟାଜ୍ (ଚିହ୍ନ) ଅଛି, ଯାହାକୁ ଆପଣଙ୍କ ସଂସ୍ଥା ସୁରକ୍ଷିତ ରଖିଥାଏ। ସହଜରେ ଆକ୍ସେସ୍ କରିବା ପାଇଁ ଆପ୍‌କୁ ହୋମ୍ ସ୍କ୍ରୀନ୍ ଉପରକୁ ଆଣନ୍ତୁ।"</string>
+    <string name="work_mode_on_label" msgid="4781128097185272916">"ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ପରିଚାଳିତ"</string>
+    <string name="work_mode_off_label" msgid="3194894777601421047">"ବିଜ୍ଞପ୍ତି ଓ ଆପ୍‌ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ବନ୍ଦ କରନ୍ତୁ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ବନ୍ଦ ହୋଇଯାଇଛି"</string>
+</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 6b6c929..1ca7cc8 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"</string>
     <string name="notifications_header" msgid="1404149926117359025">"ਸੂਚਨਾਵਾਂ"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ਐਪ ਸੂਚੀ"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ਨਿੱਜੀ ਐਪਾਂ ਦੀ ਸੂਚੀ"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"ਕਾਰਜ-ਸਥਾਨ ਸੰਬੰਧੀ ਐਪਾਂ ਦੀ ਸੂਚੀ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ਹੋਮ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ਹਟਾਓ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ਵਾਲਪੇਪਰ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ਹੋਮ ਸੈਟਿੰਗਾਂ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਈ ਗਈ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ਰੂਪ-ਰੇਖਾ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ਹੋਮ ਸਕ੍ਰੀਨ ਨੂੰ ਘੁੰਮਾਉਣ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ਜਦੋਂ ਫ਼ੋਨ ਘੁੰਮਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ਵਰਤਮਾਨ ਡਿਸਪਲੇ ਸੈਟਿੰਗ ਘੁੰਮਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦੀ ਹੈ"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"ਸੂਚਨਾ ਬਿੰਦੂ"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ਚਾਲੂ"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ਬੰਦ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"ਸੂਚਨਾ ਪਹੁੰਚ ਲੋੜੀਂਦੀ ਹੈ"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"ਸੂਚਨਾ ਬਿੰਦੂਆਂ ਦਿਖਾਉਣ ਲਈ, <xliff:g id="NAME">%1$s</xliff:g> ਲਈ ਐਪ ਸੂਚਨਾਵਾਂ ਚਾਲੂ ਕਰੋ"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"ਸੂਚਨਾ ਬਿੰਦੂ ਦਿਖਾਓ"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰਤੀਕ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ਨਵੀਆਂ ਐਪਾਂ ਲਈ"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ਪ੍ਰਤੀਕ ਦੀ ਆਕ੍ਰਿਤੀ ਬਦਲੋ"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ਸਿਸਟਮ ਦੀ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗ ਵਰਤੋ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"ਵਰਗ"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"ਵਰਗਾਕਾਰ-ਚੱਕਰ"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ਵਿਜੇਟਾਂ ਦੀ ਸੂਚੀ ਬੰਦ ਕੀਤੀ ਗਈ"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ਇਸਦੇ ਨਾਲ ਫੋਲਡਰ ਬਣਾਓ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ਫੋਲਡਰ ਬਣਾਇਆ ਗਿਆ"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"ਸਕ੍ਰੀਨ ਨੂੰ ਖੱਬੇ ਮੂਵ ਕਰੋ"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"ਸਕ੍ਰੀਨ ਨੂੰ ਸੱਜੇ ਮੂਵ ਕਰੋ"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ਸਕ੍ਰੀਨ ਨੂੰ ਮੂਵ ਕੀਤਾ ਗਿਆ"</string>
     <string name="action_resize" msgid="1802976324781771067">"ਮੁੜ ਆਕਾਰ ਦਿਓ"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"ਚੌੜਾਈ ਵਧਾਓ"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ਉਂਚਾਈ ਵਧਾਓ"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ਉਂਚਾਈ ਘਟਾਓ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ਵਿਜੈਟ ਨੂੰ ਚੌੜਾਈ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਉਂਚਾਈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਨੂੰ ਮੁੜ ਆਕਾਰ ਦਿੱਤਾ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ਸ਼ਾਰਟਕੱਟ"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਲਈ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ਸ਼ਾਰਟਕੱਟ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ਲਈ <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ਸ਼ਾਰਟਕੱਟ ਅਤੇ <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ਸ਼ਾਰਟਕੱਟ ਅਤੇ ਸੂਚਨਾਵਾਂ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ਸੂਚਨਾ ਖਾਰਜ ਕੀਤੀ ਗਈ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ਨਿੱਜੀ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ਕਾਰਜ-ਸਥਾਨ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ ਇੱਥੇ ਲੱਭੋ"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਸੰਤਰੀ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਰਾਹੀਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ਬੰਦ ਕਰੋ"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
 </resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index c90ba1e..776f39d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Wyszukaj więcej aplikacji"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Powiadomienia"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Kliknij i przytrzymaj, by wybrać skrót."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Brak miejsca w Ulubionych"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista aplikacji"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista aplikacji osobistych"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista aplikacji do pracy"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ekran główny"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Usuń"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Ustawienia strony głównej"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Funkcja wyłączona przez administratora"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Przegląd"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Zezwalaj na obrót ekranu głównego"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Po obróceniu telefonu"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Obecne ustawienia wyświetlania nie pozwalają na obrót ekranu"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Plakietki z powiadomieniami"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Włączono"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Wyłączono"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazać plakietki z powiadomieniami, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Pokaż plakietki z powiadomieniami"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikonę do ekranu głównego"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmień kształt ikon"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na ekranie głównym"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Użyj ustawienia domyślnego"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kwadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaokrąglony kwadrat"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Pobieranie elementu <xliff:g id="NAME">%1$s</xliff:g>, ukończono: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> oczekuje na instalację"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> – widżety"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista widgetów"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista widgetów zamknięta"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodaj do strony głównej"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Przenieś element tutaj"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element został dodany do ekranu głównego"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Utwórz folder z: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folder został utworzony"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Przenieś na ekran główny"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Przenieś ekran w lewo"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Przenieś ekran w prawo"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran został przeniesiony"</string>
     <string name="action_resize" msgid="1802976324781771067">"Zmień rozmiar"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Zwiększ szerokość"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Zwiększ wysokość"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zmniejsz wysokość"</string>
     <string name="widget_resized" msgid="9130327887929620">"Szerokość i wysokość widżetu zmieniła się na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Skróty"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Skróty aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Skróty (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) i powiadomienia (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) aplikacji <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Skróty i powiadomienia"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odrzuć"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Powiadomienie odrzucone"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobiste"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Praca"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil służbowy"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Aplikacje do pracy"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Każda aplikacja do pracy ma pomarańczową plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Każda aplikacja do pracy ma plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Profil zarządzany przez Twoją organizację"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Powiadomienia i aplikacje są wyłączone"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zamknij"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zamknięto"</string>
 </resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index c370a8e..4010591 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -40,13 +40,17 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhuma aplicação correspondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais aplicações"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Toque sem soltar para escolher um atalho."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Não existe mais espaço no tabuleiro de Favoritos"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicações"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicações pessoais"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicações de trabalho"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ecrã principal"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Inf. da aplicação"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicação"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma aplicação adicionar atalhos sem a intervenção do utilizador."</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagens de fundo"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Definições da página inicial"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativada pelo gestor"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Vista geral"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotação do ecrã principal"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Quando o telemóvel é rodado"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"A definição de visualização atual não permite a rotação"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativada"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativada"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar os Pontos de notificação, ative as notificações de aplicações para o <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Alterar definições"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar pontos de notificação"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone ao ecrã principal"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novas aplicações"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma do ícone"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"no ecrã principal"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Utilizar a predefinição do sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado e círculo"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"A transferir o <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A aguardar a instalação do <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada."</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar ao Ecrã principal"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mover o item para aqui"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado ao ecrã principal"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Criar pasta com: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Pasta criada"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover para o Ecrã principal"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover ecrã para a esquerda"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mover ecrã para a direita"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ecrã movido"</string>
     <string name="action_resize" msgid="1802976324781771067">"Redimensionar"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumentar largura"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atalhos"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atalhos para a aplicação <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atalhos e <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificações para a aplicação <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atalhos e notificações"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorar"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notificação ignorada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Encontrar as aplicações de trabalho aqui"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada aplicação de trabalho apresenta um emblema laranja, pelo que a sua entidade a mantém em segurança. Pode mover as aplicações para o ecrã principal para facilitar o acesso."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada aplicação de trabalho apresenta um emblema, pelo que a sua entidade a mantém em segurança. Pode mover as aplicações para o ecrã principal para facilitar o acesso."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Gerido pela sua entidade"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e as aplicações estão desativadas."</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fechar"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fechado"</string>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 0686ae7..6238e7a 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Pesquisar mais apps"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificações"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Toque e segure para selecionar um atalho."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Não há mais espaço na tela inicial."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Sem espaço na bandeja de favoritos"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de apps"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de apps pessoais"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de apps profissionais"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Início"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Pasta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Planos de fundo"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Configurações da página inicial"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Configurações da tela inicial"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativado pelo administrador"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Visão geral"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotação da tela inicial"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Quando o smartphone for girado"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"A configuração atual de exibição não permite rotação"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pontos de notificação"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Ativado"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Desativado"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Acesso a notificações necessário"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar pontos de notificação, ative as notificações de app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Alterar configurações"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Mostrar pontos de notificação"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adicionar ícone à tela inicial"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para novos apps"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Alterar forma de ícones"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na tela inicial"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Usar padrão do sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Quadrado"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Quadrado arredondado"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Fazendo download de <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aguardando instalação de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgets do <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista de widgets"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgets fechada"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar à tela inicial"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mover item para cá"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado à tela inicial"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Criar pasta com: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Pasta criada"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover para a tela inicial"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover tela para a esquerda"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mover tela para a direita"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Tela movida"</string>
     <string name="action_resize" msgid="1802976324781771067">"Redimensionar"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Aumentar largura"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atalhos"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atalhos para <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> atalhos e <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificações para o app <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atalhos e notificações"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dispensar"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notificação dispensada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoais"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Comerciais"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Localizar apps de trabalho aqui"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Cada app de trabalho tem um selo laranja e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Cada app de trabalho tem um selo e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Gerenciados pela sua organização"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"As notificações e os apps estão desativados"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Fechar"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Fechado"</string>
 </resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 651b264..fb5fb96 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Căutați mai multe aplicații"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Notificări"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Atingeți lung pentru a selecta o comandă rapidă."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Atingeți lung pentru a selecta o comandă rapidă sau folosiți acțiuni personalizate."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spațiu epuizat în bara Preferate"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista de aplicații"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista de aplicații personale"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicații de serviciu"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ecran de pornire"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eliminați"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalați"</string>
@@ -78,19 +82,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagini de fundal"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Setări pentru ecranul de pornire"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dezactivată de administrator"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Prezentare generală"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permiteți rotirea ecranului de pornire"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Când telefonul este rotit"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Setarea actuală a afișajului nu permite rotirea"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Puncte de notificare"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Activat"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Dezactivat"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Este necesar accesul la notificări"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Pentru a afișa punctele de notificare, activați notificările din aplicație pentru <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Modificați setările"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Afișați punctele de notificare"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Adaugă pictograme în ecranul de pornire"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pentru aplicații noi"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Schimbați forma pictogramei"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"pe ecranul de pornire"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Folosiți setarea prestabilită a sistemului"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Pătrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Pătrat cu colțuri rotunjite"</string>
@@ -105,6 +109,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se descarcă (finalizat <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> așteaptă instalarea"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Widgeturi <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Listă de widgeturi"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista de widgeturi este închisă"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Adăugați pe ecranul de pornire"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Mutați elementul aici"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element adăugat pe ecranul de pornire"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Creați dosar cu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Dosar creat"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Mutați pe ecranul de pornire"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Mutați ecranul la stânga"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Mutați ecranul la dreapta"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ecran mutat"</string>
     <string name="action_resize" msgid="1802976324781771067">"Redimensionați"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Creșteți lățimea"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Creșteți înălțimea"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reduceți înălțimea"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetul a fost redimensionat la lățimea <xliff:g id="NUMBER_0">%1$s</xliff:g> și înălțimea <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Comenzi rapide"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> comenzi rapide pentru <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> comenzi rapide și <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> notificări pentru <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Comenzi rapide și notificări"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Închideți"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Notificare închisă"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Profesionale"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil de serviciu"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Găsiți aplicații de serviciu aici"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Fiecare aplicație de serviciu are o insignă portocalie și este păstrată în siguranță de organizația dvs. Mutați aplicațiile de serviciu pe ecranul de pornire pentru acces mai ușor."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Fiecare aplicație de serviciu are o insignă și este păstrată în siguranță de organizația dvs. Mutați aplicațiile pe ecranul de pornire pentru acces mai ușor."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Gestionat de organizația dvs."</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Notificările și aplicațiile sunt dezactivate"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Închideți"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Închis"</string>
 </resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9f43c56..dd70521 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Искать другие приложения"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Уведомления"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Нажмите и удерживайте, чтобы выбрать ярлык."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Нажмите дважды и удерживайте, чтобы выбрать ярлык или использовать специальные действия."</string>
     <string name="out_of_space" msgid="4691004494942118364">"На этом экране все занято"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В разделе \"Избранное\" больше нет места"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Список приложений"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Открыть список личных приложений"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Открыть список приложений для работы"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Главный экран"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Убрать"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
@@ -67,7 +71,7 @@
       <item quantity="other">В приложении \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> уведомления</item>
     </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Стр. %1$d из %2$d"</string>
-    <string name="workspace_scroll_format" msgid="8458889198184077399">"Главные экран %1$d из %2$d"</string>
+    <string name="workspace_scroll_format" msgid="8458889198184077399">"Главный экран %1$d из %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Новый экран"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папка открыта, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="4625795376335528256">"Нажмите, чтобы закрыть папку"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Обои"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Настройки главного экрана"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Функция отключена администратором"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Обзор"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Разрешить поворачивать главный экран"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Когда телефон повернут"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"В настройках отключен поворот экрана"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Значки уведомлений"</string>
-    <string name="icon_badging_desc_on" msgid="2627952638544674079">"ВКЛ"</string>
-    <string name="icon_badging_desc_off" msgid="5503319969924580241">"ВЫКЛ"</string>
+    <string name="icon_badging_desc_on" msgid="2627952638544674079">"Вкл."</string>
+    <string name="icon_badging_desc_off" msgid="5503319969924580241">"Выкл."</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Нет доступа к уведомлениям"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Чтобы показывать значки уведомлений, включите уведомления в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Изменить настройки"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Показывать значки уведомлений"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Добавлять значки"</string>
-    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Добавлять значки установленных приложений на главный экран."</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Добавлять значки установленных приложений на главный экран"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Изменить форму значков"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на главном экране"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Использовать системные настройки по умолчанию"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Квадрат с закругленными краями"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Скачивается \"<xliff:g id="NAME">%1$s</xliff:g>\" (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Ожидание установки \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>: виджеты"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Список виджетов"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Список виджетов закрыт"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Добавить на главный экран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Переместить элемент сюда"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент добавлен на главный экран"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Создать папку с элементом <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="folder_created" msgid="6409794597405184510">"Папка создана."</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Переместить на главный экран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Переместить экран влево"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Переместить экран вправо"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Экран перемещен"</string>
     <string name="action_resize" msgid="1802976324781771067">"Изменить размер"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Увеличить ширину"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Увеличить высоту"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Уменьшить высоту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Изменен размер виджета: до <xliff:g id="NUMBER_0">%1$s</xliff:g> в ширину и <xliff:g id="NUMBER_1">%2$s</xliff:g> в высоту"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыки"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Количество ярлыков для приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\": <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Количество ярлыков для приложения \"<xliff:g id="APP_NAME">%3$s</xliff:g>\": <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>. Количество уведомлений: <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>."</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлыки и уведомления"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Закрыть"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Уведомление закрыто"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Личные"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Рабочие"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Рабочий профиль"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Приложения для работы"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Рабочие приложения отмечены оранжевым значком, который подтверждает, что ваша организация гарантирует их безопасность. Для удобства перенесите эти приложения на главный экран."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Рабочие приложения отмечены специальным значком. Их безопасность обеспечивает ваша организация. Для удобства перенесите эти приложения на главный экран."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Управляется вашей организацией"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Уведомления и приложения отключены."</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрыть"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрыта"</string>
 </resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index bbcc257..ee61124 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"තව යෙදුම් සඳහා සොයන්න"</string>
     <string name="notifications_header" msgid="1404149926117359025">"දැනුම්දීම්"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
     <string name="out_of_space" msgid="4691004494942118364">"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ප්‍රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"යෙදුම් ලැයිස්තුව"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"පෞද්ගලික යෙදුම් ලැයිස්තුව"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"වැඩ යෙදුම් ලැයිස්තුව"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"මුල් පිටුව"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ඉවත් කරන්න"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"අස්ථාපනය කරන්න"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"වෝල්පේපර"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home සැකසීම්"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ඔබගේ පරිපාලක විසින් අබල කරන ලදී"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"දළ විශ්ලේෂණය"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"මුල් පිටු තිරය කරකැවීමට ඉඩ දෙන්න"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"දුරකථනය කරකවන විට"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"වත්මන් සංදර්ශක සැකසීම් කරකැවීමට සහාය නොදක්වයි"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"දැනුම්දීම් තිත්"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ක්‍රියාත්මකයි"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ක්‍රියාවිරහිතයි"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"දැනුම්දීම් ප්‍රවේශය අවශ්‍යයි"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"දැනුම්දීම් තිත් පෙන්වීමට, <xliff:g id="NAME">%1$s</xliff:g> සඳහා යෙදුම් දැනුම්දීම් සබල කරන්න"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"සැකසීම් වෙනස් කරන්න"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"දැනුම් දීමේ තිත් පෙන්වන්න"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"මුල් පිටු තිරය වෙත අයිකනය එක් කරන්න"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"නව යෙදුම් සඳහා"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"නිරූපක හැඩය වෙනස් කරන්න"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"මුල් පිටු තිරය මත"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"පද්ධති පෙරනිමි භාවිත කරන්න"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"සමචතුරස්‍රය"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"හතරැස් කවය"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> බාගත කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කිරීමට බලා සිටිමින්"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> විජට්"</string>
+    <string name="widgets_list" msgid="796804551140113767">"විජට් ලැයිස්තුව"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"විජට් ලැයිස්තුව වසා ඇත"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"මුල් තිරය වෙත එක් කරන්න"</string>
     <string name="action_move_here" msgid="2170188780612570250">"මෙතනට අයිතමය ගෙන එන්න"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"අයිතමය මුල් තිරය වෙත එකතු කරන ලදි"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"මේ සමග ෆෝල්ඩරය සාදන්න: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ෆෝල්ඩරය සාදන ලදි"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"මුල් තිරය වෙත ගෙන යන්න"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"තිරය වම් පැත්තට ගෙනයන්න"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"තිරය දකුණු පැත්තට ගෙනයන්න"</string>
-    <string name="screen_moved" msgid="266230079505650577">"තිරය ගෙන යන ලදි"</string>
     <string name="action_resize" msgid="1802976324781771067">"නැවත ප්‍රමාණගත කිරීම"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"පළල වැඩි කරන්න"</string>
     <string name="action_increase_height" msgid="459390020612501122">"උස වැඩි කරන්න"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"උස අඩු කරන්න"</string>
     <string name="widget_resized" msgid="9130327887929620">"විජට් පළල <xliff:g id="NUMBER_0">%1$s</xliff:g> උස <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ප්‍රමාණකරණය කරන ලදි"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"කෙටිමං"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> සඳහා කෙටි මං <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> සඳහා කෙටි මං <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>ක් සහ දැනුම්දීම් <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>ක්"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"කෙටි මං සහ දැනුම්දීම්"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ඉවතලන්න"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"දැනුම්දීම ඉවතලන ලදී"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"පුද්ගලික"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"කාර්යාලය"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"කාර්යාල පැතිකඩ"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"මෙහි කාර්යාල යෙදුම් සොයා ගන්න"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"සෑම කාර්යාල යෙදුමකම තැඹිලි ලාංඡනයක් ඇත ඇති අතර එය ඔබේ සංවිධානය විසින් සුරක්ෂිතව තබා ගනී. වඩා පහසුවෙන් පිවිසීමට යෙදුම් ඔබගේ මුල් පිටු තිරය වෙත ගෙන යන්න."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"සෑම කාර්යාල යෙදුමකම ලාංඡනයක් ඇත ඇති අතර එය ඔබේ සංවිධානය මගින් සුරක්ෂිතව තබා ගනී. වඩාත් පහසු ප්‍රවේශයකට යෙදුම් ඔබේ මුල් පිටු තිරය වෙත ගෙන යන්න."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"ඔබේ සංවිධානය විසින් කළමනාකරණය කරනු ලැබේ"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"දැනුම්දීම් සහ යෙදුම් ක්‍රියාවිරහිතයි"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"වසන්න"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"වසා ඇත"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index a3bc4ec..649aecc8 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Hľadať ďalšie aplikácie"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Upozornenia"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Skratku pridáte pridržaním."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tejto ploche už nie je miesto"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na paneli Obľúbené položky už nie je miesto"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Zoznam aplikácií"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Zoznam osobných aplikácií"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Zoznam pracovných aplikácií"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Domovská stránka"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrániť"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinštalovať"</string>
@@ -77,21 +81,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Priečinok: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikácie"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Nastavenia služby Home"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Nastavenia Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Zakázané vaším správcom"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Prehľad"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Povoliť otáčanie plochy"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Pri otočení telefónu"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Aktuálne nastavenie obrazovky nepovoľuje otáčanie"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Bodky upozornení"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Zapnuté"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Vypnuté"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Vyžaduje sa prístup k upozorneniam"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Ak chcete, aby sa zobrazovali bodky upozornení, zapnite upozornenia aplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Zmeniť nastavenia"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Zobrazovať bodky upozornení"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Pridať ikonu na plochu"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pri inštalácii novej aplikácie"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Zmeniť tvar ikony"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na ploche"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Použiť predvolené nastavenie systému"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Štvorec"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Okrúhly štvorec"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Sťahuje sa aplikácia <xliff:g id="NAME">%1$s</xliff:g>. Stiahnuté: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikácia <xliff:g id="NAME">%1$s</xliff:g> čaká na inštaláciu"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Miniaplikácie <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Zoznam miniaplikácií"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Zoznam miniaplikácií je zavretý"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Pridať na plochu"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Presunúť položku sem"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Položka bola pridaná na plochu"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Vytvoriť priečinok pomocou: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Priečinok bol vytvorený"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Presunúť na plochu"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Presunúť obrazovku doľava"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Presunúť obrazovku doprava"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Obrazovka bola posunutá"</string>
     <string name="action_resize" msgid="1802976324781771067">"Zmeniť veľkosť"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Zvýšiť šírku"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Zväčšiť výšku"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Znížiť výšku"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veľkosť miniaplikácie bola zmenená na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g> (šírka x výška)"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Skratky"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Počet skratiek aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Odkazy (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) a upozornenia (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) pre aplikáciu <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Odkazy a upozornenia"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Zavrieť"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Upozornenie bolo zavreté"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobné"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovné"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovný profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tu nájdete pracovné aplikácie"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Všetky pracovné aplikácie majú oranžový štítok a sú bezpečne uchovávané vašou organizáciou. Ak chcete mať k aplikáciám ľahší prístup, presuňte ich na plochu."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Všetky pracovné aplikácie majú štítok a sú bezpečne uchovávané vašou organizáciou. Ak chcete mať k aplikáciám ľahší prístup, presuňte ich na plochu."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Spravované vašou organizáciou"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Upozornenia a aplikácie sú vypnuté"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zavrieť"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zavreté"</string>
 </resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 337cb2d..aa3bc4f 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Iskanje več aplikacij"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Obvestila"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Pridržite bližnjico, da jo izberete."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tem začetnem zaslonu ni več prostora."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"V vrstici za priljubljene ni več prostora"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Seznam aplikacij"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Seznam osebnih aplikacij"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Seznam delovnih aplikacij"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Začetni zaslon"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrani"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odstrani"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ozadja"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Nastavitve začetnega zaslona"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Onemogočil skrbnik."</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Pregled"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Omogočanje sukanja začetnega zaslona"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Ko se telefon zasuka"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Trenutna nastavitev zaslona ne dovoljuje sukanja"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Obvestilne pike"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Vklopljeno"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Izklopljeno"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreben je dostop do obvestil"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Za prikaz obvestilnih pik vklopite obvestila aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Spremeni nastavitve"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Pokaži obvestilne pike"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Dodaj ikono na začetni zaslon"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Spremeni obliko ikon"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"na začetnem zaslonu"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Uporabi privzeto nastavitev sistema"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Zaobljen kvadrat"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Prenašanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>; preneseno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> čaka na namestitev"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Pripomočki za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Seznam pripomočkov"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Seznam pripomočkov se je zaprl"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodajanje na začetni zaslon"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Premik elementa sem"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Element je bil dodan na začetni zaslon"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Ustvarjanje mape s tem: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mapa je ustvarjena"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Premik na začetni zaslon"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Premik zaslona levo"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Premika zaslona desno"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Zaslon je bil premaknjen"</string>
     <string name="action_resize" msgid="1802976324781771067">"Spreminjanje velikosti"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Povečanje širine"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Povečanje višine"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zmanjšanje višine"</string>
     <string name="widget_resized" msgid="9130327887929620">"Velikost pripomočka je bila spremenjena na <xliff:g id="NUMBER_0">%1$s</xliff:g> širine in <xliff:g id="NUMBER_1">%2$s</xliff:g> višine"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Bližnjice"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Št. bližnjic za aplikacijo <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Bližnjice (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) in obvestila (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) aplikacije <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Bližnjice in obvestila"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Opusti"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Obvestilo je bilo opuščeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osebno"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Služba"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Delovni profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tukaj poiščite delovne aplikacije"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Vsaka delovna aplikacija ima oranžno značko. Za varnost teh aplikacij skrbi vaša organizacija. Za preprostejši dostop premaknite aplikacije na začetni zaslon."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Vsaka delovna aplikacija ima značko. Za varnost teh aplikacij skrbi vaša organizacija. Za preprostejši dostop premaknite aplikacije na začetni zaslon."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Upravlja vaša organizacija"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Obvestila in aplikacije – izklopljeno"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Zapri"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Zaprto"</string>
 </resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index e79f0d4..8cf0a81 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nuk u gjet asnjë aplikacion që përputhet me \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Kërko për më shumë aplikacione"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Njoftimet"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Prek dhe mbaj prekur për të zgjedhur një shkurtore."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nuk ka më hapësirë në këtë ekran bazë."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Lista e aplikacioneve"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista e aplikacioneve personale"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista e aplikacioneve të punës"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Faqja kryesore"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hiqe"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
@@ -77,20 +81,20 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imazhet e sfondit"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Cilësimet e Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Çaktivizuar nga administratori"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Përmbledhje"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Lejo rrotullimin e ekranit kryesor"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kur telefoni rrotullohet"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Cilësimi aktuali i afishimit nuk lejon rrotullimin"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Pikat e njoftimeve"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Aktiv"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Joaktiv"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Nevojitet qasja në njoftime"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Për të shfaqur \"Pikat e njoftimeve\", aktivizo njoftimet e aplikacionit për <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Ndrysho cilësimet"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Shfaq pikat e njoftimeve"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Shto ikonë në ekranin bazë"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Për aplikacionet e reja"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ndrysho formën e ikonës"</string>
-    <string name="icon_shape_system_default" msgid="1709762974822753030">"Përdor parazgjedhjen e sisteit"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"në ekranin bazë"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Përdor parazgjedhjen e sistemit"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Katror"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Katror me kënde të rrumbullakëta"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Rreth"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> po shkarkohet, <xliff:g id="PROGRESS">%2$s</xliff:g> të përfunduara"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> po pret të instalohet"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Miniaplikacionet e <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista e miniaplikacioneve"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista e miniaplikacioneve u mbyll"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Shto në Ekranin bazë"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Zhvendose artikullin këtu"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Artikulli u shtua tek ekrani bazë"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Krijo një dosje me: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Dosja u krijua"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Zhvendose në Ekranin bazë"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Zhvendose ekranin në të majtë"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Zhvendose ekranin në të djathtë"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekrani u zhvendos"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ndrysho madhësinë"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Rrit gjerësinë"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Rrit lartësinë"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zvogëlo lartësinë"</string>
     <string name="widget_resized" msgid="9130327887929620">"Madhësia e miniaplikacionit u ndryshua me gjerësinë <xliff:g id="NUMBER_0">%1$s</xliff:g> dhe lartësinë <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Shkurtoret"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shkurtesa për <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> shkurtore dhe <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> njoftime për <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shkurtoret dhe njoftimet"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hiqe"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Njoftimi u hoq"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Punë"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profili i punës"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Gjej këtu aplikacionet e punës"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Secili aplikacion pune ka një distinktiv portokalli dhe mbahet i sigurt nga organizata jote. Zhvendosi aplikacionet e punës në ekranin tënd kryesor për qasje më të lehtë."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Secili aplikacion pune ka një distinktiv dhe mbahet i sigurt nga organizata jote. Zhvendosi aplikacionet e punës në ekranin tënd kryesor për qasje më të lehtë."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Menaxhohet nga organizata jote"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Njoftimet dhe aplikacionet janë joaktive"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Mbyll"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Mbyllur"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 7d5e28d..42522a5 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Претражи још апликација"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Обавештења"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Додирните и задржите да бисте изабрали пречицу."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Нема више простора на овом почетном екрану."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема више простора на траци Омиљено"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Листа апликација"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Листа личних апликација"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Листа пословних апликација"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Уклони"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
@@ -78,19 +82,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Позадине"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Подешавања почетног екрана"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администратор је онемогућио"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Преглед"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Дозволи ротацију почетног екрана"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Када се телефон ротира"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Актуелно подешавање приказа не дозвољава ротацију"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Тачке за обавештења"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Укључено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Искључено"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребан је приступ за обавештења"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Промените подешавања"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Приказуј тачке за обавештења"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додај икону на почетни екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нове апликације"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Промените облик икона"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на почетном екрану"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Користи подразумевано системско подешавање"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Заобљени квадрат"</string>
@@ -105,6 +109,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Виџети за <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Листа виџета"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Листа виџета је затворена"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Додај на почетни екран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Премести ставку овде"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставка је додата на почетни екран"</string>
@@ -120,9 +126,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Направите директоријум са: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Директоријум је направљен"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Премести на почетни екран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Помери екран улево"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Помери екран удесно"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Екран је померен"</string>
     <string name="action_resize" msgid="1802976324781771067">"Промени величину"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Повећај ширину"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Повећај висину"</string>
@@ -130,15 +133,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Смањи висину"</string>
     <string name="widget_resized" msgid="9130327887929620">"Величина виџета је промењена на ширину <xliff:g id="NUMBER_0">%1$s</xliff:g> и висину <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Пречице"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> пречице(а) за <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Пречице (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) и обавештења (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) за <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Пречице и обавештења"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Одбаци"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Обавештење је одбачено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Личне"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Пословне"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Профил за Work"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Пронађите пословне апликације овде"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Свака пословна апликација има наранџасту значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Свака пословна апликација има значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Овим управља организација"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Обавештења и апликације су искључени"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Затвори"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Затворено"</string>
 </resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index c886780..957a4cb 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Inga appar som matchar <xliff:g id="QUERY">%1$s</xliff:g> hittades"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Sök efter fler appar"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Aviseringar"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tryck länge om du vill ta upp en genväg."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritfältet är fullt"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Applista"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Listan Personliga appar"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Listan Jobbappar"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startskärm"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ta bort"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Mapp: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Widgetar"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunder"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Inställningar för startsidan"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Startinställningar"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inaktiverat av administratören"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Översikt"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Tillåt rotering av startskärmen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"När mobilen vrids"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Rotering tillåts inte i de nuvarande skärminställningarna"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Aviseringsprickar"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"På"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Av"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Åtkomst till aviseringar krävs"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Aktivera appaviseringar för <xliff:g id="NAME">%1$s</xliff:g> om du vill att aviseringsprickar ska visas"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Ändra inställningar"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Visa aviseringsprickar"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Lägg till ikonen på startskärmen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"För nya appar"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ändra form på ikoner"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"på startskärmen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Använd systemstandard"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kvirkel"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laddas ned, <xliff:g id="PROGRESS">%2$s</xliff:g> klart"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> väntar på installation"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widgetar"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widgetlista"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widgetslistan har stängts"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Lägg till på startskärmen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Flytta objekt hit"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Objektet har lagts till på startskärmen"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Skapa mapp med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Mappen har skapats"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Flytta till startskärmen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Flytta skärmen till vänster"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Flytta skärmen till höger"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skärmen har flyttats"</string>
     <string name="action_resize" msgid="1802976324781771067">"Ändra storlek"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Öka bredden"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Öka höjden"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Minska höjden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetens storlek har ändrats till: bredd <xliff:g id="NUMBER_0">%1$s</xliff:g>, höjd <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Genvägar"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> genvägar för <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> har <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> genvägar och <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> aviseringar"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Genvägar och aviseringar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorera"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Aviseringen togs bort"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privat"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Arbete"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Här hittar du jobbappar"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Alla jobbappar har ett orange märke och organisationen ser till att de är skyddade. Flytta apparna till startskärmen så kommer du åt dem lättare."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Alla jobbappar har ett märke och organisationen ser till att de är skyddade. Flytta apparna till startskärmen så kommer du åt dem lättare."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Hanteras av organisationen"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Aviseringar och appar är inaktiverade"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Stäng"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Stängd"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 8925c89..faa40a7 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Haikupata programu zozote zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Tafuta programu zaidi"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Arifa"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Gusa na ushikilie ili uchague njia ya mkato."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Gusa mara mbili na ushikilie ili uchague njia ya mkato au utumie vitendo maalum."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Hakuna nafasi zaidi katika treya ya Vipendeleo"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Orodha ya programu"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Orodha ya programu za binafsi"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Orodha ya programu za kazini"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Mwanzo"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ondoa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
@@ -77,22 +81,22 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Folda: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Wijeti"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Mandhari"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Mipangilio ya ukurasa wa mwanzo"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Mipangilio ya mwanzo"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Imezimwa na msimamizi wako"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Muhtasari"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Ruhusu kuzungusha skrini ya Kwanza"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Simu inapozungushwa"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Mipangilio ya sasa ya sehemu ya Onyesho hairuhusu kuzungusha"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Vitone vya arifa"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Imewashwa"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Imezimwa"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Inahitaji idhini ya kufikia arifa"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Ili kuonyesha Vitone vya Arifa, washa kipengele cha arifa za programu katika <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Badilisha mipangilio"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Onyesha kitone cha arifa"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ongeza aikoni kwenye Skrini ya kwanza"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwa ajili ya programu mpya"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Badilisha umbo la aikoni"</string>
-    <string name="icon_shape_system_default" msgid="1709762974822753030">"Tumia umbo chaguo-msingi la mfumo"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"kwenye Skrini ya mwanzo"</string>
+    <string name="icon_shape_system_default" msgid="1709762974822753030">"Tumia umbo chaguomsingi la mfumo"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Mraba"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Mstatili wenye pembe duara"</string>
     <string name="icon_shape_circle" msgid="6550072265930144217">"Mduara"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> inapakuliwa, <xliff:g id="PROGRESS">%2$s</xliff:g> imekamilika"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> inasubiri kusakinisha"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Wijeti za <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Orodha ya wijeti"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Orodha ya wijeti imefungwa"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Ongeza kwenye skrini ya Kwanza"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Hamishia kipengee hapa"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Kipengee kimeongezwa kwenye skrini ya kwanza"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Unda folda ukitumia: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Folda imeundwa"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Hamishia Skrini ya kwanza"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Sogeza skrini kushoto"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Sogeza skrini kulia"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Skrini imesogezwa"</string>
     <string name="action_resize" msgid="1802976324781771067">"Badilisha ukubwa"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Ongeza upana"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Ongeza urefu"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Punguza urefu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Wijeti imepunguzwa hadi upana <xliff:g id="NUMBER_0">%1$s</xliff:g> urefu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Njia za mkato"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Njia <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> za mkato za <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Njia <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> za mkato na arifa <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> za <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Arifa na njia za mkato"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ondoa"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Arifa imeondolewa"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Binafsi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Wasifu wa kazini"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Pata programu za kazi hapa"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Kila programu ya kazi ina beji ya rangi ya machungwa na hulindwa na shirika lako. Hamishia programu kwenye skrini yako ya kwanza ili uzifikie kwa urahisi."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Kila programu ya kazi ina beji na hulindwa na shirika lako. Hamishia programu kwenye skrini yako ya kwanza ili uzifikie kwa urahisi."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Inasimamiwa na shirika lako"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Vipenge vya arifa na programu vimezimwa"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Funga"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Imefungwa"</string>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 1497b5a..b211207 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -15,9 +15,6 @@
 -->
 
 <resources>
-    <!-- Dynamic Grid -->
-    <dimen name="dynamic_grid_min_page_indicator_size">24dp</dimen>
-
     <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">8dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">64dp</dimen>
diff --git a/res/values-sw720dp/styles.xml b/res/values-sw720dp/styles.xml
index 72894dc..f322e9f 100644
--- a/res/values-sw720dp/styles.xml
+++ b/res/values-sw720dp/styles.xml
@@ -26,7 +26,6 @@
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
-        <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
     </style>
 
     <!-- Workspace -->
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index fc68b82..fedb0fd 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -40,13 +40,17 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"கூடுதல் பயன்பாடுகளைத் தேடு"</string>
     <string name="notifications_header" msgid="1404149926117359025">"அறிவிப்புகள்"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ஷார்ட்கட்டைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ஷார்ட்கட்டைச் சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் (அ) தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."</string>
     <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"பயன்பாடுகளின் பட்டியல்"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"தனிப்பட்ட ஆப்ஸ் பட்டியல்"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"பணி ஆப்ஸ் பட்டியல்"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"முகப்பு"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"அகற்று"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"ஆப்ஸ் தகவல்"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"பயன்பாட்டுத் தகவல்"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"வால்பேப்பர்கள்"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"முகப்பு அமைப்புகள்"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"உங்கள் நிர்வாகி முடக்கியுள்ளார்"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"மேலோட்டப் பார்வை"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"முகப்புத் திரை சுழற்சியை அனுமதி"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"மொபைலைச் சுழற்றும் போது"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"தற்போதைய திரை அமைப்பு சுழற்றுவதை அனுமதிக்கவில்லை"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"அறிவிப்புப் புள்ளிகள்"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ஆன்"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"முடக்கப்பட்டுள்ளது"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"அறிவிப்பிற்கான அணுகல் தேவை"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"அறிவிப்புப் புள்ளிகளைக் காட்ட, <xliff:g id="NAME">%1$s</xliff:g> இன் பயன்பாட்டு அறிவிப்புகளை இயக்கவும்"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"அமைப்புகளை மாற்று"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"அறிவிப்புப் புள்ளிகளைக் காட்டு"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"முகப்புத் திரையில் ஐகானைச் சேர்"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"புதிய பயன்பாடுகளுக்கு"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"ஐகான் வடிவத்தை மாற்று"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"முகப்புத் திரையில்"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"அமைப்பின் இயல்புநிலையைப் பயன்படுத்து"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"சதுரம்"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"சதுரவட்டம்"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> விட்ஜெட்டுகள்"</string>
+    <string name="widgets_list" msgid="796804551140113767">"விட்ஜெட்கள் பட்டியல்"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"விட்ஜெட்கள் பட்டியல் மூடப்பட்டது"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"முகப்புத் திரையில் சேர்"</string>
     <string name="action_move_here" msgid="2170188780612570250">"இங்கு நகர்த்து"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"இதனுடன் கோப்புறையை உருவாக்கும்: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"கோப்புறை உருவாக்கப்பட்டது"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"முகப்புத் திரைக்கு நகர்த்து"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"திரையை இடப்புறம் நகர்த்து"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"திரையை வலப்புறம் நகர்த்து"</string>
-    <string name="screen_moved" msgid="266230079505650577">"திரை நகர்த்தப்பட்டது"</string>
     <string name="action_resize" msgid="1802976324781771067">"அளவு மாற்று"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"அகலத்தை அதிகரி"</string>
     <string name="action_increase_height" msgid="459390020612501122">"உயரத்தை அதிகரி"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"உயரத்தைக் குறை"</string>
     <string name="widget_resized" msgid="9130327887929620">"அகலம் <xliff:g id="NUMBER_0">%1$s</xliff:g> மற்றும் உயரம் <xliff:g id="NUMBER_1">%2$s</xliff:g>க்கு விட்ஜெட் அளவு மாற்றப்பட்டது"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"குறுக்குவழிகள்"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>க்கான <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> குறுக்குவழிகள்"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> பயன்பாட்டிற்கான <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> குறுக்குவழிகளும் <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> அறிவிப்புகளும் உள்ளன"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ஷார்ட்கட்கள் மற்றும் அறிவிப்புகள்"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"நிராகரி"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"அறிவிப்பு நிராகரிக்கப்பட்டது"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"தனிப்பட்டவை"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"பணி"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"பணி விவரம்"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"பணி ஆப்ஸை இங்கு காணலாம்"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ஒவ்வொரு பணிப் பயன்பாடும் ஆரஞ்சு நிற பேட்ஜைக் கொண்டிருக்கும். இவை, உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ஒவ்வொரு பணிப் பயன்பாடும் ஒரு பேட்ஜைக் கொண்டிருக்கும். இவை, ஆப்ஸ் உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன என்பதைக் குறிக்கின்றன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"உங்கள் நிறுவனம் நிர்வகிக்கிறது"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"மூடுக"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"மூடப்பட்டது"</string>
 </resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index fb8a71b..3cc9761 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అప్లికేషన్‌లేవీ కనుగొనబడలేదు"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"మరిన్ని యాప్‌ల కోసం వెతుకు"</string>
     <string name="notifications_header" msgid="1404149926117359025">"నోటిఫికేషన్‌లు"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"షార్ట్‌కట్‌ని ఎంచుకోవడం కోసం నొక్కి, పట్టుకోండి."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"రెండుసార్లు నొక్కి, పట్టుకోవడం ద్వారా షార్ట్‌కట్‌ని ఎంచుకోండి లేదా అనుకూల చర్యలను ఉపయోగించండి."</string>
     <string name="out_of_space" msgid="4691004494942118364">"ఈ హోమ్ స్క్రీన్‌లో ఖాళీ లేదు."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"అనువర్తనాల జాబితా"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"వ్యక్తిగత యాప్‌ల జాబితా"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"కార్యాలయ యాప్‌ల జాబితా"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"హోమ్"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"తీసివేయి"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్‌స్టాల్ చేయి"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"వాల్‌పేపర్‌లు"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"హోమ్ సెట్టింగ్‌లు"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"మీ నిర్వాహకులు నిలిపివేసారు"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"స్థూలదృష్టి"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"హోమ్ స్క్రీన్ భ్రమణాన్ని అనుమతించండి"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ఫోన్‌‌ను తిప్పినప్పుడు"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"ప్రస్తుత డిస్‌ప్లే సెట్టింగ్ భ్రమణాన్ని అనుమతించలేదు"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"నోటిఫికేషన్ డాట్‌లు"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"ఆన్"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ఆఫ్"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"నోటిఫికేషన్ యాక్సెస్ అవసరం"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"నోటిఫికేషన్ డాట్‌లను చూపించడానికి <xliff:g id="NAME">%1$s</xliff:g>కు యాప్ నోటిఫికేషన్‌లను ఆన్ చేయండి"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"సెట్టింగ్‌లను మార్చు"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"నోటిఫికేషన్ డాట్‌లను చూపుతుంది"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"హోమ్ స్క్రీన్‌కి చిహ్నాన్ని జోడించు"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"కొత్త యాప్‌ల కోసం"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"చిహ్న ఆకారాన్ని మార్చు"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"హోమ్ స్క్రీన్‌పై"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"సిస్టమ్ డిఫాల్ట్‌ను ఉపయోగించండి"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"చతురస్రం"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"చతురస్రాకార వృత్తం"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్‌లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్‌స్టాల్ కావడానికి వేచి ఉంది"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> విడ్జెట్‌లు"</string>
+    <string name="widgets_list" msgid="796804551140113767">"విడ్జెట్‌ల జాబితా"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"విడ్జెట్‌ల జాబితా మూసివేయబడింది"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"హోమ్ స్క్రీన్‌కు జోడించు"</string>
     <string name="action_move_here" msgid="2170188780612570250">"అంశాన్ని ఇక్కడికి తరలించు"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"అంశం హోమ్‌స్క్రీన్‌కి జోడించబడింది"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"ఈ పేరుతో ఫోల్డర్‌ను సృష్టించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"ఫోల్డర్ సృష్టించబడింది"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"హోమ్‌స్క్రీన్‌కు తరలించు"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"స్క్రీన్‌ను ఎడమవైపుకి జరుపు"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"స్క్రీన్‌ను కుడివైపుకి జరుపు"</string>
-    <string name="screen_moved" msgid="266230079505650577">"స్క్రీన్ జరపబడింది"</string>
     <string name="action_resize" msgid="1802976324781771067">"పరిమాణం మార్చు"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"వెడల్పును పెంచు"</string>
     <string name="action_increase_height" msgid="459390020612501122">"ఎత్తును పెంచు"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ఎత్తును తగ్గించు"</string>
     <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ పరిమాణం వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"సత్వరమార్గాలు"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> కోసం <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> సత్వరమార్గాలు"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> కోసం <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> సత్వరమార్గాలు మరియు <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> నోటిఫికేషన్‌లు"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"షార్ట్‌కట్‌లు మరియు నోటిఫికేషన్‌లు"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"తీసివేయి"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"నోటిఫికేషన్ తీసివేయబడింది"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"వ్యక్తిగతం"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"కార్యాలయం"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"కార్యాలయ యాప్‌లను ఇక్కడ కనుగొనండి"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ప్రతి కార్యాలయ యాప్‌కు నారింజ బ్యాడ్జ్‌ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్‌లను మీ హోమ్ స్క్రీన్‌కి తరలించండి."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ప్రతి కార్యాలయ యాప్‌కు బ్యాడ్జ్‌ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్‌లను మీ హోమ్ స్క్రీన్‌కి తరలించండి."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"మీ సంస్థ ద్వారా నిర్వహించబడతాయి"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"నోటిఫికేషన్‌లు మరియు యాప్‌లు ఆఫ్ చేయబడ్డాయి"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"మూసివేయి"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"మూసివేయబడింది"</string>
 </resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 6f2bc71..2da32de 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"ค้นหาแอปเพิ่มเติม"</string>
     <string name="notifications_header" msgid="1404149926117359025">"การแจ้งเตือน"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"แตะค้างไว้เพื่อเลือกทางลัด"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ไม่มีที่ว่างในหน้าจอหลักนี้"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ไม่มีพื้นที่เหลือในถาดรายการโปรด"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"รายชื่อแอป"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"รายการแอปส่วนตัว"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"รายการแอปสำหรับทำงาน"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"หน้าแรก"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"นำออก"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"วอลเปเปอร์"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"การตั้งค่าหน้าแรก"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ปิดใช้โดยผู้ดูแลระบบ"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"ภาพรวม"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"อนุญาตให้หมุนหน้าจอหลัก"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"เมื่อหมุนโทรศัพท์"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"การตั้งค่าการแสดงผลปัจจุบันไม่อนุญาตให้มีการหมุน"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"จุดแจ้งเตือน"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"เปิด"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"ปิด"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"ต้องได้รับสิทธิ์เข้าถึงการแจ้งเตือน"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"เปิดการแจ้งเตือนแอปของ <xliff:g id="NAME">%1$s</xliff:g> เพื่อแสดงจุดแจ้งเตือน"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"เปลี่ยนการตั้งค่า"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"แสดงจุดแจ้งเตือน"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"เพิ่มไอคอนในหน้าจอหลัก"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"สำหรับแอปใหม่"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"เปลี่ยนรูปร่างไอคอน"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ในหน้าจอหลัก"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"ใช้ค่าเริ่มต้นของระบบ"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"สี่เหลี่ยมจัตุรัส"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"สี่เหลี่ยมขอบมน"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"กำลังดาวน์โหลด <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> กำลังรอติดตั้ง"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"วิดเจ็ตของ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"รายการวิดเจ็ต"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ปิดรายการวิดเจ็ตแล้ว"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าแรก"</string>
     <string name="action_move_here" msgid="2170188780612570250">"ย้ายรายการมาที่นี่"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"เพิ่มรายการไปยังหน้าจอหลักแล้ว"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"สร้างโฟลเดอร์ด้วย: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"สร้างโฟลเดอร์แล้ว"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ย้ายไปที่หน้าจอหลัก"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"เลื่อนหน้าจอไปทางซ้าย"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"เลื่อนหน้าจอไปทางขวา"</string>
-    <string name="screen_moved" msgid="266230079505650577">"ย้ายหน้าจอแล้ว"</string>
     <string name="action_resize" msgid="1802976324781771067">"ปรับขนาด"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"เพิ่มความกว้าง"</string>
     <string name="action_increase_height" msgid="459390020612501122">"เพิ่มความสูง"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ลดความสูง"</string>
     <string name="widget_resized" msgid="9130327887929620">"ปรับขนาดของวิดเจ็ตเป็นกว้าง <xliff:g id="NUMBER_0">%1$s</xliff:g> สูง <xliff:g id="NUMBER_1">%2$s</xliff:g> แล้ว"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ทางลัด"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ทางลัดสำหรับ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"ทางลัด <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> รายการและการแจ้งเตือน <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> รายการสำหรับ <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ทางลัดและการแจ้งเตือน"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ปิด"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"ปิดการแจ้งเตือนแล้ว"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ส่วนตัว"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"งาน"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"โปรไฟล์งาน"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"หาแอปงานที่นี่"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"แอปงานแต่ละแอปมีป้ายสีส้มและได้รับการรักษาความปลอดภัยจากองค์กรของคุณ ย้ายแอปไปยังหน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"แอปงานแต่ละแอปมีป้ายและได้รับการรักษาความปลอดภัยจากองค์กรของคุณ ย้ายแอปไปยังหน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"จัดการโดยองค์กร"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"ปิดการแจ้งเตือนและแอปอยู่"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"ปิด"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"ปิด"</string>
 </resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 5aad29a..68d5259 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Walang nahanap na app na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Maghanap ng higit pang mga app"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Mga Notification"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Pindutin nang matagal para kumuha ng shortcut."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"I-double tap nang matagal para kumuha ng shortcut o gumamit ng mga custom na pagkilos."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Wala nang lugar sa Home screen na ito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Wala nang lugar sa tray ng Mga Paborito"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Listahan ng mga app"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Listahan ng mga personal na app"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Listahan ng mga app sa trabaho"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alisin"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"I-uninstall"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Mga Wallpaper"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Mga setting ng Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Na-disable ng iyong admin"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Pangkalahatang-ideya"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Payagan ang pag-rotate ng Home screen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Kailan maro-rotate ang telepono"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Hindi pinahihintulutan ng kasalukuyang setting ng Display ang pag-rotate"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Mga notification dot"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Naka-on"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Naka-off"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Kinakailangan ng access sa notification"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Baguhin ang mga setting"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Ipakita ang mga notification dot"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Idagdag ang icon sa Home screen"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para sa mga bagong app"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Baguhin ang hugis ng icon"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"sa Home screen"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Gamitin ang default ng system"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Parisukat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Dina-download na ang <xliff:g id="NAME">%1$s</xliff:g>, tapos na ang <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Hinihintay nang mag-install ang <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Mga widget ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Listahan ng mga widget"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Nakasara ang listahan ng mga widget"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Idagdag sa Home screen"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Ilipat ang item dito"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Naidagdag sa home screen ang item"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Gumawa ng folder na may: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Nagawa ang folder"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Ilipat sa Home screen"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Ilipat sa kaliwa ang screen"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Ilipat sa kanan ang screen"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Nailipat ang screen"</string>
     <string name="action_resize" msgid="1802976324781771067">"I-resize"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Dagdagan ang lapad"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Dagdagan ang taas"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Bawasan ang taas"</string>
     <string name="widget_resized" msgid="9130327887929620">"Na-resize ang widget sa lapad <xliff:g id="NUMBER_0">%1$s</xliff:g> taas <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Mga Shortcut"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> (na) shortcut para sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> (na) shortcut at <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> (na) notification para sa <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Mga shortcut at notification"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"I-dismiss"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Na-dismiss ang notification"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabaho"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profile sa trabaho"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Maghanap ng mga app para sa trabaho rito"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Ang bawat app para sa trabaho ay may orange na badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Ang bawat app para sa trabaho ay may badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Pinamamahalaan ng iyong organisasyon"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Naka-off ang mga notification at app"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Isara"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Nakasara"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index a0ebe6f0..af121f2 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Başka uygulamalar ara"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Bildirimler"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Kısayol seçmek için dokunun ve basılı tutun."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Bu Ana ekranda yer kalmadı."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoriler tepsisinde başka yer kalmadı"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Uygulamalar listesi"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Kişisel uygulamalar listesi"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"İş uygulamaları listesi"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ana ekran"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Kaldır"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Yüklemeyi kaldır"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Duvar Kağıtları"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Ana ekran ayarları"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Yöneticiniz tarafından devre dışı bırakıldı"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Genel bakış"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Ana ekranı döndürmeye izin ver"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon döndürüldüğünde"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Mevcut Ekran ayarı, döndürmeye izin vermiyor"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Bildirim noktaları"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Açık"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kapalı"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirim erişimi gerekli"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirim Noktaları\'nı göstermek için <xliff:g id="NAME">%1$s</xliff:g> uygulamasının bildirimlerini açın"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Ayarları değiştir"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Bildirim noktalarını göster"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Ana ekrana simge ekle"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yeni uygulamalar için"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Simge şeklini değiştir"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Ana ekranda"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sistem varsayılanını kullan"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kare"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Kare-daire"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> indiriliyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> uygulaması yüklenmek için bekliyor"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> widget\'ları"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Widget listesi"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Widget listesi kapalı"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Ana ekrana ekle"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Öğeyi buraya taşı"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Öğe ana ekrana eklendi"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Şu öğeyle klasör oluştur: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Klasör oluşturuldu"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Ana ekrana taşı"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranı sola taşı"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranı sağa taşı"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran taşındı"</string>
     <string name="action_resize" msgid="1802976324781771067">"Yeniden boyutlandır"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Genişliği artır"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Yüksekliği artır"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Yüksekliği azalt"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget, <xliff:g id="NUMBER_0">%1$s</xliff:g> genişlik ve <xliff:g id="NUMBER_1">%2$s</xliff:g> yükseklik değerine yeniden boyutlandırıldı"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Kısayollar"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> için <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> kısayol"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> için <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> kısayol ve <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> bildirim"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Kısayollar ve bildirimler"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Kapat"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Bildirim kapatıldı"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Kişisel"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"İş uygulamalarını burada bulabilirsiniz"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Her iş uygulamasında, uygulama güvenliğinin kuruluşunuz tarafından sağlandığını gösteren turuncu bir rozet bulunur. Uygulamaları daha kolay erişim için Ana ekranınıza taşıyın."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Her iş uygulamasında, uygulama güvenliğinin kuruluşunuz tarafından sağlandığını gösteren bir rozet bulunur. Daha kolay erişim için uygulamaları Ana ekranınıza taşıyın."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Kuruluşunuz tarafından yönetiliyor"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Bildirimler ve uygulamalar kapalı"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Kapat"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Kapalı"</string>
 </resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index ffced57..305c9aa 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Шукати ще додатки"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Сповіщення"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Натисніть і втримуйте, щоб вибрати ярлик."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Двічі натисніть і втримуйте, щоб вибрати ярлик, або виконайте іншу дію."</string>
     <string name="out_of_space" msgid="4691004494942118364">"На цьому головному екрані більше немає місця."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В області \"Вибране\" немає місця"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Список додатків"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Список особистих додатків"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Список робочих додатків"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Головний екран"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Видалити"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Видалити"</string>
@@ -79,19 +83,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Фонові малюнки"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Налаштування Home"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Вимкнув адміністратор"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Огляд"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Дозволити обертання головного екрана"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Коли телефон обертається"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Поточні налаштування дисплея не підтримують обертання"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Значки сповіщень"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Увімкнено"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Вимкнено"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Потрібен доступ до сповіщень"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Щоб показувати значки сповіщень, увімкніть сповіщення в додатку <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Змінити налаштування"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Показувати значки сповіщень"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Додати значок на головний екран"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Для нових додатків"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Змінити форму значка"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"на головному екрані"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Використовувати налаштування системи за умовчанням"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Квадрат"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Квадрат із заокругленими кутами"</string>
@@ -106,6 +110,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> завантажується, <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> очікує на завантаження"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Віджети додатка <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Список віджетів"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Список віджектів закрито"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Додати на головний екран"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Перемістити елемент сюди"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Елемент додано на головний екран"</string>
@@ -121,9 +127,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Створити папку з: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Папку створено"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Перемістити на головний екран"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Перемістити екран ліворуч"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Перемістити екран праворуч"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Екран переміщено"</string>
     <string name="action_resize" msgid="1802976324781771067">"Змінити розміри"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Збільшити ширину"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Збільшити висоту"</string>
@@ -131,15 +134,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Зменшити висоту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Розміри віджета змінено на <xliff:g id="NUMBER_0">%1$s</xliff:g> завширшки та <xliff:g id="NUMBER_1">%2$s</xliff:g> заввишки"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлики"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"Ярликів для додатка <xliff:g id="APP_NAME">%2$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"Ярлики (<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g>) і сповіщення (<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g>) додатка <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлики та сповіщення"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Закрити"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Сповіщення закрито"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Особисті додатки"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Робочі додатки"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Робочий профіль"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Робочі додатки містяться тут"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Кожний робочий додаток має оранжевий значок. Його захищає організація. Для швидкого доступу перенесіть додатки на головний екран."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Кожний робочий додаток має значок і перебуває під захистом організації. Перенесіть додатки на головний екран, щоб швидко запускати їх."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Профілем керує ваша організація"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Сповіщення та додатки вимкнено"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Закрити"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Закрито"</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index cd65738..c06c943 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" سے مماثل کوئی ایپس نہیں ملیں"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"مزید ایپس تلاش کریں"</string>
     <string name="notifications_header" msgid="1404149926117359025">"اطلاعات"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"ایک شارٹ کٹ منتخب کرنے کیلئے ٹچ کر کے دبائے رکھیں۔"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"ایک شارٹ کٹ منتخب کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"</string>
     <string name="out_of_space" msgid="4691004494942118364">"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"ایپس کی فہرست"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"ذاتی ایپس کی فہرست"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"دفتری ایپس کی فہرست"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ہوم"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ہٹائیں"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"اَن انسٹال کریں"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"وال پیپرز"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ہوم ترتیبات"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"آپ کے منتظم کی طرف سے غیر فعال کر دیا گیا"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"مجموعی جائزہ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ہوم اسکرین گھمانے کی اجازت دیں"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"جب فون گھمایا جاتا ہے"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"موجودہ ڈسپلے ترتیب گھمانے کی اجازت نہیں دیتی"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"اطلاعاتی ڈاٹس"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"آن"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"آف"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"اطلاعاتی رسائی درکار ہے"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"اطلاعاتی ڈاٹس دکھانے کی خاطر <xliff:g id="NAME">%1$s</xliff:g> کیلئے ایپ کی اطلاعات آن کریں"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ترتیبات تبدیل کریں"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"اطلاعاتی ڈاٹس دکھائیں"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"آئیکن کو ہوم اسکرین میں شامل کریں"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"نئی ایپس کیلئے"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"آئیکن کی شکل تبدیل کریں"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"ہوم اسکرین پر"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"سسٹم ڈیفالٹ کا استعمال کریں"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"مربع"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"اسکورکل"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> ویجیٹس"</string>
+    <string name="widgets_list" msgid="796804551140113767">"ویجیٹس کی فہرست"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"ویجیٹس کی فہرست بند کر دی گئی"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"ہوم اسکرین میں شامل کریں"</string>
     <string name="action_move_here" msgid="2170188780612570250">"آئٹم یہاں منتقل کریں"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"آئٹم کو ہوم اسکرین میں شامل کر دیا گیا"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"اس کے ساتھ فولڈر بنائیں: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"فولڈر بنا دیا گیا"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"ہوم اسکرین میں منتقل کریں"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"اسکرین کو بائیں منتقل کریں"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"اسکرین کو دائیں منتقل کریں"</string>
-    <string name="screen_moved" msgid="266230079505650577">"اسکرین منتقل کر دی گئی"</string>
     <string name="action_resize" msgid="1802976324781771067">"سائز تبدیل کریں"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"چوڑائی بڑھائیں"</string>
     <string name="action_increase_height" msgid="459390020612501122">"اونچائی بڑھائیں"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"اونچائی کم کریں"</string>
     <string name="widget_resized" msgid="9130327887929620">"ویجیٹ کے سائز کو چوڑائی <xliff:g id="NUMBER_0">%1$s</xliff:g> اونچائی <xliff:g id="NUMBER_1">%2$s</xliff:g> میں تبدیل کر دیا گیا"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"شارٹ کٹس"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> کیلئے <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> شارٹ کٹس"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> کے <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> شارٹ کٹس اور <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> اطلاعات"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"شارٹ کٹس اور اطلاعات"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"برخاست کریں"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"اطلاع مسترد ہو گئی"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ذاتی"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"یہاں دفتری ایپس تلاش کریں"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"ہر دفتری ایپ میں نارنجی بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"ہر دفتری ایپ میں ایک بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"آپ کی تنظیم کے زیر انتظام"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"اطلاعات اور ایپس آف ہیں"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"بند کریں"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"بند"</string>
 </resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 200c2c0..287ec09 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"“<xliff:g id="QUERY">%1$s</xliff:g>” bilan mos hech qanday ilova topilmadi"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Boshqa ilovalarni qidirish"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Bildirishnomalar"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Yorliqni tanlab olish uchun bosib turing."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Uy ekranida bitta ham xona yo‘q."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Ilovalar ro‘yxati"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Shaxsiy ilovalar ro‘yxati"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Ishchi ilovalar ro‘yxati"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Bosh sahifa"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Olib tashlash"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Jild: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Vidjetlar"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fon rasmlari"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Home sozlamalari"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Bosh ekran sozlamalari"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator tomonidan o‘chirilgan"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Umumiy ko‘rinish"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Asosiy ekranni aylantirishga ruxsat berish"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefon burilganda"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Ekran sozlamalariga ko‘ra uni aylantirib bo‘lmaydi"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Bildirishnoma belgilari"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Yoniq"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"O‘chiq"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Bildirishnomalarga ruxsat berilmagan"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Bildirishnoma belgilarini ko‘rsatish uchun <xliff:g id="NAME">%1$s</xliff:g> ilovasida bildirishnomalarni yoqing"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Sozlamalarni o‘zgartirish"</string>
-    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Bosh ekranga ikonka qo‘shish"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Bildirishnoma belgilarini ko‘rsatish"</string>
+    <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Bosh ekranga ikonka chiqarish"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Yangi o‘rnatilgan ilovalar ikonkasini bosh ekranga chiqarish"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Ikonka shaklini o‘zgartirish"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"Bosh ekranda"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Standart tizim parametrlaridan foydalanish"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Kvadrat"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Qirralari aylana kvadrat"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> yuklab olinmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> bajarildi"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi o‘rnatilishi kutilmoqda"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> vidjetlari"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Vidjetlar ro‘yxati"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Vidjetlar ro‘yxati yopildi"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Bosh ekranga qo‘shish"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Obyektni bu yerga ko‘chirish"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Obyekt bosh ekranga qo‘shildi"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g> bilan jild yaratish"</string>
     <string name="folder_created" msgid="6409794597405184510">"Jild yaratildi"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Bosh ekranga ko‘chirish"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranni chapga siljitish"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranni o‘ngga siljitish"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Ekran siljitildi"</string>
     <string name="action_resize" msgid="1802976324781771067">"O‘lchamini o‘zgartirish"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Enini uzaytirish"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Bo‘yini uzaytirish"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Bo‘yini kichraytirish"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidjetning eni <xliff:g id="NUMBER_0">%1$s</xliff:g>, bo‘yi <xliff:g id="NUMBER_1">%2$s</xliff:g> qilib o‘zgartirildi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Tezkor tugmalar"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g> ilovasi uchun <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ta tezkor tugma"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g> ilovasi uchun <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> ta yorliq va <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ta bildirishnoma"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Yorliqlar va bildirishnomalar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Yopish"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Bildirishnoma yopildi"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Shaxsiy"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Ishchi"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ishchi profil"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Ishga oid ilovalarni shu yerdan topish mumkin"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Apelsinrangli nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Tashkilotingiz tomonidan boshqariladi"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Bildirishnomalar va ilovalar faol emas"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Yopish"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Yopiq"</string>
 </resources>
diff --git a/res/values-v26/styles.xml b/res/values-v26/styles.xml
index b25f46a..e810ab2 100644
--- a/res/values-v26/styles.xml
+++ b/res/values-v26/styles.xml
@@ -21,7 +21,7 @@
     <style name="WidgetContainerTheme" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
     </style>
-    <style name="WidgetContainerTheme.Dark" parent="LauncherThemeDark">
+    <style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
         <item name="android:colorPrimaryDark">#616161</item> <!-- Gray 700 -->
     </style>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index a5b4892..06278f5 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Tìm kiếm thêm ứng dụng"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Thông báo"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Chạm và giữ để chọn lối tắt."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Không còn chỗ trên Màn hình chính này."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Không còn chỗ trong khay Mục yêu thích"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Danh sách ứng dụng"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Danh sách ứng dụng cá nhân"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Danh sách ứng dụng công việc"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Màn hình chính"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Xóa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Gỡ cài đặt"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"Thư mục: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"Tiện ích con"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Hình nền"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Cài đặt trang chủ"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Cài đặt màn hình chính"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Bị tắt bởi quản trị viên của bạn"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Tổng quan"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Cho phép xoay Màn hình chính"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Khi xoay điện thoại"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Cài đặt Hiển thị hiện tại không cho phép xoay"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Dấu chấm thông báo"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Đang bật"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Đã tắt"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Cần quyền truy cập thông báo"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Để hiển thị Dấu chấm thông báo, hãy bật thông báo ứng dụng cho <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Thay đổi cài đặt"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Hiển thị dấu chấm thông báo"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Thêm biểu tượng vào màn hình chính"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Cho ứng dụng mới"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Thay đổi hình dạng biểu tượng"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"trên Màn hình chính"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sử dụng mặc định của hệ thống"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Hình vuông"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"Hình vuông cạnh bo tròn"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"Đang tải xuống <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> hoàn tất"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Đang chờ cài đặt <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"Tiện ích của <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Danh sách tiện ích"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Đã đóng danh sách tiện ích"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Thêm vào màn hình chính"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Di chuyển mục vào đây"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Đã thêm mục vào màn hình chính"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Tạo thư mục bằng: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Đã tạo thư mục"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Di chuyển đến màn hình chính"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Di chuyển màn hình sang trái"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Di chuyển màn hình sang phải"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Đã di chuyển màn hình"</string>
     <string name="action_resize" msgid="1802976324781771067">"Đổi kích thước"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Tăng chiều rộng"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Tăng chiều cao"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Giảm chiều cao"</string>
     <string name="widget_resized" msgid="9130327887929620">"Đã đổi kích thước tiện ích thành chiều rộng <xliff:g id="NUMBER_0">%1$s</xliff:g> chiều cao <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Lối tắt"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> phím tắt cho <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> phím tắt và <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> thông báo cho <xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Phím tắt và thông báo"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Loại bỏ"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Đã loại bỏ thông báo"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Cá nhân"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Cơ quan"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Hồ sơ công việc"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Tìm ứng dụng công việc tại đây"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Mỗi ứng dụng công việc đều có một huy hiệu màu cam và được tổ chức của bạn bảo mật. Bạn có thể di chuyển ứng dụng đến Màn hình chính để truy cập dễ dàng hơn."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Mỗi ứng dụng công việc đều có một huy hiệu và được tổ chức của bạn bảo mật. Bạn có thể di chuyển ứng dụng đến Màn hình chính để truy cập dễ dàng hơn."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Do tổ chức của bạn quản lý"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Thông báo và ứng dụng đang tắt"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Đóng"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Đã đóng"</string>
 </resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 71e06e7..640aa0e 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜索更多应用"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"触摸并按住快捷方式即可选择快捷方式。"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"</string>
     <string name="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"收藏栏已满"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"应用列表"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"个人应用列表"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"工作应用列表"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主屏幕"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"卸载"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"壁纸"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"主屏幕设置"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"已被您的管理员停用"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"概览"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"允许旋转主屏幕"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"手机旋转时"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"当前的显示设置不允许旋转设备"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"通知圆点"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"开启"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"关闭"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"需要获取通知使用权"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"要显示通知圆点,请开启<xliff:g id="NAME">%1$s</xliff:g>的应用通知功能"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"更改设置"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"显示通知圆点"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"将图标添加到主屏幕"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"适用于新应用"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"更改图标形状"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"在主屏幕上"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系统默认设置"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圆形"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下载<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>正在等待安装"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>微件"</string>
+    <string name="widgets_list" msgid="796804551140113767">"微件列表"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"微件列表已关闭"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"添加到主屏幕"</string>
     <string name="action_move_here" msgid="2170188780612570250">"将项目移至此处"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"已将项目添加到主屏幕"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"创建“<xliff:g id="NAME">%1$s</xliff:g>”文件夹"</string>
     <string name="folder_created" msgid="6409794597405184510">"文件夹已创建"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"移至主屏幕"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"将屏幕向左移动"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"将屏幕向右移动"</string>
-    <string name="screen_moved" msgid="266230079505650577">"屏幕已移动"</string>
     <string name="action_resize" msgid="1802976324781771067">"调整大小"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"增加宽度"</string>
     <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"减小高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"微件尺寸已调整为:宽度 <xliff:g id="NUMBER_0">%1$s</xliff:g>,高度 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"快捷方式"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>有 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 个快捷方式"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>的 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 个快捷方式和 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 条通知"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"快捷方式和通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"关闭"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"已关闭通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"个人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作资料"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"请在此处查找工作应用"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每个工作应用均有一个橙色徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"每个工作应用均有一个徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"由贵单位管理"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"通知和应用均已关闭"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"关闭"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已关闭"</string>
 </resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 7f792f8..2677b21 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"找不到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"按住捷徑即可選取。"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"連㩒兩下之後繼續㩒住,就可以揀選捷徑或者用自訂嘅操作。"</string>
     <string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"我的收藏寄存區沒有足夠空間"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"應用程式清單"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"個人應用程式清單"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"工作應用程式清單"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主畫面"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
@@ -75,21 +79,21 @@
     <string name="folder_name_format" msgid="6629239338071103179">"資料夾:<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widget_button_text" msgid="2880537293434387943">"小工具"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Home 設定"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"主螢幕設定"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"已由您的管理員停用"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"概覽"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"允許主畫面旋轉"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"當手機旋轉時"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"「目前顯示屏」設定不允許旋轉"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"通知圓點"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"開啟"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"關閉"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"需要獲取通知存取權"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"如要顯示「通知圓點」,請開啟「<xliff:g id="NAME">%1$s</xliff:g>」的應用程式通知功能"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"變更設定"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"顯示通知圓點"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主畫面"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"在主畫面上"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系統預設設定"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"正方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圓形"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載 <xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝 <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g>小工具"</string>
+    <string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"已經關閉嘅小工具清單"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"新增至主畫面"</string>
     <string name="action_move_here" msgid="2170188780612570250">"移動項目至這裡"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目加入至主畫面"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"使用以下項目建立資料夾:<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"已建立資料夾"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"移動至主畫面"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"向左移動螢幕"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"向右移動螢幕"</string>
-    <string name="screen_moved" msgid="266230079505650577">"已移動螢幕"</string>
     <string name="action_resize" msgid="1802976324781771067">"重新調整大小"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"增加闊度"</string>
     <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"已調整小工具的大小至闊 <xliff:g id="NUMBER_0">%1$s</xliff:g> 高 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"捷徑"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」嘅 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個捷徑"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"「<xliff:g id="APP_NAME">%3$s</xliff:g>」嘅 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個捷徑同 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 個通知"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"捷徑同通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"關閉"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"關閉咗通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"商務"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作設定檔"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"請在此處尋找工作應用程式"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每個工作應用程式都有橙色徽章,並由您的機構負責保持安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"每個工作應用程式都有一個徽章,並由您的機構負責保持安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"由您的機構管理"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"通知和應用程式已關閉"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"關閉"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已關閉"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b95e838..4d37cdd 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"找不到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
     <string name="notifications_header" msgid="1404149926117359025">"通知"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"按住捷徑即可選取。"</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"</string>
     <string name="out_of_space" msgid="4691004494942118364">"這個主螢幕已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"「我的最愛」匣已無可用空間"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"應用程式清單"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"個人應用程式清單"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"辦公應用程式清單"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主螢幕"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Home 設定"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"已由你的管理員停用"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"總覽"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"允許旋轉主螢幕"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"當手機旋轉時"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"目前的顯示設定不允許旋轉畫面"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"通知圓點"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"已啟用"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"已停用"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"需要取得通知存取權"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"如要顯示通知圓點,請開啟「<xliff:g id="NAME">%1$s</xliff:g>」的應用程式通知功能"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"變更設定"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"顯示通知圓點"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"將圖示加到主螢幕"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"適用於新安裝的應用程式"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"變更圖示形狀"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"在主螢幕上"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"使用系統預設值"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"正方形"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"方圓形"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載「<xliff:g id="NAME">%1$s</xliff:g>」,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"「<xliff:g id="NAME">%1$s</xliff:g>」小工具"</string>
+    <string name="widgets_list" msgid="796804551140113767">"小工具清單"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"已關閉小工具清單"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"新增至主畫面"</string>
     <string name="action_move_here" msgid="2170188780612570250">"將項目移至這裡"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目新增到主畫面"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"建立「<xliff:g id="NAME">%1$s</xliff:g>」資料夾"</string>
     <string name="folder_created" msgid="6409794597405184510">"已建立資料夾"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"移至主畫面"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"將畫面往左移"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"將畫面往右移"</string>
-    <string name="screen_moved" msgid="266230079505650577">"已移動畫面"</string>
     <string name="action_resize" msgid="1802976324781771067">"調整大小"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"增加寬度"</string>
     <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"已將小工具的寬度和高度分別調整為 <xliff:g id="NUMBER_0">%1$s</xliff:g> 和 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"捷徑"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」有 <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個捷徑"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個捷徑和 <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 則「<xliff:g id="APP_NAME">%3$s</xliff:g>」通知"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"捷徑和通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"關閉"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"已關閉通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"公司"</string>
-    <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work 設定檔"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作資料夾"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"在這裡尋找辦公應用程式"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"每個辦公應用程式都有橘色徽章,並由貴機構負責管理及確保其安全。請將辦公應用程式移至主螢幕以便輕鬆存取。"</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"每個辦公應用程式都有徽章,並由貴機構負責管理及確保其安全。請將辦公應用程式移至主螢幕以便輕鬆存取。"</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"由貴機構所管理"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"已關閉通知和應用程式"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"關閉"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"已關閉"</string>
 </resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 65d7d4c..8e3e5ab 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -40,9 +40,13 @@
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="all_apps_search_market_message" msgid="1366263386197059176">"Sesha izinhlelo zokusebenza eziningi"</string>
     <string name="notifications_header" msgid="1404149926117359025">"Izaziso"</string>
+    <string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Thinta futhi ubambe ukuze ukhethe isinqamuleli."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Thepha kabili uphinde ubambe ukuze uphakamise isinqamuleli noma usebenzise izenzo zangokwezifiso."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Asisekho isikhala kulesi sikrini Sasekhaya."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Asisekho isikhala kwitreyi lezintandokazi"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Uhlu lwezinhlelo zokusebenza"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Uhlu lwezinhlelo zokusebenza zomuntu siqu"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Uhlu lwezinhlelo zokusebenza zomsebenzi"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ikhaya"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Susa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Khipha"</string>
@@ -77,19 +81,19 @@
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Izithombe zangemuva"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Izilungiselelo zasekhaya"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Kukhutshazwe umlawuli wakho"</string>
-    <string name="accessibility_action_overview" msgid="6257665857640347026">"Ukubuka konke"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Vumela ukuphendukiswa kwesikrini sasekhaya"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Uma ifoni iphendukiswa"</string>
-    <string name="allow_rotation_blocked_desc" msgid="3212602545192996253">"Isilungiselelo sesiboniso samanje asivumeli ukuzungezisa"</string>
     <string name="icon_badging_title" msgid="874121399231955394">"Amachashazi esaziso"</string>
     <string name="icon_badging_desc_on" msgid="2627952638544674079">"Kuvuliwe"</string>
     <string name="icon_badging_desc_off" msgid="5503319969924580241">"Kuvaliwe"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Ukufinyelela izaziso kuyadingeka"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Shintsha izilungiselelo"</string>
+    <string name="icon_badging_service_title" msgid="2309733118428242174">"Bonisa amacashazi esaziso"</string>
     <string name="auto_add_shortcuts_label" msgid="8222286205987725611">"Engeza isithonjana eskrinini sasekhaya"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Kwezinhlelo zokusebenza ezintsha"</string>
     <string name="icon_shape_override_label" msgid="2977264953998281004">"Shintsha isimo sesithonjana"</string>
+    <string name="icon_shape_override_label_location" msgid="3841607380657692863">"kusikrini sasekhaya"</string>
     <string name="icon_shape_system_default" msgid="1709762974822753030">"Sebenzisa okuzenzakalelayo kwesistimu"</string>
     <string name="icon_shape_square" msgid="633575066111622774">"Isikwele"</string>
     <string name="icon_shape_squircle" msgid="5658049910802669495">"I-Squircle"</string>
@@ -104,6 +108,8 @@
     <string name="app_downloading_title" msgid="8336702962104482644">"I-<xliff:g id="NAME">%1$s</xliff:g> iyalandwa, <xliff:g id="PROGRESS">%2$s</xliff:g> kuqediwe"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilinde ukufakwa"</string>
     <string name="widgets_bottom_sheet_title" msgid="2904559530954183366">"<xliff:g id="NAME">%1$s</xliff:g> amawijethi"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Uhlu lwamawijethi"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Uhlu lwamawijethi luvaliwe"</string>
     <string name="action_add_to_workspace" msgid="8902165848117513641">"Faka kusikrini sasekhaya"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Hambisa into lapha"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"Into ingezwe kusikrini sasekhaya"</string>
@@ -119,9 +125,6 @@
     <string name="create_folder_with" msgid="4050141361160214248">"Dala ifolda nge-: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_created" msgid="6409794597405184510">"Ifolda idaliwe"</string>
     <string name="action_move_to_workspace" msgid="1603837886334246317">"Hambisa kusikrini sasekhaya"</string>
-    <string name="action_move_screen_left" msgid="8854216831569401665">"Hambisa isikrini kwesokunxele"</string>
-    <string name="action_move_screen_right" msgid="329334910274311123">"Hambisa isikrini kwesokudla"</string>
-    <string name="screen_moved" msgid="266230079505650577">"Isikrini sihanjisiwe"</string>
     <string name="action_resize" msgid="1802976324781771067">"Shintsha usayizi"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Khuphula ububanzi"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Khuphula ubude"</string>
@@ -129,15 +132,16 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Nciphisa ubude"</string>
     <string name="widget_resized" msgid="9130327887929620">"Iwijethi inikezwe usayizi omusha ngobubanzi obungu-<xliff:g id="NUMBER_0">%1$s</xliff:g> ubude obungu-<xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Izinqamuleli"</string>
-    <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> izinqamuleli ze-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> izinqamuleli nezaziso ezingu-<xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> ze-<xliff:g id="APP_NAME">%3$s</xliff:g>"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Izinqamuleli nezaziso"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Cashisa"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"Isaziso sicashisiwe"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Okomuntu siqu"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Umsebenzi"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Iphrofayela yomsebenzi"</string>
     <string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"Thola izinhlelo zokusebenza lapha"</string>
-    <string name="bottom_work_tab_user_education_body" msgid="1485375451542813426">"Uhlo lokusebenza ngalunye lomsebenzi linebheji ewolintshi futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula."</string>
+    <string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"Uhlo lokusebenza ngalunye lomsebenzi linebheji futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula."</string>
     <string name="work_mode_on_label" msgid="4781128097185272916">"Kuphethwe inhlangano yakho"</string>
     <string name="work_mode_off_label" msgid="3194894777601421047">"Izaziso nezinhlelo zokusebenza kuvaliwe"</string>
+    <string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"Vala"</string>
+    <string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"Kuvaliwe"</string>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 1351dfa..30091a5 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -20,6 +20,7 @@
 
     <!-- Attributes used for launcher theme -->
     <attr name="allAppsScrimColor" format="color" />
+    <attr name="allAppsInterimScrimAlpha" format="integer" />
     <attr name="allAppsNavBarScrimColor" format="color" />
     <attr name="popupColorPrimary" format="color" />
     <attr name="popupColorSecondary" format="color" />
@@ -44,7 +45,6 @@
             <enum name="widget_section" value="3" />
             <enum name="shortcut_popup" value="4" />
         </attr>
-        <attr name="deferShadowGeneration" format="boolean" />
         <attr name="centerVertically" format="boolean" />
     </declare-styleable>
 
diff --git a/res/values/config.xml b/res/values/config.xml
index 065ad36..f462b9c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -18,6 +18,9 @@
     <!-- String representing the intent to delete a package.-->
     <string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;end</string>
 
+    <!-- String representing the fragment class for settings activity.-->
+    <string name="settings_fragment_name" translatable="false">com.android.launcher3.SettingsActivity$LauncherSettingsFragment</string>
+
     <!-- Values for icon shape overrides. These should correspond to entries defined
      in icon_shape_override_paths_names -->
     <string-array translatable="false" name="icon_shape_override_paths_values">
@@ -41,9 +44,6 @@
     <item type="id" name="drag_event_parity" />
 
 <!-- AllApps & Launcher transitions -->
-    <!-- The alpha of the AppsCustomize bg in spring loaded mode -->
-    <integer name="config_workspaceScrimAlpha">76</integer>
-
     <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
     <integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
 
@@ -95,9 +95,6 @@
     <!-- Name of an app transition manager class. -->
     <string name="app_transition_manager_class" translatable="false"></string>
 
-    <!-- Name of a color extraction implementation class. -->
-    <string name="color_extraction_impl_class" translatable="false"></string>
-
     <!-- Name of a subclass of com.android.launcher3.util.InstantAppResolver. Can be empty. -->
     <string name="instant_app_resolver_class" translatable="false"></string>
 
@@ -116,6 +113,13 @@
     <!-- View ID used by cell layout to jail its content -->
     <item type="id" name="cell_layout_jail_id" />
 
+    <!-- Tag id used for view scrim -->
+    <item type="id" name="view_scrim" />
+
+    <!-- View IDs to store item highlight information -->
+    <item type="id" name="view_unhighlight_background" />
+    <item type="id" name="view_highlighted" />
+
 <!-- Popup items -->
     <integer name="config_popupOpenCloseDuration">150</integer>
     <integer name="config_popupArrowOpenDuration">80</integer>
@@ -124,7 +128,7 @@
 <!-- Accessibility actions -->
     <item type="id" name="action_remove" />
     <item type="id" name="action_uninstall" />
-    <item type="id" name="action_info" />
+    <item type="id" name="action_reconfigure" />
     <item type="id" name="action_add_to_workspace" />
     <item type="id" name="action_move" />
     <item type="id" name="action_move_to_workspace" />
@@ -132,6 +136,7 @@
     <item type="id" name="action_move_screen_forwards" />
     <item type="id" name="action_resize" />
     <item type="id" name="action_deep_shortcuts" />
+    <item type="id" name="action_shortcuts_and_notifications"/>
     <item type="id" name="action_dismiss_notification" />
 
 <!-- QSB IDs. DO not change -->
@@ -140,7 +145,9 @@
     <item type="id" name="search_container_all_apps" />
 
 <!-- Recents -->
+    <item type="id" name="overview_panel"/>
     <integer name="config_recentsMaxThumbnailCacheSize">6</integer>
     <integer name="config_recentsMaxIconCacheSize">12</integer>
 
+    <item name="workspace_page_container" type="id" />
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 1f46844..3bb7a79 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,13 +20,8 @@
 
     <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">8dp</dimen>
-    <dimen name="dynamic_grid_min_page_indicator_size">24dp</dimen>
     <dimen name="dynamic_grid_page_indicator_line_height">1dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">8dp</dimen>
-    <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
-    <dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
-    <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
-    <dimen name="dynamic_grid_overview_bar_spacer_width">25dp</dimen>
     <dimen name="dynamic_grid_workspace_top_padding">8dp</dimen>
     <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
     <!-- Minimum space between workspace and hotseat in spring loaded mode -->
@@ -39,6 +34,8 @@
     <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_top_padding">8dp</dimen>
     <dimen name="dynamic_grid_hotseat_bottom_padding">2dp</dimen>
+    <!-- Extra bottom padding for non-tall devices. -->
+    <dimen name="dynamic_grid_hotseat_bottom_non_tall_padding">0dp</dimen>
     <dimen name="dynamic_grid_hotseat_size">80dp</dimen>
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
 
@@ -46,6 +43,8 @@
     <dimen name="all_apps_scrim_radius">8dp</dimen>
     <dimen name="all_apps_scrim_margin">8dp</dimen>
     <dimen name="all_apps_scrim_blur">4dp</dimen>
+    <dimen name="vertical_drag_handle_size">24dp</dimen>
+    <dimen name="vertical_drag_handle_overlap_workspace">0dp</dimen>
 
 <!-- Drop target bar -->
     <dimen name="dynamic_grid_drop_target_size">48dp</dimen>
@@ -79,7 +78,7 @@
     <!-- All Apps -->
     <dimen name="all_apps_button_scale_down">0dp</dimen>
     <dimen name="all_apps_search_bar_field_height">48dp</dimen>
-    <dimen name="all_apps_search_bar_height">60dp</dimen>
+    <dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
     <dimen name="all_apps_empty_search_bg_top_offset">144dp</dimen>
     <dimen name="all_apps_background_canvas_width">700dp</dimen>
@@ -141,8 +140,6 @@
     <dimen name="spring_loaded_panel_border">1dp</dimen>
 
 <!-- Folders -->
-    <!-- The size of the padding on the preview background drawable -->
-    <dimen name="folder_preview_padding">10dp</dimen>
     <dimen name="page_indicator_dot_size">8dp</dimen>
 
     <dimen name="folder_cell_x_padding">9dp</dimen>
@@ -227,5 +224,6 @@
     <dimen name="swipe_helper_falsing_threshold">70dp</dimen>
 
 <!-- Overview -->
-    <dimen name="options_menu_icon_size">48dp</dimen>
+    <dimen name="options_menu_icon_size">24dp</dimen>
+    <dimen name="options_menu_thumb_size">32dp</dimen>
 </resources>
diff --git a/res/values/drawables.xml b/res/values/drawables.xml
index fea17b1..1367174 100644
--- a/res/values/drawables.xml
+++ b/res/values/drawables.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <drawable name="ic_info_shadow">@drawable/ic_info_no_shadow</drawable>
+    <drawable name="ic_setup_shadow">@drawable/ic_setting</drawable>
     <drawable name="ic_remove_shadow">@drawable/ic_remove_no_shadow</drawable>
     <drawable name="ic_uninstall_shadow">@drawable/ic_uninstall_no_shadow</drawable>
 </resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2318e9e..7bc11c3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -72,6 +72,11 @@
     <string name="notifications_header">Notifications</string>
 
     <!-- Drag and drop -->
+    <!-- Message to tell the user to press and hold on a shortcut to add it [CHAR_LIMIT=50] -->
+    <string name="long_press_shortcut_to_add">Touch &amp; hold to pick up a shortcut.</string>
+    <!-- Accessibility spoken hint message in deep shortcut menu, which allows user to add a shortcut. Custom action is the label for additional accessibility actions available in this mode [CHAR_LIMIT=200] -->
+    <string name="long_accessible_way_to_add_shortcut">Double-tap &amp; hold to pick up a shortcut or use custom actions.</string>
+
     <skip />
     <!-- Error message when user has filled a home screen -->
     <string name="out_of_space">No more room on this Home screen.</string>
@@ -80,6 +85,9 @@
 
     <!-- All applications label -->
     <string name="all_apps_button_label">Apps list</string>
+    <string name="all_apps_button_personal_label">Personal apps list</string>
+    <string name="all_apps_button_work_label">Work apps list</string>
+
     <!-- Label for button in all applications label to go back home (to the workspace / desktop)
          for accessibilty (spoken when the button gets focus). -->
     <string name="all_apps_home_button_label">Home</string>
@@ -169,16 +177,12 @@
     <string name="settings_button_text">Home settings</string>
     <!-- Message shown when a feature is disabled by the administrator -->
     <string name="msg_disabled_by_admin">Disabled by your admin</string>
-    <!-- Text for custom accessibility action to go to the overview mode, where users can look and change the overall UI of the launcher. -->
-    <string name="accessibility_action_overview">Overview</string>
 
     <!-- Strings for settings -->
     <!-- Title for Allow Rotation setting. [CHAR LIMIT=50] -->
     <string name="allow_rotation_title">Allow Home screen rotation</string>
     <!-- Text explaining when the home screen will get rotated. [CHAR LIMIT=100] -->
     <string name="allow_rotation_desc">When phone is rotated</string>
-    <!-- Text explaining that rotation is disabled in Display settings. 'Display' refers to the Display section in system settings [CHAR LIMIT=100] -->
-    <string name="allow_rotation_blocked_desc">Current Display setting doesn\'t permit rotation</string>
     <!-- Title for Notification dots setting. Tapping this will link to the system Notifications settings screen where the user can turn off notification dots globally. [CHAR LIMIT=50] -->
     <string name="icon_badging_title">Notification dots</string>
     <!-- Text to indicate that the system icon badging setting is on [CHAR LIMIT=100] -->
@@ -191,6 +195,8 @@
     <string name="msg_missing_notification_access">To show Notification Dots, turn on app notifications for <xliff:g id="name" example="My App">%1$s</xliff:g></string>
     <!-- Button text in the confirmation dialog which would take the user to the system settings [CHAR LIMIT=50] -->
     <string name="title_change_settings">Change settings</string>
+    <!-- Summary for Notification dots setting. Tapping this will link enable/disable notification dots feature on the home screen. [CHAR LIMIT=50] -->
+    <string name="icon_badging_service_title">Show notification dots</string>
 
     <!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
     <string name="auto_add_shortcuts_label">Add icon to Home screen</string>
@@ -199,6 +205,8 @@
 
     <!-- Developer setting to change the shape of icons on home screen. [CHAR LIMIT=50] -->
     <string name="icon_shape_override_label">Change icon shape</string>
+    <!-- Subtext explaining that the icons will only be affected on the home screen. This text follows the actual icon action: Change icon shape, on Home screen [CHAR LIMIT=100] -->
+    <string name="icon_shape_override_label_location">on Home screen</string>
     <!-- Option to not change the icon shape on home screen and use the system default setting instead. [CHAR LIMIT=50] -->
     <string name="icon_shape_system_default">Use system default</string>
     <!-- Option to change the shape of the home screen icons to a square. [CHAR LIMIT=50] -->
@@ -236,6 +244,11 @@
     <!-- Title for a bottom sheet that shows widgets for a particular app -->
     <string name="widgets_bottom_sheet_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> widgets</string>
 
+    <!-- Accessibility title for the popup containing a list of widgets. [CHAR_LIMIT=50] -->
+    <string name="widgets_list">Widgets list</string>
+    <!-- Text announced by accessibility when the popup containing the list of widgets is closed. [CHAR_LIMIT=100] -->
+    <string name="widgets_list_closed">Widgets list closed</string>
+
 <!-- Strings for accessibility actions -->
     <!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
     <string name="action_add_to_workspace">Add to Home screen</string>
@@ -282,15 +295,6 @@
     <!-- Accessibility action to move an item from folder to workspace. [CHAR_LIMIT=30] -->
     <string name="action_move_to_workspace">Move to Home screen</string>
 
-    <!-- Accessibility action to move an homescreen to the left. [CHAR_LIMIT=30] -->
-    <string name="action_move_screen_left">Move screen to left</string>
-
-    <!-- Accessibility action to move an homescreen to the right. [CHAR_LIMIT=30] -->
-    <string name="action_move_screen_right">Move screen to right</string>
-
-    <!-- Accessibility confirmation when a screen was moved. -->
-    <string name="screen_moved">Screen moved</string>
-
     <!-- Accessibility action to resize a widget. [CHAR_LIMIT=30] -->
     <string name="action_resize">Resize</string>
 
@@ -311,11 +315,9 @@
 
     <!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_deep_shortcut">Shortcuts</string>
-
-    <!-- Accessibility description for the shortcuts menu shown for an app. -->
-    <string name="shortcuts_menu_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts for <xliff:g id="app_name" example="Messenger">%2$s</xliff:g></string>
-    <!-- Accessibility description when the shortcuts menu has notifications as well as shortcuts. -->
-    <string name="shortcuts_menu_with_notifications_description"><xliff:g id="number_of_shortcuts" example="3">%1$d</xliff:g> shortcuts and <xliff:g id="number_of_notifications" example="3">%2$d</xliff:g> notifications for <xliff:g id="app_name" example="Messenger">%3$s</xliff:g></string>
+    <!-- Accessibility description when the context menu of a launcher icon that has notifications as well as shortcuts (providing quick access to app's actions). The "shortcuts" translation should be consistent with the one for action_deep_shortcut. [CHAR_LIMIT=50] -->
+    <string name="shortcuts_menu_with_notifications_description">Shortcuts and notifications
+    </string>
 
     <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_dismiss_notification">Dismiss</string>
@@ -334,11 +336,12 @@
     <!-- Title of an overlay in All Apps. This overlay is letting a user know about their work profile, which is managed by their employer. "Work apps" are apps in a user's work profile.-->
     <string name="bottom_work_tab_user_education_title">Find work apps here</string>
     <!-- Text in an overlay in All Apps. This overlay is letting a user know about their work profile, which is managed by their employer.-->
-    <string name="bottom_work_tab_user_education_body">Each work app has an orange badge and is kept secure by your organization. Move apps to your Home screen for easier access.</string>
+    <string name="bottom_work_tab_user_education_body">Each work app has a badge and is kept secure by your organization. Move apps to your Home screen for easier access.</string>
     <!-- This string is in the work profile tab when a user has All Apps open on their phone. It describes the label of a toggle, "Work profile," as being managed by the user's employer.
     "Organization" is used to represent a variety of businesses, non-profits, and educational institutions).-->
     <string name="work_mode_on_label">Managed by your organization</string>
     <!-- This string appears under a the label of a toggle in the work profile tab on a user's phone. It describes the status of the toggle, "Work profile," when it's turned off. "Work profile" means a separate profile on a user's phone that's speficially for their work apps and is managed by their company.-->
     <string name="work_mode_off_label">Notifications and apps are off</string>
-
+    <string name="bottom_work_tab_user_education_close_button">Close</string>
+    <string name="bottom_work_tab_user_education_closed">Closed</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8cc4743..07bd800 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -25,11 +25,11 @@
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:colorEdgeEffect">#FF757575</item>
-        <item name="android:keyboardLayout">@layout/search_container_all_apps</item>
     </style>
 
     <style name="BaseLauncherThemeWithCustomAttrs" parent="@style/BaseLauncherTheme">
-        <item name="allAppsScrimColor">#CCFFFFFF</item>
+        <item name="allAppsScrimColor">#EAFFFFFF</item>
+        <item name="allAppsInterimScrimAlpha">46</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="popupColorPrimary">#FFF</item>
         <item name="popupColorSecondary">#F5F5F5</item> <!-- Gray 100 -->
@@ -46,7 +46,35 @@
 
     <style name="LauncherTheme" parent="@style/BaseLauncherThemeWithCustomAttrs"></style>
 
-    <style name="LauncherThemeDarkText" parent="@style/LauncherTheme">
+    <style name="LauncherTheme.DarkText" parent="@style/LauncherTheme">
+        <item name="workspaceTextColor">#FF212121</item>
+        <item name="allAppsInterimScrimAlpha">128</item>
+        <item name="workspaceShadowColor">@android:color/transparent</item>
+        <item name="workspaceAmbientShadowColor">@android:color/transparent</item>
+        <item name="workspaceKeyShadowColor">@android:color/transparent</item>
+        <item name="isWorkspaceDarkText">true</item>
+        <item name="workspaceStatusBarScrim">@null</item>
+    </style>
+
+    <style name="LauncherTheme.Dark" parent="@style/LauncherTheme">
+        <item name="android:textColorPrimary">#FFFFFFFF</item>
+        <item name="android:textColorSecondary">#FFFFFFFF</item>
+        <item name="android:textColorTertiary">#CCFFFFFF</item>
+        <item name="android:textColorHint">#A0FFFFFF</item>
+        <item name="android:colorControlHighlight">#A0FFFFFF</item>
+        <item name="android:colorPrimary">#FF212121</item>
+        <item name="allAppsScrimColor">#EA212121</item>
+        <item name="allAppsInterimScrimAlpha">102</item>
+        <item name="allAppsNavBarScrimColor">#80000000</item>
+        <item name="popupColorPrimary">?android:attr/colorPrimary</item>
+        <item name="popupColorSecondary">#424242</item> <!-- Gray 800 -->
+        <item name="popupColorTertiary">#757575</item> <!-- Gray 600 -->
+        <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+        <item name="isMainColorDark">true</item>
+    </style>
+
+    <style name="LauncherTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark">
+        <item name="allAppsInterimScrimAlpha">25</item>
         <item name="workspaceTextColor">#FF212121</item>
         <item name="workspaceShadowColor">@android:color/transparent</item>
         <item name="workspaceAmbientShadowColor">@android:color/transparent</item>
@@ -55,21 +83,12 @@
         <item name="workspaceStatusBarScrim">@null</item>
     </style>
 
-    <style name="LauncherThemeDark" parent="@style/LauncherTheme">
-        <item name="android:textColorPrimary">#FFFFFFFF</item>
-        <item name="android:textColorSecondary">#FFFFFFFF</item>
-        <item name="android:textColorTertiary">#CCFFFFFF</item>
-        <item name="android:textColorHint">#A0FFFFFF</item>
-        <item name="android:colorControlHighlight">#A0FFFFFF</item>
-        <item name="android:colorPrimary">#FF333333</item>
-        <item name="allAppsScrimColor">#7A212121</item>
-        <item name="allAppsNavBarScrimColor">#80000000</item>
-        <item name="popupColorPrimary">?android:attr/colorPrimary</item>
-        <item name="popupColorSecondary">#424242</item> <!-- Gray 800 -->
-        <item name="popupColorTertiary">#757575</item> <!-- Gray 600 -->
-        <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
-        <item name="isMainColorDark">true</item>
-    </style>
+    <!-- A derivative project can extend these themes to customize the application theme without
+         affecting the base theme -->
+    <style name="AppTheme" parent="@style/LauncherTheme" />
+    <style name="AppTheme.DarkText" parent="@style/LauncherTheme.DarkText" />
+    <style name="AppTheme.Dark" parent="@style/LauncherTheme.Dark" />
+    <style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
 
     <!--
     Theme overrides to element on homescreen, i.e., which are drawn on top on wallpaper.
@@ -103,6 +122,7 @@
         <item name="android:saveEnabled">false</item>
         <item name="android:textColor">@android:color/white</item>
         <item name="android:includeFontPadding">false</item>
+        <item name="android:importantForAccessibility">no</item>
     </style>
 
     <!-- Base theme for BubbleTextView and sub classes -->
@@ -113,9 +133,9 @@
         <item name="android:focusable">true</item>
         <item name="android:gravity">center_horizontal</item>
         <item name="android:singleLine">true</item>
-        <item name="android:ellipsize">marquee</item>
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:defaultFocusHighlightEnabled">false</item>
 
         <!-- No shadows in the base theme -->
         <item name="android:shadowRadius">0</item>
diff --git a/res/xml/launcher_preferences.xml b/res/xml/launcher_preferences.xml
index 28a35b8..3bba73a 100644
--- a/res/xml/launcher_preferences.xml
+++ b/res/xml/launcher_preferences.xml
@@ -34,15 +34,14 @@
         android:title="@string/auto_add_shortcuts_label"
         android:summary="@string/auto_add_shortcuts_description"
         android:defaultValue="true"
-        android:persistent="true"
-        />
+        android:persistent="true" />
 
     <SwitchPreference
         android:key="pref_allowRotation"
         android:title="@string/allow_rotation_title"
+        android:summary="@string/allow_rotation_desc"
         android:defaultValue="@bool/allow_rotation"
-        android:persistent="true"
-        />
+        android:persistent="true" />
 
     <ListPreference
         android:key="pref_override_icon_shape"
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 12f022f..3223837 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -16,17 +16,26 @@
 
 package com.android.launcher3;
 
+import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.support.annotation.IntDef;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.LinearLayout;
 
-import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BaseDragLayer;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -43,6 +52,7 @@
             TYPE_WIDGET_RESIZE_FRAME,
             TYPE_WIDGETS_FULL_SHEET,
             TYPE_ON_BOARD_POPUP,
+            TYPE_DISCOVERY_BOUNCE,
 
             TYPE_QUICKSTEP_PREVIEW,
             TYPE_TASK_MENU,
@@ -56,6 +66,7 @@
     public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3;
     public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
     public static final int TYPE_ON_BOARD_POPUP = 1 << 5;
+    public static final int TYPE_DISCOVERY_BOUNCE = 1 << 6;
 
     // Popups related to quickstep UI
     public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 6;
@@ -64,11 +75,18 @@
 
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
-            | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_TASK_MENU | TYPE_OPTIONS_POPUP;
+            | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
+            | TYPE_OPTIONS_POPUP;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
-            | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_OPTIONS_POPUP;
+            | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE;
+
+    // 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;
+
+    public static final int TYPE_ACCESSIBLE = TYPE_ALL
+            & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_QUICKSTEP_PREVIEW;
 
     protected boolean mIsOpen;
 
@@ -90,9 +108,13 @@
     }
 
     public final void close(boolean animate) {
-        animate &= !Utilities.isPowerSaverOn(getContext());
+        animate &= !Utilities.isPowerSaverPreventingAnimation(getContext());
+        if (mIsOpen) {
+            BaseActivity.fromContext(getContext()).getUserEventDispatcher()
+                    .resetElapsedContainerMillis("container closed");
+        }
         handleClose(animate);
-        Launcher.getLauncher(getContext()).getUserEventDispatcher().resetElapsedContainerMillis();
+        mIsOpen = false;
     }
 
     protected abstract void handleClose(boolean animate);
@@ -108,9 +130,11 @@
 
     protected abstract boolean isOfType(@FloatingViewType int type);
 
-    public void onBackPressed() {
+    /** @return Whether the back is consumed. If false, Launcher will handle the back as well. */
+    public boolean onBackPressed() {
         logActionCommand(Action.Command.BACK);
         close(true);
+        return true;
     }
 
     @Override
@@ -118,9 +142,28 @@
         return false;
     }
 
+    protected void announceAccessibilityChanges() {
+        Pair<View, String> targetInfo = getAccessibilityTarget();
+        if (targetInfo == null || !isAccessibilityEnabled(getContext())) {
+            return;
+        }
+        sendCustomAccessibilityEvent(
+                targetInfo.first, TYPE_WINDOW_STATE_CHANGED, targetInfo.second);
+
+        if (mIsOpen) {
+            sendAccessibilityEvent(TYPE_VIEW_FOCUSED);
+        }
+        ActivityContext.lookupContext(getContext()).getDragLayer()
+                .sendAccessibilityEvent(TYPE_WINDOW_CONTENT_CHANGED);
+    }
+
+    protected Pair<View, String> getAccessibilityTarget() {
+        return null;
+    }
+
     protected static <T extends AbstractFloatingView> T getOpenView(
-            Launcher launcher, @FloatingViewType int type) {
-        DragLayer dragLayer = launcher.getDragLayer();
+            ActivityContext activity, @FloatingViewType int type) {
+        BaseDragLayer dragLayer = activity.getDragLayer();
         // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
         // and will be one of the last views.
         for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@@ -135,16 +178,17 @@
         return null;
     }
 
-    public static void closeOpenContainer(Launcher launcher, @FloatingViewType int type) {
-        AbstractFloatingView view = getOpenView(launcher, type);
+    public static void closeOpenContainer(ActivityContext activity,
+            @FloatingViewType int type) {
+        AbstractFloatingView view = getOpenView(activity, type);
         if (view != null) {
             view.close(true);
         }
     }
 
-    public static void closeOpenViews(Launcher launcher, boolean animate,
+    public static void closeOpenViews(ActivityContext activity, boolean animate,
             @FloatingViewType int type) {
-        DragLayer dragLayer = launcher.getDragLayer();
+        BaseDragLayer dragLayer = activity.getDragLayer();
         // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
         // and will be one of the last views.
         for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
@@ -158,16 +202,21 @@
         }
     }
 
-    public static void closeAllOpenViews(Launcher launcher, boolean animate) {
-        closeOpenViews(launcher, animate, TYPE_ALL);
-        launcher.finishAutoCancelActionMode();
+    public static void closeAllOpenViews(ActivityContext activity, boolean animate) {
+        closeOpenViews(activity, animate, TYPE_ALL);
+        activity.finishAutoCancelActionMode();
     }
 
-    public static void closeAllOpenViews(Launcher launcher) {
-        closeAllOpenViews(launcher, true);
+    public static void closeAllOpenViews(ActivityContext activity) {
+        closeAllOpenViews(activity, true);
     }
 
-    public static AbstractFloatingView getTopOpenView(Launcher launcher) {
-        return getOpenView(launcher, TYPE_ALL);
+    public static AbstractFloatingView getTopOpenView(ActivityContext activity) {
+        return getTopOpenViewWithType(activity, TYPE_ALL);
+    }
+
+    public static AbstractFloatingView getTopOpenViewWithType(ActivityContext activity,
+            @FloatingViewType int type) {
+        return getOpenView(activity, type);
     }
 }
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
index 923835a..9b6166f 100644
--- a/src/com/android/launcher3/AppFilter.java
+++ b/src/com/android/launcher3/AppFilter.java
@@ -3,10 +3,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 
-public class AppFilter {
+import com.android.launcher3.util.ResourceBasedOverride;
+
+public class AppFilter implements ResourceBasedOverride {
 
     public static AppFilter newInstance(Context context) {
-        return Utilities.getOverrideObject(AppFilter.class, context, R.string.app_filter_class);
+        return Overrides.getObject(AppFilter.class, context, R.string.app_filter_class);
     }
 
     public boolean shouldShowApp(ComponentName app) {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 4a0f52d..6c82e63 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -16,27 +16,85 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
+import android.content.res.Configuration;
+import android.support.annotation.IntDef;
+import android.view.ContextThemeWrapper;
 import android.view.View.AccessibilityDelegate;
 
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
+import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.SystemUiController;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
 import java.util.ArrayList;
 
-public abstract class BaseActivity extends Activity {
+public abstract class BaseActivity extends Activity implements UserEventDelegate{
+
+    public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
+    public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
+    public static final int INVISIBLE_BY_PENDING_FLAGS = 1 << 2;
+
+    // This is not treated as invisibility flag, but adds as a hint for an incomplete transition.
+    // When the wallpaper animation runs, it replaces this flag with a proper invisibility
+    // flag, INVISIBLE_BY_PENDING_FLAGS only for the duration of that animation.
+    public static final int PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION = 1 << 3;
+
+    private static final int INVISIBLE_FLAGS =
+            INVISIBLE_BY_STATE_HANDLER | INVISIBLE_BY_APP_TRANSITIONS | INVISIBLE_BY_PENDING_FLAGS;
+    public static final int STATE_HANDLER_INVISIBILITY_FLAGS =
+            INVISIBLE_BY_STATE_HANDLER | PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+    public static final int INVISIBLE_ALL =
+            INVISIBLE_FLAGS | PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+
+    @Retention(SOURCE)
+    @IntDef(
+            flag = true,
+            value = {INVISIBLE_BY_STATE_HANDLER, INVISIBLE_BY_APP_TRANSITIONS,
+                    INVISIBLE_BY_PENDING_FLAGS, PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION})
+    public @interface InvisibilityFlags{}
 
     private final ArrayList<OnDeviceProfileChangeListener> mDPChangeListeners = new ArrayList<>();
+    private final ArrayList<MultiWindowModeChangedListener> mMultiWindowModeChangedListeners =
+            new ArrayList<>();
 
     protected DeviceProfile mDeviceProfile;
     protected UserEventDispatcher mUserEventDispatcher;
     protected SystemUiController mSystemUiController;
 
-    private boolean mStarted;
+    private static final int ACTIVITY_STATE_STARTED = 1 << 0;
+    private static final int ACTIVITY_STATE_RESUMED = 1 << 1;
+    /**
+     * State flag indicating if the user is active or the actitvity when to background as a result
+     * of user action.
+     * @see #isUserActive()
+     */
+    private static final int ACTIVITY_STATE_USER_ACTIVE = 1 << 2;
+
+    @Retention(SOURCE)
+    @IntDef(
+            flag = true,
+            value = {ACTIVITY_STATE_STARTED, ACTIVITY_STATE_RESUMED, ACTIVITY_STATE_USER_ACTIVE})
+    public @interface ActivityFlags{}
+
+    @ActivityFlags
+    private int mActivityFlags;
+
+    // When the recents animation is running, the visibility of the Launcher is managed by the
+    // animation
+    @InvisibilityFlags private int mForceInvisible;
 
     public DeviceProfile getDeviceProfile() {
         return mDeviceProfile;
@@ -46,10 +104,11 @@
         return null;
     }
 
+    public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {}
+
     public final UserEventDispatcher getUserEventDispatcher() {
         if (mUserEventDispatcher == null) {
-            mUserEventDispatcher = UserEventDispatcher.newInstance(this,
-                    mDeviceProfile.isLandscape, isInMultiWindowModeCompat());
+            mUserEventDispatcher = UserEventDispatcher.newInstance(this, this);
         }
         return mUserEventDispatcher;
     }
@@ -58,13 +117,6 @@
         return Utilities.ATLEAST_NOUGAT && isInMultiWindowMode();
     }
 
-    public static BaseActivity fromContext(Context context) {
-        if (context instanceof BaseActivity) {
-            return (BaseActivity) context;
-        }
-        return ((BaseActivity) ((ContextWrapper) context).getBaseContext());
-    }
-
     public SystemUiController getSystemUiController() {
         if (mSystemUiController == null) {
             mSystemUiController = new SystemUiController(getWindow());
@@ -79,28 +131,136 @@
 
     @Override
     protected void onStart() {
-        mStarted = true;
+        mActivityFlags |= ACTIVITY_STATE_STARTED;
         super.onStart();
     }
 
     @Override
+    protected void onResume() {
+        mActivityFlags |= ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE;
+        super.onResume();
+    }
+
+    @Override
+    protected void onUserLeaveHint() {
+        mActivityFlags &= ~ACTIVITY_STATE_USER_ACTIVE;
+        super.onUserLeaveHint();
+    }
+
+    @Override
+    public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
+        super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
+        for (int i = mMultiWindowModeChangedListeners.size() - 1; i >= 0; i--) {
+            mMultiWindowModeChangedListeners.get(i).onMultiWindowModeChanged(isInMultiWindowMode);
+        }
+    }
+
+    @Override
     protected void onStop() {
-        mStarted = false;
+        mActivityFlags &= ~ACTIVITY_STATE_STARTED & ~ACTIVITY_STATE_USER_ACTIVE;
+        mForceInvisible = 0;
         super.onStop();
     }
 
+    @Override
+    protected void onPause() {
+        mActivityFlags &= ~ACTIVITY_STATE_RESUMED;
+        super.onPause();
+
+        // Reset the overridden sysui flags used for the task-swipe launch animation, we do this
+        // here instead of at the end of the animation because the start of the new activity does
+        // not happen immediately, which would cause us to reset to launcher's sysui flags and then
+        // back to the new app (causing a flash)
+        getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
+    }
+
     public boolean isStarted() {
-        return mStarted;
+        return (mActivityFlags & ACTIVITY_STATE_STARTED) != 0;
+    }
+
+    /**
+     * isResumed in already defined as a hidden final method in Activity.java
+     */
+    public boolean hasBeenResumed() {
+        return (mActivityFlags & ACTIVITY_STATE_RESUMED) != 0;
+    }
+
+    public boolean isUserActive() {
+        return (mActivityFlags & ACTIVITY_STATE_USER_ACTIVE) != 0;
     }
 
     public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
         mDPChangeListeners.add(listener);
     }
 
+    public void removeOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
+        mDPChangeListeners.remove(listener);
+    }
+
     protected void dispatchDeviceProfileChanged() {
-        int count = mDPChangeListeners.size();
-        for (int i = 0; i < count; i++) {
+        for (int i = mDPChangeListeners.size() - 1; i >= 0; i--) {
             mDPChangeListeners.get(i).onDeviceProfileChanged(mDeviceProfile);
         }
     }
+
+    public void addMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) {
+        mMultiWindowModeChangedListeners.add(listener);
+    }
+
+    public void removeMultiWindowModeChangedListener(MultiWindowModeChangedListener listener) {
+        mMultiWindowModeChangedListeners.remove(listener);
+    }
+
+    /**
+     * Used to set the override visibility state, used only to handle the transition home with the
+     * recents animation.
+     * @see LauncherAppTransitionManagerImpl#getWallpaperOpenRunner()
+     */
+    public void addForceInvisibleFlag(@InvisibilityFlags int flag) {
+        mForceInvisible |= flag;
+    }
+
+    public void clearForceInvisibleFlag(@InvisibilityFlags int flag) {
+        mForceInvisible &= ~flag;
+    }
+
+    /**
+     * @return Wether this activity should be considered invisible regardless of actual visibility.
+     */
+    public boolean isForceInvisible() {
+        return hasSomeInvisibleFlag(INVISIBLE_FLAGS);
+    }
+
+    public boolean hasSomeInvisibleFlag(int mask) {
+        return (mForceInvisible & mask) != 0;
+    }
+
+    public interface MultiWindowModeChangedListener {
+        void onMultiWindowModeChanged(boolean isInMultiWindowMode);
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (!UiFactory.dumpActivity(this, writer)) {
+            super.dump(prefix, fd, writer, args);
+        }
+    }
+
+    protected void dumpMisc(PrintWriter writer) {
+        writer.println(" deviceProfile isTransposed=" + getDeviceProfile().isVerticalBarLayout());
+        writer.println(" orientation=" + getResources().getConfiguration().orientation);
+        writer.println(" mSystemUiController: " + mSystemUiController);
+        writer.println(" mActivityFlags: " + mActivityFlags);
+        writer.println(" mForceInvisible: " + mForceInvisible);
+    }
+
+    public static <T extends BaseActivity> T fromContext(Context context) {
+        if (context instanceof BaseActivity) {
+            return (T) context;
+        } else if (context instanceof ContextThemeWrapper) {
+            return fromContext(((ContextWrapper) context).getBaseContext());
+        } else {
+            throw new IllegalArgumentException("Cannot find BaseActivity in parent tree");
+        }
+    }
 }
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
new file mode 100644
index 0000000..d6635dc
--- /dev/null
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2018 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;
+
+import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.ActionMode;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.badge.BadgeInfo;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.uioverrides.DisplayRotationListener;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.views.ActivityContext;
+
+/**
+ * Extension of BaseActivity allowing support for drag-n-drop
+ */
+public abstract class BaseDraggingActivity extends BaseActivity
+        implements WallpaperColorInfo.OnChangeListener, ActivityContext {
+
+    private static final String TAG = "BaseDraggingActivity";
+
+    // The Intent extra that defines whether to ignore the launch animation
+    public static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
+            "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
+
+    // When starting an action mode, setting this tag will cause the action mode to be cancelled
+    // automatically when user interacts with the launcher.
+    public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
+
+    private ActionMode mCurrentActionMode;
+    protected boolean mIsSafeModeEnabled;
+
+    private OnStartCallback mOnStartCallback;
+
+    private int mThemeRes = R.style.AppTheme;
+
+    private DisplayRotationListener mRotationListener;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mIsSafeModeEnabled = getPackageManager().isSafeMode();
+        mRotationListener = new DisplayRotationListener(this, this::onDeviceRotationChanged);
+
+        // Update theme
+        WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
+        wallpaperColorInfo.addOnChangeListener(this);
+        int themeRes = getThemeRes(wallpaperColorInfo);
+        if (themeRes != mThemeRes) {
+            mThemeRes = themeRes;
+            setTheme(themeRes);
+        }
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+        if (mThemeRes != getThemeRes(wallpaperColorInfo)) {
+            recreate();
+        }
+    }
+
+    protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) {
+        if (wallpaperColorInfo.isDark()) {
+            return wallpaperColorInfo.supportsDarkText() ?
+                    R.style.AppTheme_Dark_DarkText : R.style.AppTheme_Dark;
+        } else {
+            return wallpaperColorInfo.supportsDarkText() ?
+                    R.style.AppTheme_DarkText : R.style.AppTheme;
+        }
+    }
+
+    @Override
+    public void onActionModeStarted(ActionMode mode) {
+        super.onActionModeStarted(mode);
+        mCurrentActionMode = mode;
+    }
+
+    @Override
+    public void onActionModeFinished(ActionMode mode) {
+        super.onActionModeFinished(mode);
+        mCurrentActionMode = null;
+    }
+
+    @Override
+    public boolean finishAutoCancelActionMode() {
+        if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
+            mCurrentActionMode.finish();
+            return true;
+        }
+        return false;
+    }
+
+    public abstract BaseDragLayer getDragLayer();
+
+    public abstract <T extends View> T getOverviewPanel();
+
+    public abstract View getRootView();
+
+    public abstract BadgeInfo getBadgeInfoForItem(ItemInfo info);
+
+    public abstract void invalidateParent(ItemInfo info);
+
+    public Rect getViewBounds(View v) {
+        int[] pos = new int[2];
+        v.getLocationOnScreen(pos);
+        return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+    }
+
+    public final Bundle getActivityLaunchOptionsAsBundle(View v) {
+        ActivityOptions activityOptions = getActivityLaunchOptions(v);
+        return activityOptions == null ? null : activityOptions.toBundle();
+    }
+
+    public abstract ActivityOptions getActivityLaunchOptions(View v);
+
+    public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
+        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
+            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
+            return false;
+        }
+
+        // Only launch using the new animation if the shortcut has not opted out (this is a
+        // private contract between launcher and may be ignored in the future).
+        boolean useLaunchAnimation = (v != null) &&
+                !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
+        Bundle optsBundle = useLaunchAnimation
+                ? getActivityLaunchOptionsAsBundle(v)
+                : null;
+
+        UserHandle user = item == null ? null : item.user;
+
+        // Prepare intent
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (v != null) {
+            intent.setSourceBounds(getViewBounds(v));
+        }
+        try {
+            boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
+                    && (item instanceof ShortcutInfo)
+                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
+                    || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
+                    && !((ShortcutInfo) item).isPromise();
+            if (isShortcut) {
+                // Shortcuts need some special checks due to legacy reasons.
+                startShortcutIntentSafely(intent, optsBundle, item);
+            } else if (user == null || user.equals(Process.myUserHandle())) {
+                // Could be launching some bookkeeping activity
+                startActivity(intent, optsBundle);
+            } else {
+                LauncherAppsCompat.getInstance(this).startActivityForProfile(
+                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
+            }
+            getUserEventDispatcher().logAppLaunch(v, intent);
+            return true;
+        } catch (ActivityNotFoundException|SecurityException e) {
+            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
+        }
+        return false;
+    }
+
+    private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
+        try {
+            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
+            try {
+                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
+                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
+                // is enabled by default on NYC.
+                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
+                        .penaltyLog().build());
+
+                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                    String id = ((ShortcutInfo) info).getDeepShortcutId();
+                    String packageName = intent.getPackage();
+                    DeepShortcutManager.getInstance(this).startShortcut(
+                            packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+                } else {
+                    // Could be launching some bookkeeping activity
+                    startActivity(intent, optsBundle);
+                }
+            } finally {
+                StrictMode.setVmPolicy(oldPolicy);
+            }
+        } catch (SecurityException e) {
+            if (!onErrorStartingShortcut(intent, info)) {
+                throw e;
+            }
+        }
+    }
+
+    protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+        return false;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        if (mOnStartCallback != null) {
+            mOnStartCallback.onActivityStart(this);
+            mOnStartCallback = null;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        WallpaperColorInfo.getInstance(this).removeOnChangeListener(this);
+        mRotationListener.disable();
+    }
+
+    public <T extends BaseDraggingActivity> void setOnStartCallback(OnStartCallback<T> callback) {
+        mOnStartCallback = callback;
+    }
+
+    protected void onDeviceProfileInitiated() {
+        if (mDeviceProfile.isVerticalBarLayout()) {
+            mRotationListener.enable();
+            mDeviceProfile.updateIsSeascape(getWindowManager());
+        } else {
+            mRotationListener.disable();
+        }
+    }
+
+    private void onDeviceRotationChanged() {
+        if (mDeviceProfile.updateIsSeascape(getWindowManager())) {
+            reapplyUi();
+        }
+    }
+
+    protected abstract void reapplyUi();
+
+    /**
+     * Callback for listening for onStart
+     */
+    public interface OnStartCallback<T extends BaseDraggingActivity> {
+
+        void onActivityStart(T activity);
+    }
+}
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index cc13263..74b9cfa 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -33,8 +33,7 @@
  *   <li> Enable fast scroller.
  * </ul>
  */
-public abstract class BaseRecyclerView extends RecyclerView
-        implements RecyclerView.OnItemTouchListener {
+public abstract class BaseRecyclerView extends RecyclerView  {
 
     protected RecyclerViewFastScroller mScrollbar;
 
@@ -51,12 +50,6 @@
     }
 
     @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        addOnItemTouchListener(this);
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         bindFastScrollbar();
@@ -69,40 +62,8 @@
         onUpdateScrollbar(0);
     }
 
-    /**
-     * We intercept the touch handling only to support fast scrolling when initiated from the
-     * scroll bar.  Otherwise, we fall back to the default RecyclerView touch handling.
-     */
-    @Override
-    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
-        return handleTouchEvent(ev);
-    }
-
-    @Override
-    public void onTouchEvent(RecyclerView rv, MotionEvent ev) {
-        handleTouchEvent(ev);
-    }
-
-    /**
-     * Handles the touch event and determines whether to show the fast scroller (or updates it if
-     * it is already showing).
-     */
-    private boolean handleTouchEvent(MotionEvent ev) {
-        // Move to mScrollbar's coordinate system.
-        // We need to take parent into account (view pager's location)
-        ViewGroup parent = (ViewGroup) getParent();
-        int left = parent.getLeft() - mScrollbar.getLeft();
-        int top = parent.getTop() + getTop() - mScrollbar.getTop() - getScrollBarTop();
-        ev.offsetLocation(left, top);
-        try {
-            return mScrollbar.handleTouchEvent(ev);
-        } finally {
-            ev.offsetLocation(-left, -top);
-        }
-    }
-
-    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        // DO NOT REMOVE, NEEDED IMPLEMENTATION FOR M BUILDS
+    public RecyclerViewFastScroller getScrollbar() {
+        return mScrollbar;
     }
 
     public int getScrollBarTop() {
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index dbdb2dc..fb7c0ce 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -29,6 +28,7 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.v4.graphics.ColorUtils;
+import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.util.TypedValue;
@@ -37,7 +37,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewDebug;
-import android.view.ViewParent;
 import android.widget.TextView;
 
 import com.android.launcher3.IconCache.IconLoadRequest;
@@ -46,9 +45,7 @@
 import com.android.launcher3.badge.BadgeInfo;
 import com.android.launcher3.badge.BadgeRenderer;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderIconPreviewVerifier;
 import com.android.launcher3.graphics.DrawableFactory;
-import com.android.launcher3.graphics.HolographicOutlineHelper;
 import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.model.PackageItemInfo;
@@ -68,31 +65,6 @@
 
     private static final int[] STATE_PRESSED = new int[] {android.R.attr.state_pressed};
 
-    private final Launcher mLauncher;
-    private Drawable mIcon;
-    private final boolean mCenterVertically;
-
-    private final CheckLongPressHelper mLongPressHelper;
-    private final HolographicOutlineHelper mOutlineHelper;
-    private final StylusEventHelper mStylusEventHelper;
-    private final float mSlop;
-
-    private Bitmap mPressedBackground;
-
-    private final boolean mDeferShadowGenerationOnTouch;
-    private final boolean mLayoutHorizontal;
-    private final int mIconSize;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private int mTextColor;
-    private boolean mIsIconVisible = true;
-
-    private BadgeInfo mBadgeInfo;
-    private BadgeRenderer mBadgeRenderer;
-    private int mBadgeColor;
-    private float mBadgeScale;
-    private boolean mForceHideBadge;
-    private Point mTempSpaceForBadgeOffset = new Point();
-    private Rect mTempIconBounds = new Rect();
 
     private static final Property<BubbleTextView, Float> BADGE_SCALE_PROPERTY
             = new Property<BubbleTextView, Float>(Float.TYPE, "badgeScale") {
@@ -108,19 +80,45 @@
         }
     };
 
-    public static final Property<BubbleTextView, Integer> TEXT_ALPHA_PROPERTY
-            = new Property<BubbleTextView, Integer>(Integer.class, "textAlpha") {
+    public static final Property<BubbleTextView, Float> TEXT_ALPHA_PROPERTY
+            = new Property<BubbleTextView, Float>(Float.class, "textAlpha") {
         @Override
-        public Integer get(BubbleTextView bubbleTextView) {
-            return bubbleTextView.getTextAlpha();
+        public Float get(BubbleTextView bubbleTextView) {
+            return bubbleTextView.mTextAlpha;
         }
 
         @Override
-        public void set(BubbleTextView bubbleTextView, Integer alpha) {
+        public void set(BubbleTextView bubbleTextView, Float alpha) {
             bubbleTextView.setTextAlpha(alpha);
         }
     };
 
+    private final BaseDraggingActivity mActivity;
+    private Drawable mIcon;
+    private final boolean mCenterVertically;
+
+    private final CheckLongPressHelper mLongPressHelper;
+    private final StylusEventHelper mStylusEventHelper;
+    private final float mSlop;
+
+    private final boolean mLayoutHorizontal;
+    private final int mIconSize;
+
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private boolean mIsIconVisible = true;
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private int mTextColor;
+    @ViewDebug.ExportedProperty(category = "launcher")
+    private float mTextAlpha = 1;
+
+    private BadgeInfo mBadgeInfo;
+    private BadgeRenderer mBadgeRenderer;
+    private int mBadgeColor;
+    private float mBadgeScale;
+    private boolean mForceHideBadge;
+    private Point mTempSpaceForBadgeOffset = new Point();
+    private Rect mTempIconBounds = new Rect();
+
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mStayPressed;
     @ViewDebug.ExportedProperty(category = "launcher")
@@ -140,15 +138,13 @@
 
     public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mLauncher = Launcher.getLauncher(context);
-        DeviceProfile grid = mLauncher.getDeviceProfile();
+        mActivity = BaseDraggingActivity.fromContext(context);
+        DeviceProfile grid = mActivity.getDeviceProfile();
         mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
         mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
-        mDeferShadowGenerationOnTouch =
-                a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
 
         int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
         int defaultIconSize = grid.iconSizePx;
@@ -173,9 +169,16 @@
         mLongPressHelper = new CheckLongPressHelper(this);
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
 
-        mOutlineHelper = HolographicOutlineHelper.getInstance(getContext());
-        setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
+        setEllipsize(TruncateAt.END);
+        setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
+        setTextAlpha(1f);
+    }
 
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        // Disable marques when not focused to that, so that updating text does not cause relayout.
+        setEllipsize(focused ? TruncateAt.MARQUEE : TruncateAt.END);
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
     }
 
     /**
@@ -231,7 +234,6 @@
         FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info);
         mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f);
 
-        iconDrawable.setIsDisabled(info.isDisabled());
         setIcon(iconDrawable);
         setText(info.title);
         if (info.contentDescription != null) {
@@ -291,13 +293,6 @@
 
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                // So that the pressed outline is visible immediately on setStayPressed(),
-                // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
-                // to create it)
-                if (!mDeferShadowGenerationOnTouch && mPressedBackground == null) {
-                    mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-                }
-
                 // If we're in a stylus button press, don't check for long press.
                 if (!mStylusEventHelper.inStylusButtonPressed()) {
                     mLongPressHelper.postCheckForLongPress();
@@ -305,12 +300,6 @@
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                // If we've touched down and up on an item, and it's still not "pressed", then
-                // destroy the pressed outline
-                if (!isPressed()) {
-                    mPressedBackground = null;
-                }
-
                 mLongPressHelper.cancelLongPress();
                 break;
             case MotionEvent.ACTION_MOVE:
@@ -324,22 +313,6 @@
 
     void setStayPressed(boolean stayPressed) {
         mStayPressed = stayPressed;
-        if (!stayPressed) {
-            HolographicOutlineHelper.getInstance(getContext()).recycleShadowBitmap(mPressedBackground);
-            mPressedBackground = null;
-        } else {
-            if (mPressedBackground == null) {
-                mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-            }
-        }
-
-        // Only show the shadow effect when persistent pressed state is set.
-        ViewParent parent = getParent();
-        if (parent != null && parent.getParent() instanceof BubbleTextShadowHandler) {
-            ((BubbleTextShadowHandler) parent.getParent()).setPressedIcon(
-                    this, mPressedBackground);
-        }
-
         refreshDrawableState();
     }
 
@@ -356,26 +329,12 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (super.onKeyDown(keyCode, event)) {
-            // Pre-create shadow so show immediately on click.
-            if (mPressedBackground == null) {
-                mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         // Unlike touch events, keypress event propagate pressed state change immediately,
         // without waiting for onClickHandler to execute. Disable pressed state changes here
         // to avoid flickering.
         mIgnorePressedStateChange = true;
         boolean result = super.onKeyUp(keyCode, event);
-
-        mPressedBackground = null;
         mIgnorePressedStateChange = false;
         refreshDrawableState();
         return result;
@@ -450,13 +409,17 @@
     @Override
     public void setTextColor(int color) {
         mTextColor = color;
-        super.setTextColor(color);
+        super.setTextColor(getModifiedColor());
     }
 
     @Override
     public void setTextColor(ColorStateList colors) {
         mTextColor = colors.getDefaultColor();
-        super.setTextColor(colors);
+        if (Float.compare(mTextAlpha, 1) == 0) {
+            super.setTextColor(colors);
+        } else {
+            super.setTextColor(getModifiedColor());
+        }
     }
 
     public boolean shouldTextBeVisible() {
@@ -467,19 +430,21 @@
     }
 
     public void setTextVisibility(boolean visible) {
-        if (visible) {
-            super.setTextColor(mTextColor);
-        } else {
-            setTextAlpha(0);
+        setTextAlpha(visible ? 1 : 0);
+    }
+
+    private void setTextAlpha(float alpha) {
+        mTextAlpha = alpha;
+        super.setTextColor(getModifiedColor());
+    }
+
+    private int getModifiedColor() {
+        if (mTextAlpha == 0) {
+            // Special case to prevent text shadows in high contrast mode
+            return Color.TRANSPARENT;
         }
-    }
-
-    private void setTextAlpha(int alpha) {
-        super.setTextColor(ColorUtils.setAlphaComponent(mTextColor, alpha));
-    }
-
-    private int getTextAlpha() {
-        return Color.alpha(getCurrentTextColor());
+        return ColorUtils.setAlphaComponent(
+                mTextColor, Math.round(Color.alpha(mTextColor) * mTextAlpha));
     }
 
     /**
@@ -487,8 +452,8 @@
      * @param fadeIn Whether the text should fade in or fade out.
      */
     public ObjectAnimator createTextAlphaAnimator(boolean fadeIn) {
-        int toAlpha = shouldTextBeVisible() && fadeIn ? Color.alpha(mTextColor) : 0;
-        return ObjectAnimator.ofInt(this, TEXT_ALPHA_PROPERTY, toAlpha);
+        float toAlpha = shouldTextBeVisible() && fadeIn ? 1 : 0;
+        return ObjectAnimator.ofFloat(this, TEXT_ALPHA_PROPERTY, toAlpha);
     }
 
     @Override
@@ -547,10 +512,10 @@
     public void applyBadgeState(ItemInfo itemInfo, boolean animate) {
         if (mIcon instanceof FastBitmapDrawable) {
             boolean wasBadged = mBadgeInfo != null;
-            mBadgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
+            mBadgeInfo = mActivity.getBadgeInfoForItem(itemInfo);
             boolean isBadged = mBadgeInfo != null;
             float newBadgeScale = isBadged ? 1f : 0;
-            mBadgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
+            mBadgeRenderer = mActivity.getDeviceProfile().mBadgeRenderer;
             if (wasBadged || isBadged) {
                 // Animate when a badge is first added or when it is removed.
                 if (animate && (wasBadged ^ isBadged) && isShown()) {
@@ -576,31 +541,30 @@
      * Sets the icon for this view based on the layout direction.
      */
     private void setIcon(Drawable icon) {
-        mIcon = icon;
-        mIcon.setBounds(0, 0, mIconSize, mIconSize);
         if (mIsIconVisible) {
-            applyCompoundDrawables(mIcon);
+            applyCompoundDrawables(icon);
         }
+        mIcon = icon;
     }
 
     public void setIconVisible(boolean visible) {
         mIsIconVisible = visible;
-        mDisableRelayout = true;
-        Drawable icon = mIcon;
-        if (!visible) {
-            icon = new ColorDrawable(Color.TRANSPARENT);
-            icon.setBounds(0, 0, mIconSize, mIconSize);
-        }
+        Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
         applyCompoundDrawables(icon);
-        mDisableRelayout = false;
     }
 
     protected void applyCompoundDrawables(Drawable icon) {
+        // If we had already set an icon before, disable relayout as the icon size is the
+        // same as before.
+        mDisableRelayout = mIcon != null;
+
+        icon.setBounds(0, 0, mIconSize, mIconSize);
         if (mLayoutHorizontal) {
             setCompoundDrawablesRelative(icon, null, null, null);
         } else {
             setCompoundDrawables(null, icon, null, null);
         }
+        mDisableRelayout = false;
     }
 
     @Override
@@ -626,15 +590,7 @@
                 applyFromApplicationInfo((AppInfo) info);
             } else if (info instanceof ShortcutInfo) {
                 applyFromShortcutInfo((ShortcutInfo) info);
-                FolderIconPreviewVerifier verifier =
-                        new FolderIconPreviewVerifier(mLauncher.getDeviceProfile().inv);
-                if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
-                    View folderIcon =
-                            mLauncher.getWorkspace().getHomescreenIconByItemId(info.container);
-                    if (folderIcon != null) {
-                        folderIcon.invalidate();
-                    }
-                }
+                mActivity.invalidateParent(info);
             } else if (info instanceof PackageItemInfo) {
                 applyFromPackageItemInfo((PackageItemInfo) info);
             }
@@ -663,11 +619,4 @@
     public int getIconSize() {
         return mIconSize;
     }
-
-    /**
-     * Interface to be implemented by the grand parent to allow click shadow effect.
-     */
-    public interface BubbleTextShadowHandler {
-        void setPressedIcon(BubbleTextView icon, Bitmap background);
-    }
 }
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 19ee0b8..ed8c42d 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
 
@@ -108,6 +109,12 @@
         setContentDescription(mText);
     }
 
+    protected void updateText(int resId) {
+        setText(resId);
+        mText = getText();
+        setContentDescription(mText);
+    }
+
     protected void setDrawable(int resId) {
         // We do not set the drawable in the xml as that inflates two drawables corresponding to
         // drawableLeft and drawableStart.
@@ -186,8 +193,10 @@
             mCurrentFilter = new ColorMatrix();
         }
 
-        Themes.setColorScaleOnMatrix(getTextColor(), mSrcFilter);
-        Themes.setColorScaleOnMatrix(targetColor, mDstFilter);
+        int defaultTextColor = mOriginalTextColor.getDefaultColor();
+        Themes.setColorChangeOnMatrix(defaultTextColor, getTextColor(), mSrcFilter);
+        Themes.setColorChangeOnMatrix(defaultTextColor, targetColor, mDstFilter);
+
         ValueAnimator anim1 = ValueAnimator.ofObject(
                 new FloatArrayEvaluator(mCurrentFilter.getArray()),
                 mSrcFilter.getArray(), mDstFilter.getArray());
@@ -236,9 +245,7 @@
 
     protected abstract boolean supportsDrop(ItemInfo info);
 
-    public boolean supportsAccessibilityDrop(ItemInfo info) {
-        return supportsDrop(info);
-    }
+    public abstract boolean supportsAccessibilityDrop(ItemInfo info, View view);
 
     @Override
     public boolean isDropEnabled() {
@@ -368,4 +375,6 @@
                 TextUtils.TruncateAt.END);
         return !mText.equals(displayedText);
     }
+
+    public abstract Target getDropTargetForLogging();
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5e4f670..6c2fd8e 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -21,6 +21,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -45,7 +46,6 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 
-import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
 import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -70,7 +70,7 @@
 import java.util.Comparator;
 import java.util.Stack;
 
-public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
+public class CellLayout extends ViewGroup {
     public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
     public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
 
@@ -128,8 +128,6 @@
     private int mDragOutlineCurrent = 0;
     private final Paint mDragOutlinePaint = new Paint();
 
-    private final ClickShadowView mTouchFeedbackView;
-
     @Thunk final ArrayMap<LayoutParams, Animator> mReorderAnimators = new ArrayMap<>();
     @Thunk final ArrayMap<View, ReorderPreviewAnimation> mShakeAnimators = new ArrayMap<>();
 
@@ -285,9 +283,6 @@
         mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mCountX, mCountY);
 
         mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
-
-        mTouchFeedbackView = new ClickShadowView(context);
-        addView(mTouchFeedbackView);
         addView(mShortcutsAndWidgets);
     }
 
@@ -297,7 +292,7 @@
             ViewCompat.setAccessibilityDelegate(this, null);
             setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
             getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-            setOnClickListener(mLauncher);
+            setOnClickListener(null);
         } else {
             if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
                     !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
@@ -384,11 +379,6 @@
         return mDropPending;
     }
 
-    @Override
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        mTouchFeedbackView.setPressedIcon(icon, background);
-    }
-
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
@@ -785,13 +775,6 @@
             throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
         }
 
-        // Make the feedback view large enough to hold the blur bitmap.
-        mTouchFeedbackView.measure(
-                MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(),
-                        MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(),
-                        MeasureSpec.EXACTLY));
-
         mShortcutsAndWidgets.measure(
                 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
@@ -815,11 +798,7 @@
         int top = getPaddingTop();
         int bottom = b - t - getPaddingBottom();
 
-        mTouchFeedbackView.layout(left, top,
-                left + mTouchFeedbackView.getMeasuredWidth(),
-                top + mTouchFeedbackView.getMeasuredHeight());
         mShortcutsAndWidgets.layout(left, top, right, bottom);
-
         // Expand the background drawing bounds by the padding baked into the background drawable
         mBackground.getPadding(mTempRect);
         mBackground.setBounds(
@@ -1012,6 +991,7 @@
         }
     }
 
+    @SuppressLint("StringFormatMatches")
     public String getItemMoveDescription(int cellX, int cellY) {
         if (mContainerType == HOTSEAT) {
             return getContext().getString(R.string.move_to_hotseat_position,
@@ -2000,7 +1980,7 @@
             // Animations are disabled in power save mode, causing the repeated animation to jump
             // spastically between beginning and end states. Since this looks bad, we don't repeat
             // the animation in power save mode.
-            if (!Utilities.isPowerSaverOn(getContext())) {
+            if (!Utilities.isPowerSaverPreventingAnimation(getContext())) {
                 va.setRepeatMode(ValueAnimator.REVERSE);
                 va.setRepeatCount(ValueAnimator.INFINITE);
             }
diff --git a/src/com/android/launcher3/ClickShadowView.java b/src/com/android/launcher3/ClickShadowView.java
deleted file mode 100644
index 5391b4d..0000000
--- a/src/com/android/launcher3/ClickShadowView.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2014 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;
-
-import static com.android.launcher3.FastBitmapDrawable.CLICK_FEEDBACK_DURATION;
-import static com.android.launcher3.FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR;
-import static com.android.launcher3.LauncherAnimUtils.ELEVATION;
-import static com.android.launcher3.graphics.HolographicOutlineHelper.ADAPTIVE_ICON_SHADOW_BITMAP;
-
-import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-
-public class ClickShadowView extends View {
-
-    private static final int SHADOW_SIZE_FACTOR = 3;
-    private static final int SHADOW_LOW_ALPHA = 30;
-    private static final int SHADOW_HIGH_ALPHA = 60;
-
-    private static float sAdaptiveIconScaleFactor = 1f;
-
-    private final Paint mPaint;
-
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private final float mShadowOffset;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private final float mShadowPadding;
-
-    private Bitmap mBitmap;
-    private ObjectAnimator mAnim;
-
-    private Drawable mAdaptiveIcon;
-    private ViewOutlineProvider mOutlineProvider;
-
-    public ClickShadowView(Context context) {
-        super(context);
-        mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-        mPaint.setColor(Color.BLACK);
-
-        mShadowPadding = getResources().getDimension(R.dimen.blur_size_click_shadow);
-        mShadowOffset = getResources().getDimension(R.dimen.click_shadow_high_shift);
-    }
-
-    public static void setAdaptiveIconScaleFactor(float factor) {
-        sAdaptiveIconScaleFactor = factor;
-    }
-
-    /**
-     * @return extra space required by the view to show the shadow.
-     */
-    public int getExtraSize() {
-        return (int) (SHADOW_SIZE_FACTOR * mShadowPadding);
-    }
-
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        if (icon == null) {
-            setBitmap(null);
-            cancelAnim();
-            return;
-        }
-        if (background == null) {
-            if (mBitmap == ADAPTIVE_ICON_SHADOW_BITMAP) {
-                // clear animation shadow
-            }
-            setBitmap(null);
-            cancelAnim();
-            icon.setOutlineProvider(null);
-        } else if (setBitmap(background)) {
-            if (mBitmap == ADAPTIVE_ICON_SHADOW_BITMAP) {
-                setupAdaptiveShadow(icon);
-                cancelAnim();
-                startAnim(icon, ELEVATION,
-                        getResources().getDimension(R.dimen.click_shadow_elevation));
-            } else {
-                alignWithIconView(icon);
-                startAnim(this, ALPHA, 1);
-            }
-        }
-    }
-
-    @TargetApi(Build.VERSION_CODES.O)
-    private void setupAdaptiveShadow(final BubbleTextView view) {
-        if (mAdaptiveIcon == null) {
-            mAdaptiveIcon = new AdaptiveIconDrawable(null, null);
-            mOutlineProvider = new ViewOutlineProvider() {
-                @Override
-                public void getOutline(View view, Outline outline) {
-                    mAdaptiveIcon.getOutline(outline);
-                }
-            };
-        }
-
-        int iconWidth = view.getRight() - view.getLeft();
-        int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
-        int drawableWidth = view.getIcon().getBounds().width();
-
-        Rect bounds = new Rect();
-        bounds.left = view.getCompoundPaddingLeft() + (iconHSpace - drawableWidth) / 2;
-        bounds.right = bounds.left + drawableWidth;
-        bounds.top = view.getPaddingTop();
-        bounds.bottom = bounds.top + view.getIcon().getBounds().height();
-        Utilities.scaleRectAboutCenter(bounds, sAdaptiveIconScaleFactor);
-
-        mAdaptiveIcon.setBounds(bounds);
-        view.setOutlineProvider(mOutlineProvider);
-    }
-
-    /**
-     * Applies the new bitmap.
-     * @return true if the view was invalidated.
-     */
-    private boolean setBitmap(Bitmap b) {
-        if (b != mBitmap){
-            mBitmap = b;
-            invalidate();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mBitmap != null) {
-            mPaint.setAlpha(SHADOW_LOW_ALPHA);
-            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
-            mPaint.setAlpha(SHADOW_HIGH_ALPHA);
-            canvas.drawBitmap(mBitmap, 0, mShadowOffset, mPaint);
-        }
-    }
-
-    private void cancelAnim() {
-        if (mAnim != null) {
-            mAnim.cancel();
-            mAnim.setCurrentPlayTime(0);
-            mAnim = null;
-        }
-    }
-
-    private void startAnim(View target, Property<View, Float> property, float endValue) {
-        cancelAnim();
-        property.set(target, 0f);
-        mAnim = ObjectAnimator.ofFloat(target, property, endValue);
-        mAnim.setDuration(CLICK_FEEDBACK_DURATION)
-                .setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
-        mAnim.start();
-    }
-
-    /**
-     * Aligns the shadow with {@param view}
-     * Note: {@param view} must be a descendant of my parent.
-     */
-    private void alignWithIconView(BubbleTextView view) {
-        int[] coords = new int[] {0, 0};
-        Utilities.getDescendantCoordRelativeToAncestor(
-                (ViewGroup) view.getParent(), (View) getParent(), coords, false);
-
-        float leftShift = view.getLeft() + coords[0] - getLeft();
-        float topShift = view.getTop() + coords[1] - getTop();
-        int iconWidth = view.getRight() - view.getLeft();
-        int iconHeight = view.getBottom() - view.getTop();
-        int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
-        float drawableWidth = view.getIcon().getBounds().width();
-
-        // Set the bounds to clip against
-        int clipLeft = (int) Math.max(0, coords[0] - leftShift - mShadowPadding);
-        int clipTop = (int) Math.max(0, coords[1] - topShift - mShadowPadding) ;
-        setClipBounds(new Rect(clipLeft, clipTop, clipLeft + iconWidth, clipTop + iconHeight));
-
-        setTranslationX(leftShift
-                + view.getCompoundPaddingLeft() * view.getScaleX()
-                + (iconHSpace - drawableWidth) * view.getScaleX() / 2  /* drawable gap */
-                + iconWidth * (1 - view.getScaleX()) / 2  /* gap due to scale */
-                - mShadowPadding  /* extra shadow size */
-                );
-        setTranslationY(topShift
-                + view.getPaddingTop() * view.getScaleY()  /* drawable gap */
-                + view.getHeight() * (1 - view.getScaleY()) / 2  /* gap due to scale */
-                - mShadowPadding  /* extra shadow size */
-                );
-    }
-}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index c12ea57..64a58fb 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -24,9 +24,14 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
+import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 
 public class DeleteDropTarget extends ButtonDropTarget {
 
+    private int mControlType = ControlType.DEFAULT_CONTROLTYPE;
+
     public DeleteDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -48,13 +53,14 @@
     public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
         super.onDragStart(dragObject, options);
         setTextBasedOnDragSource(dragObject.dragInfo);
+        setControlTypeBasedOnDragSource(dragObject.dragInfo);
     }
 
     /**
      * @return true for items that should have a "Remove" action in accessibility.
      */
     @Override
-    public boolean supportsAccessibilityDrop(ItemInfo info) {
+    public boolean supportsAccessibilityDrop(ItemInfo info, View view) {
         return (info instanceof ShortcutInfo)
                 || (info instanceof LauncherAppWidgetInfo)
                 || (info instanceof FolderInfo);
@@ -82,6 +88,14 @@
         }
     }
 
+    /**
+     * Set mControlType depending on the drag item.
+     */
+    private void setControlTypeBasedOnDragSource(ItemInfo item) {
+        mControlType = item.id != ItemInfo.NO_ID ? ControlType.REMOVE_TARGET
+                : ControlType.CANCEL_TARGET;
+    }
+
     @Override
     public void completeDrop(DragObject d) {
         ItemInfo item = d.dragInfo;
@@ -103,4 +117,11 @@
         mLauncher.getDragLayer()
                 .announceForAccessibility(getContext().getString(R.string.item_removed));
     }
+
+    @Override
+    public Target getDropTargetForLogging() {
+        Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
+        t.controlType = mControlType;
+        return t;
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 950c7f7..820c125 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -25,9 +25,12 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
+import android.view.Surface;
+import android.view.WindowManager;
 
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.graphics.IconNormalizer;
 
 public class DeviceProfile {
 
@@ -41,6 +44,8 @@
 
     // Device properties in current orientation
     public final boolean isLandscape;
+    public final boolean isMultiWindowMode;
+
     public final int widthPx;
     public final int heightPx;
     public final int availableWidthPx;
@@ -65,8 +70,9 @@
     public float workspaceSpringLoadShrinkFactor;
     public final int workspaceSpringLoadedBottomSpace;
 
-    // Page indicator
-    public final int pageIndicatorSizePx;
+    // Drag handle
+    public final int verticalDragHandleSizePx;
+    private final int verticalDragHandleOverlapWorkspace;
 
     // Workspace icons
     public int iconSizePx;
@@ -79,9 +85,8 @@
     public int workspaceCellPaddingXPx;
 
     // Folder
-    public int folderBackgroundOffset;
     public int folderIconSizePx;
-    public int folderIconPreviewPadding;
+    public int folderIconOffsetYPx;
 
     // Folder cell
     public int folderCellWidthPx;
@@ -97,8 +102,10 @@
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
     public final int hotseatBarTopPaddingPx;
-    public final int hotseatBarBottomPaddingPx;
-    public final int hotseatBarSidePaddingPx;
+    public int hotseatBarBottomPaddingPx;
+    // Start is the side next to the nav bar, end is the side next to the workspace
+    public final int hotseatBarSidePaddingStartPx;
+    public final int hotseatBarSidePaddingEndPx;
 
     // All apps
     public int allAppsCellHeightPx;
@@ -115,16 +122,30 @@
     // Insets
     private final Rect mInsets = new Rect();
     public final Rect workspacePadding = new Rect();
+    private final Rect mHotseatPadding = new Rect();
+    private boolean mIsSeascape;
 
     // Icon badges
     public BadgeRenderer mBadgeRenderer;
 
     public DeviceProfile(Context context, InvariantDeviceProfile inv,
             Point minSize, Point maxSize,
-            int width, int height, boolean isLandscape) {
+            int width, int height, boolean isLandscape, boolean isMultiWindowMode) {
 
         this.inv = inv;
         this.isLandscape = isLandscape;
+        this.isMultiWindowMode = isMultiWindowMode;
+
+        // Determine sizes.
+        widthPx = width;
+        heightPx = height;
+        if (isLandscape) {
+            availableWidthPx = maxSize.x;
+            availableHeightPx = minSize.y;
+        } else {
+            availableWidthPx = minSize.x;
+            availableHeightPx = maxSize.y;
+        }
 
         Resources res = context.getResources();
         DisplayMetrics dm = res.getDisplayMetrics();
@@ -133,6 +154,8 @@
         isTablet = res.getBoolean(R.bool.is_tablet);
         isLargeTablet = res.getBoolean(R.bool.is_large_tablet);
         isPhone = !isTablet && !isLargeTablet;
+        float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
+        boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
 
         // Some more constants
         transposeLayoutWithOrientation =
@@ -153,8 +176,10 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
         cellLayoutBottomPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding);
-        pageIndicatorSizePx = res.getDimensionPixelSize(
-                R.dimen.dynamic_grid_min_page_indicator_size);
+        verticalDragHandleSizePx = res.getDimensionPixelSize(
+                R.dimen.vertical_drag_handle_size);
+        verticalDragHandleOverlapWorkspace =
+                res.getDimensionPixelSize(R.dimen.vertical_drag_handle_overlap_workspace);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
         topWorkspacePadding =
@@ -169,39 +194,33 @@
 
         hotseatBarTopPaddingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
-        hotseatBarBottomPaddingPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
-        hotseatBarSidePaddingPx =
+        hotseatBarBottomPaddingPx = (isTallDevice ? 0
+                : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding))
+                + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
+        hotseatBarSidePaddingEndPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
+        // Add a bit of space between nav bar and hotseat in multi-window vertical bar layout.
+        hotseatBarSidePaddingStartPx = isMultiWindowMode && isVerticalBarLayout()
+                ? edgeMarginPx : 0;
         hotseatBarSizePx = isVerticalBarLayout()
-                ? Utilities.pxFromDp(inv.iconSize, dm)
+                ? Utilities.pxFromDp(inv.iconSize, dm) + hotseatBarSidePaddingStartPx
+                        + hotseatBarSidePaddingEndPx
                 : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size)
                         + hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
 
-        // Determine sizes.
-        widthPx = width;
-        heightPx = height;
-        if (isLandscape) {
-            availableWidthPx = maxSize.x;
-            availableHeightPx = minSize.y;
-        } else {
-            availableWidthPx = minSize.x;
-            availableHeightPx = maxSize.y;
-        }
-
         // Calculate all of the remaining variables.
         updateAvailableDimensions(dm, res);
 
         // Now that we have all of the variables calculated, we can tune certain sizes.
-        float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
-        boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
         if (!isVerticalBarLayout() && isPhone && isTallDevice) {
             // We increase the hotseat size when there is extra space.
             // ie. For a display with a large aspect ratio, we can keep the icons on the workspace
             // in portrait mode closer together by adding more height to the hotseat.
             // Note: This calculation was created after noticing a pattern in the design spec.
-            int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx;
-            hotseatBarSizePx += extraSpace - pageIndicatorSizePx;
+            int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx * 2
+                    - verticalDragHandleSizePx;
+            hotseatBarSizePx += extraSpace;
+            hotseatBarBottomPaddingPx += extraSpace;
 
             // Recalculate the available dimensions using the new hotseat size.
             updateAvailableDimensions(dm, res);
@@ -214,7 +233,8 @@
 
     public DeviceProfile copy(Context context) {
         Point size = new Point(availableWidthPx, availableHeightPx);
-        return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape);
+        return new DeviceProfile(context, inv, size, size, widthPx, heightPx, isLandscape,
+                isMultiWindowMode);
     }
 
     public DeviceProfile getMultiWindowProfile(Context context, Point mwSize) {
@@ -226,7 +246,7 @@
         // and heightPx = availableHeightPx because Launcher uses the InvariantDeviceProfiles'
         // widthPx and heightPx values where it's needed.
         DeviceProfile profile = new DeviceProfile(context, inv, mwSize, mwSize, mwSize.x, mwSize.y,
-                isLandscape);
+                isLandscape, true);
 
         // If there isn't enough vertical cell padding with the labels displayed, hide the labels.
         float workspaceCellPaddingY = profile.getCellSize().y - profile.iconSizePx
@@ -246,6 +266,14 @@
     }
 
     /**
+     * Inverse of {@link #getMultiWindowProfile(Context, Point)}
+     * @return device profile corresponding to the current orientation in non multi-window mode.
+     */
+    public DeviceProfile getFullScreenProfile() {
+        return isLandscape ? inv.landscapeProfile : inv.portraitProfile;
+    }
+
+    /**
      * Adjusts the profile so that the labels on the Workspace are hidden.
      * It is important to call this method after the All Apps variables have been set.
      */
@@ -288,7 +316,7 @@
                 + Utilities.calculateTextHeight(iconTextSizePx);
         int cellYPadding = (getCellSize().y - cellHeightPx) / 2;
         if (iconDrawablePaddingPx > cellYPadding && !isVerticalLayout
-                && !inMultiWindowMode()) {
+                && !isMultiWindowMode) {
             // Ensures that the label is closer to its corresponding icon. This is not an issue
             // with vertical bar layout or multi-window mode since the issue is handled separately
             // with their calls to {@link #adjustToHideWorkspaceLabels}.
@@ -310,13 +338,14 @@
 
         // Hotseat
         if (isVerticalLayout) {
-            hotseatBarSizePx = iconSizePx;
+            hotseatBarSizePx = iconSizePx + hotseatBarSidePaddingStartPx
+                    + hotseatBarSidePaddingEndPx;
         }
         hotseatCellHeightPx = iconSizePx;
 
         if (!isVerticalLayout) {
             int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
-                    - pageIndicatorSizePx - topWorkspacePadding;
+                    - verticalDragHandleSizePx - topWorkspacePadding;
             float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
             workspaceSpringLoadShrinkFactor = Math.min(
                     res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
@@ -327,9 +356,8 @@
         }
 
         // Folder icon
-        folderBackgroundOffset = -iconDrawablePaddingPx;
-        folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
-        folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
+        folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx);
+        folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
     }
 
     private void updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res) {
@@ -410,17 +438,16 @@
         if (isVerticalBarLayout()) {
             padding.top = 0;
             padding.bottom = edgeMarginPx;
-            padding.left = hotseatBarSidePaddingPx;
-            padding.right = hotseatBarSidePaddingPx;
             if (isSeascape()) {
-                padding.left += hotseatBarSizePx;
-                padding.right += pageIndicatorSizePx;
+                padding.left = hotseatBarSizePx;
+                padding.right = verticalDragHandleSizePx;
             } else {
-                padding.left += pageIndicatorSizePx;
-                padding.right += hotseatBarSizePx;
+                padding.left = verticalDragHandleSizePx;
+                padding.right = hotseatBarSizePx;
             }
         } else {
-            int paddingBottom = hotseatBarSizePx + pageIndicatorSizePx;
+            int paddingBottom = hotseatBarSizePx + verticalDragHandleSizePx
+                    - verticalDragHandleOverlapWorkspace;
             if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
@@ -444,6 +471,33 @@
         }
     }
 
+    public Rect getHotseatLayoutPadding() {
+        if (isVerticalBarLayout()) {
+            if (isSeascape()) {
+                mHotseatPadding.set(mInsets.left + hotseatBarSidePaddingStartPx,
+                        mInsets.top, hotseatBarSidePaddingEndPx, mInsets.bottom);
+            } else {
+                mHotseatPadding.set(hotseatBarSidePaddingEndPx, mInsets.top,
+                        mInsets.right + hotseatBarSidePaddingStartPx, mInsets.bottom);
+            }
+        } else {
+
+            // We want the edges of the hotseat to line up with the edges of the workspace, but the
+            // icons in the hotseat are a different size, and so don't line up perfectly. To account
+            // for this, we pad the left and right of the hotseat with half of the difference of a
+            // workspace cell vs a hotseat cell.
+            float workspaceCellWidth = (float) widthPx / inv.numColumns;
+            float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons;
+            int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
+            mHotseatPadding.set(
+                    hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx,
+                    hotseatBarTopPaddingPx,
+                    hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
+                    hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
+        }
+        return mHotseatPadding;
+    }
+
     /**
      * @return the bounds for which the open folders should be contained within
      */
@@ -460,7 +514,7 @@
                     mInsets.top + dropTargetBarSizePx + edgeMarginPx,
                     mInsets.left + availableWidthPx - edgeMarginPx,
                     mInsets.top + availableHeightPx - hotseatBarSizePx
-                            - pageIndicatorSizePx - edgeMarginPx);
+                            - verticalDragHandleSizePx - edgeMarginPx);
         }
     }
 
@@ -480,9 +534,22 @@
         return isLandscape && transposeLayoutWithOrientation;
     }
 
+    /**
+     * Updates orientation information and returns true if it has changed from the previous value.
+     */
+    public boolean updateIsSeascape(WindowManager wm) {
+        if (isVerticalBarLayout()) {
+            boolean isSeascape = wm.getDefaultDisplay().getRotation() == Surface.ROTATION_270;
+            if (mIsSeascape != isSeascape) {
+                mIsSeascape = isSeascape;
+                return true;
+            }
+        }
+        return false;
+    }
+
     public boolean isSeascape() {
-        // TODO: This might not hold true for multi window mode, use configuration insead.
-        return isVerticalBarLayout() && mInsets.left > mInsets.right;
+        return isVerticalBarLayout() && mIsSeascape;
     }
 
     public boolean shouldFadeAdjacentWorkspaceScreens() {
@@ -503,16 +570,6 @@
         }
     }
 
-    public boolean inMultiWindowMode() {
-        return this != inv.landscapeProfile && this != inv.portraitProfile;
-    }
-
-    public boolean shouldIgnoreLongPressToOverview(float touchX) {
-        boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeMarginPx;
-        boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx);
-        return !inMultiWindowMode() && (touchedLhsEdge || touchedRhsEdge);
-    }
-
     private static Context getContext(Context c, int orientation) {
         Configuration context = new Configuration(c.getResources().getConfiguration());
         context.orientation = orientation;
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index a3fe89a..d025a9b 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -16,11 +16,10 @@
 
 package com.android.launcher3;
 
-import static com.android.launcher3.AlphaUpdateListener.updateVisibility;
 import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
 import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
 import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
 
 import android.animation.TimeInterpolator;
 import android.content.Context;
@@ -47,7 +46,7 @@
     protected static final TimeInterpolator DEFAULT_INTERPOLATOR = Interpolators.ACCEL;
 
     private final Runnable mFadeAnimationEndRunnable =
-            () -> updateVisibility(DropTargetBar.this, isAccessibilityEnabled(getContext()));
+            () -> updateVisibility(DropTargetBar.this);
 
     @ViewDebug.ExportedProperty(category = "launcher")
     protected boolean mDeferOnDragEnd;
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 403c8b8..4e0f2e7 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -99,6 +99,10 @@
         mShowImeAfterFirstLayout = !showSoftInput();
     }
 
+    public void hideKeyboard() {
+        UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
+    }
+
     private boolean showSoftInput() {
         return requestFocus() &&
                 ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
@@ -106,7 +110,7 @@
     }
 
     public void dispatchBackKey() {
-        UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
+        hideKeyboard();
         if (mBackKeyListener != null) {
             mBackKeyListener.onBackKey();
         }
@@ -135,6 +139,6 @@
                 nextFocus.requestFocus();
             }
         }
-        UiThreadHelper.hideKeyboardAsync(getContext(), getWindowToken());
+        hideKeyboard();
     }
 }
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index bd19dfa..7efb6ec 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -16,8 +16,9 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+
 import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -28,6 +29,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.Property;
 import android.util.SparseArray;
@@ -36,14 +38,12 @@
 
 public class FastBitmapDrawable extends Drawable {
 
-    private static final float PRESSED_BRIGHTNESS = 100f / 255f;
+    private static final float PRESSED_SCALE = 1.1f;
+
     private static final float DISABLED_DESATURATION = 1f;
     private static final float DISABLED_BRIGHTNESS = 0.5f;
 
-    public static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = (input) ->
-            (input < 0.05f) ? (input / 0.05f) : ((input < 0.3f) ? 1 : (1 - input) / 0.7f);
-
-    public static final int CLICK_FEEDBACK_DURATION = 2000;
+    public static final int CLICK_FEEDBACK_DURATION = 200;
 
     // Since we don't need 256^2 values for combinations of both the brightness and saturation, we
     // reduce the value space to a smaller value V, which reduces the number of cached
@@ -58,24 +58,29 @@
     private static final ColorMatrix sTempFilterMatrix = new ColorMatrix();
 
     protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
-    private final Bitmap mBitmap;
+    protected Bitmap mBitmap;
     protected final int mIconColor;
 
     private boolean mIsPressed;
     private boolean mIsDisabled;
 
-    private static final Property<FastBitmapDrawable, Float> BRIGHTNESS
-            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "brightness") {
+    // Animator and properties for the fast bitmap drawable's scale
+    private static final Property<FastBitmapDrawable, Float> SCALE
+            = new Property<FastBitmapDrawable, Float>(Float.TYPE, "scale") {
         @Override
         public Float get(FastBitmapDrawable fastBitmapDrawable) {
-            return fastBitmapDrawable.getBrightness();
+            return fastBitmapDrawable.mScale;
         }
 
         @Override
         public void set(FastBitmapDrawable fastBitmapDrawable, Float value) {
-            fastBitmapDrawable.setBrightness(value);
+            fastBitmapDrawable.mScale = value;
+            fastBitmapDrawable.invalidateSelf();
         }
     };
+    private ObjectAnimator mScaleAnimation;
+    private float mScale = 1;
+
 
     // The saturation and brightness are values that are mapped to REDUCED_FILTER_VALUE_SPACE and
     // as a result, can be used to compose the key for the cached ColorMatrixColorFilters
@@ -84,9 +89,6 @@
     private int mAlpha = 255;
     private int mPrevUpdateKey = Integer.MAX_VALUE;
 
-    // Animators for the fast bitmap drawable's brightness
-    private ObjectAnimator mBrightnessAnimator;
-
     public FastBitmapDrawable(Bitmap b) {
         this(b, Color.TRANSPARENT);
     }
@@ -106,8 +108,20 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
-        canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
+    public final void draw(Canvas canvas) {
+        if (mScale != 1f) {
+            int count = canvas.save();
+            Rect bounds = getBounds();
+            canvas.scale(mScale, mScale, bounds.exactCenterX(), bounds.exactCenterY());
+            drawInternal(canvas, bounds);
+            canvas.restoreToCount(count);
+        } else {
+            drawInternal(canvas, getBounds());
+        }
+    }
+
+    protected void drawInternal(Canvas canvas, Rect bounds) {
+        canvas.drawBitmap(mBitmap, null, bounds, mPaint);
     }
 
     @Override
@@ -136,6 +150,23 @@
         return mAlpha;
     }
 
+    public void setScale(float scale) {
+        if (mScaleAnimation != null) {
+            mScaleAnimation.cancel();
+            mScaleAnimation = null;
+        }
+        mScale = scale;
+        invalidateSelf();
+    }
+
+    public float getAnimatedScale() {
+        return mScaleAnimation == null ? 1 : mScale;
+    }
+
+    public float getScale() {
+        return mScale;
+    }
+
     @Override
     public int getIntrinsicWidth() {
         return mBitmap.getWidth();
@@ -156,10 +187,6 @@
         return getBounds().height();
     }
 
-    public Bitmap getBitmap() {
-        return mBitmap;
-    }
-
     @Override
     public boolean isStateful() {
         return true;
@@ -182,19 +209,20 @@
         if (mIsPressed != isPressed) {
             mIsPressed = isPressed;
 
-            if (mBrightnessAnimator != null) {
-                mBrightnessAnimator.cancel();
+            if (mScaleAnimation != null) {
+                mScaleAnimation.cancel();
+                mScaleAnimation = null;
             }
 
             if (mIsPressed) {
                 // Animate when going to pressed state
-                mBrightnessAnimator = ObjectAnimator.ofFloat(
-                        this, BRIGHTNESS, getExpectedBrightness());
-                mBrightnessAnimator.setDuration(CLICK_FEEDBACK_DURATION);
-                mBrightnessAnimator.setInterpolator(CLICK_FEEDBACK_INTERPOLATOR);
-                mBrightnessAnimator.start();
+                mScaleAnimation = ObjectAnimator.ofFloat(this, SCALE, PRESSED_SCALE);
+                mScaleAnimation.setDuration(CLICK_FEEDBACK_DURATION);
+                mScaleAnimation.setInterpolator(ACCEL);
+                mScaleAnimation.start();
             } else {
-                setBrightness(getExpectedBrightness());
+                mScale = 1f;
+                invalidateSelf();
             }
             return true;
         }
@@ -203,12 +231,7 @@
 
     private void invalidateDesaturationAndBrightness() {
         setDesaturation(mIsDisabled ? DISABLED_DESATURATION : 0);
-        setBrightness(getExpectedBrightness());
-    }
-
-    private float getExpectedBrightness() {
-        return mIsDisabled ? DISABLED_BRIGHTNESS :
-                (mIsPressed ? PRESSED_BRIGHTNESS : 0);
+        setBrightness(mIsDisabled ? DISABLED_BRIGHTNESS : 0);
     }
 
     public void setIsDisabled(boolean isDisabled) {
@@ -251,7 +274,7 @@
     /**
      * Updates the paint to reflect the current brightness and saturation.
      */
-    private void updateFilter() {
+    protected void updateFilter() {
         boolean usePorterDuffFilter = false;
         int key = -1;
         if (mDesaturation > 0) {
@@ -304,4 +327,29 @@
         }
         invalidateSelf();
     }
+
+    @Override
+    public ConstantState getConstantState() {
+        return new MyConstantState(mBitmap, mIconColor);
+    }
+
+    protected static class MyConstantState extends ConstantState {
+        protected final Bitmap mBitmap;
+        protected final int mIconColor;
+
+        public MyConstantState(Bitmap bitmap, int color) {
+            mBitmap = bitmap;
+            mIconColor = color;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new FastBitmapDrawable(mBitmap, mIconColor);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return 0;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index cea7e43..e7ca121 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -24,7 +24,8 @@
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.TraceHelper;
+
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
 
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
@@ -36,7 +37,6 @@
     private static final String TAG = "FirstFrameAnimatorHlpr";
     private static final boolean DEBUG = false;
     private static final int MAX_DELAY = 1000;
-    private static final int IDEAL_FRAME_DURATION = 16;
     private final View mTarget;
     private long mStartFrame;
     private long mStartTime = -1;
@@ -73,13 +73,7 @@
             view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
         }
 
-        TraceHelper.beginSection("TICK");
-        sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
-                public void onDraw() {
-                    sGlobalFrameCounter++;
-                    TraceHelper.partitionSection("TICK", "Frame drawn");
-                }
-            };
+        sGlobalDrawListener = () -> sGlobalFrameCounter++;
         view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
         sVisible = true;
     }
@@ -115,9 +109,9 @@
             // prevents a large jump in the animation due to an expensive first frame
             } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
                        !mAdjustedSecondFrameTime &&
-                       currentTime > mStartTime + IDEAL_FRAME_DURATION &&
-                       currentPlayTime > IDEAL_FRAME_DURATION) {
-                animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
+                       currentTime > mStartTime + SINGLE_FRAME_MS &&
+                       currentPlayTime > SINGLE_FRAME_MS) {
+                animation.setCurrentPlayTime(SINGLE_FRAME_MS);
                 mAdjustedSecondFrameTime = true;
             } else {
                 if (frameNum > 1) {
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index 1f18ea1..466b7b2 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -65,6 +65,9 @@
     }
 }
 
+/**
+ * TODO: Reevaluate if this is still required
+ */
 public class FocusHelper {
 
     private static final String TAG = "FocusHelper";
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 03043f2..6668f2c 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -63,14 +63,6 @@
         return mContent;
     }
 
-    /**
-     * Registers the specified listener on the cell layout of the hotseat.
-     */
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        mContent.setOnLongClickListener(l);
-    }
-
     /* Get the orientation invariant order of the item in the hotseat for persistence. */
     int getOrderInHotseat(int x, int y) {
         return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x;
@@ -89,12 +81,17 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContent = findViewById(R.id.layout);
-
-        resetLayout();
     }
 
-    void resetLayout() {
+    void resetLayout(boolean hasVerticalHotseat) {
         mContent.removeAllViewsInLayout();
+        mHasVerticalHotseat = hasVerticalHotseat;
+        InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
+        if (hasVerticalHotseat) {
+            mContent.setGridSize(1, idp.numHotseatIcons);
+        } else {
+            mContent.setGridSize(idp.numHotseatIcons, 1);
+        }
 
         if (!FeatureFlags.NO_ALL_APPS_ICON) {
             // Add the Apps button
@@ -115,7 +112,6 @@
             allAppsButton.setCompoundDrawables(null, d, null, null);
 
             allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
-            allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
             if (mLauncher != null) {
                 allAppsButton.setOnClickListener((v) -> {
                     if (!mLauncher.isInState(ALL_APPS)) {
@@ -156,46 +152,24 @@
     public void setInsets(Rect insets) {
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
 
-        if (mHasVerticalHotseat) {
-            mContent.setGridSize(1, grid.inv.numHotseatIcons);
-
+        if (grid.isVerticalBarLayout()) {
             lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
             if (grid.isSeascape()) {
                 lp.gravity = Gravity.LEFT;
-                lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx;
-                getLayout().setPadding(
-                        insets.left, insets.top, grid.hotseatBarSidePaddingPx, insets.bottom);
-
+                lp.width = grid.hotseatBarSizePx + insets.left;
             } else {
                 lp.gravity = Gravity.RIGHT;
-                lp.width = grid.hotseatBarSizePx + insets.right + grid.hotseatBarSidePaddingPx;
-                getLayout().setPadding(
-                        grid.hotseatBarSidePaddingPx, insets.top, insets.right, insets.bottom);
+                lp.width = grid.hotseatBarSizePx + insets.right;
             }
         } else {
-            mContent.setGridSize(grid.inv.numHotseatIcons, 1);
-
             lp.gravity = Gravity.BOTTOM;
             lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
             lp.height = grid.hotseatBarSizePx + insets.bottom;
-
-            // We want the edges of the hotseat to line up with the edges of the workspace, but the
-            // icons in the hotseat are a different size, and so don't line up perfectly. To account for
-            // this, we pad the left and right of the hotseat with half of the difference of a workspace
-            // cell vs a hotseat cell.
-            float workspaceCellWidth = (float) grid.widthPx / grid.inv.numColumns;
-            float hotseatCellWidth = (float) grid.widthPx / grid.inv.numHotseatIcons;
-            int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
-            Rect workspacePadding = grid.workspacePadding;
-
-            getLayout().setPadding(
-                    hotseatAdjustment + workspacePadding.left + grid.cellLayoutPaddingLeftRightPx,
-                    grid.hotseatBarTopPaddingPx,
-                    hotseatAdjustment + workspacePadding.right + grid.cellLayoutPaddingLeftRightPx,
-                    grid.hotseatBarBottomPaddingPx + insets.bottom + grid.cellLayoutBottomPaddingPx);
         }
+        Rect padding = grid.getHotseatLayoutPadding();
+        getLayout().setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
         setLayoutParams(lp);
         InsettableFrameLayout.dispatchInsets(this, insets);
     }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 957a5e5..f496600 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -45,12 +45,10 @@
 
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.BitmapInfo;
-import com.android.launcher3.graphics.ColorExtractor;
+import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.graphics.LauncherIcons;
 import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.Preconditions;
@@ -109,6 +107,8 @@
     private final BitmapFactory.Options mLowResOptions;
     private final BitmapFactory.Options mHighResOptions;
 
+    private int mPendingIconRequestCount = 0;
+
     public IconCache(Context context, InvariantDeviceProfile inv) {
         mContext = context;
         mPackageManager = context.getPackageManager();
@@ -126,7 +126,7 @@
         // automatically be loaded as ALPHA_8888.
         mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
 
-        if (UiFactory.USE_HARDWARE_BITMAP) {
+        if (BitmapRenderer.USE_HARDWARE_BITMAP) {
             mHighResOptions = new BitmapFactory.Options();
             mHighResOptions.inPreferredConfig = Bitmap.Config.HARDWARE;
         } else {
@@ -413,8 +413,13 @@
      */
     public IconLoadRequest updateIconInBackground(final ItemInfoUpdateReceiver caller,
             final ItemInfoWithIcon info) {
-        Runnable request = new Runnable() {
+        Preconditions.assertUIThread();
+        if (mPendingIconRequestCount <= 0) {
+            LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_FOREGROUND);
+        }
+        mPendingIconRequestCount ++;
 
+        IconLoadRequest request = new IconLoadRequest(mWorkerHandler, this::onIconRequestEnd) {
             @Override
             public void run() {
                 if (info instanceof AppInfo || info instanceof ShortcutInfo) {
@@ -422,17 +427,21 @@
                 } else if (info instanceof PackageItemInfo) {
                     getTitleAndIconForApp((PackageItemInfo) info, false);
                 }
-                mMainThreadExecutor.execute(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        caller.reapplyItemInfo(info);
-                    }
+                mMainThreadExecutor.execute(() -> {
+                    caller.reapplyItemInfo(info);
+                    onEnd();
                 });
             }
         };
-        mWorkerHandler.post(request);
-        return new IconLoadRequest(request, mWorkerHandler);
+        Utilities.postAsyncCallback(mWorkerHandler, request);
+        return request;
+    }
+
+    private void onIconRequestEnd() {
+        mPendingIconRequestCount --;
+        if (mPendingIconRequestCount <= 0) {
+            LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND);
+        }
     }
 
     /**
@@ -469,7 +478,8 @@
             info.contentDescription = "";
             info.usingLowResIcon = false;
         } else {
-            getTitleAndIcon(info, new ActivityInfoProvider(info.getIntent(), info.user),
+            Intent intent = info.getIntent();
+            getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
                     true, useLowResIcon);
         }
     }
@@ -643,11 +653,8 @@
                     // Load the full res icon for the application, but if useLowResIcon is set, then
                     // only keep the low resolution icon instead of the larger full-sized icon
                     BitmapInfo iconInfo = li.createBadgedIconBitmap(
-                            appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion);
-                    if (mInstantAppResolver.isInstantApp(appInfo)) {
-                        li.badgeWithDrawable(iconInfo.icon,
-                                mContext.getDrawable(R.drawable.ic_instant_app_badge));
-                    }
+                            appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+                            mInstantAppResolver.isInstantApp(appInfo));
                     li.recycle();
 
                     Bitmap lowResIcon =  generateLowResIcon(iconInfo.icon);
@@ -712,17 +719,27 @@
         return false;
     }
 
-    public static class IconLoadRequest {
-        private final Runnable mRunnable;
+    public static abstract class IconLoadRequest implements Runnable {
         private final Handler mHandler;
+        private final Runnable mEndRunnable;
 
-        IconLoadRequest(Runnable runnable, Handler handler) {
-            mRunnable = runnable;
+        private boolean mEnded = false;
+
+        IconLoadRequest(Handler handler, Runnable endRunnable) {
             mHandler = handler;
+            mEndRunnable = endRunnable;
         }
 
         public void cancel() {
-            mHandler.removeCallbacks(mRunnable);
+            mHandler.removeCallbacks(this);
+            onEnd();
+        }
+
+        public void onEnd() {
+            if (!mEnded) {
+                mEnded = true;
+                mEndRunnable.run();
+            }
         }
     }
 
@@ -785,7 +802,7 @@
     }
 
     private static final class IconDB extends SQLiteCacheHelper {
-        private final static int RELEASE_VERSION = 20;
+        private final static int RELEASE_VERSION = 24;
 
         private final static String TABLE_NAME = "icons";
         private final static String COLUMN_ROWID = "rowid";
@@ -853,22 +870,6 @@
         }
     }
 
-    private class ActivityInfoProvider extends Provider<LauncherActivityInfo> {
-
-        private final Intent mIntent;
-        private final UserHandle mUser;
-
-        public ActivityInfoProvider(Intent intent, UserHandle user) {
-            mIntent = intent;
-            mUser = user;
-        }
-
-        @Override
-        public LauncherActivityInfo get() {
-            return mLauncherApps.resolveActivity(mIntent, mUser);
-        }
-    }
-
     /**
      * Interface for receiving itemInfo with high-res icon.
      */
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index b469a8f..ed8d03c 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -5,14 +5,16 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 
+import com.android.launcher3.util.ResourceBasedOverride;
+
 import java.util.Locale;
 
-public class IconProvider {
+public class IconProvider implements ResourceBasedOverride {
 
     protected String mSystemState;
 
     public static IconProvider newInstance(Context context) {
-        IconProvider provider = Utilities.getOverrideObject(
+        IconProvider provider = Overrides.getObject(
                 IconProvider.class, context, R.string.icon_provider_class);
         provider.updateSystemStateString(context);
         return provider;
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
deleted file mode 100644
index e52fd76..0000000
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2011 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;
-
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
-import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.util.Themes;
-
-public class InfoDropTarget extends UninstallDropTarget {
-
-    private static final String TAG = "InfoDropTarget";
-
-    public InfoDropTarget(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public InfoDropTarget(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    @Override
-    protected void setupUi() {
-        // Get the hover color
-        mHoverColor = Themes.getColorAccent(getContext());
-        setDrawable(R.drawable.ic_info_shadow);
-    }
-
-    @Override
-    protected ComponentName performDropAction(ItemInfo item) {
-        return performDropAction(mLauncher, item, null, null);
-    }
-
-    /**
-     * @return Whether the activity was started.
-     */
-    public static boolean startDetailsActivityForInfo(
-            ItemInfo info, Launcher launcher, Rect sourceBounds, Bundle opts) {
-        return performDropAction(launcher, info, sourceBounds, opts) != null;
-    }
-
-    /**
-     * Performs the drop action and returns the target component for the dragObject or null if
-     * the action was not performed.
-     */
-    private static ComponentName performDropAction(Context context, ItemInfo info,
-            Rect sourceBounds, Bundle opts) {
-        if (info instanceof PromiseAppInfo) {
-            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
-            context.startActivity(promiseAppInfo.getMarketIntent(context));
-            return null;
-        }
-        ComponentName componentName = null;
-        if (info instanceof AppInfo) {
-            componentName = ((AppInfo) info).componentName;
-        } else if (info instanceof ShortcutInfo) {
-            componentName = info.getTargetComponent();
-        } else if (info instanceof PendingAddItemInfo) {
-            componentName = ((PendingAddItemInfo) info).componentName;
-        } else if (info instanceof LauncherAppWidgetInfo) {
-            componentName = ((LauncherAppWidgetInfo) info).providerName;
-        }
-        if (componentName != null) {
-            try {
-                LauncherAppsCompat.getInstance(context)
-                        .showAppDetailsForProfile(componentName, info.user, sourceBounds, opts);
-                return componentName;
-            } catch (SecurityException | ActivityNotFoundException e) {
-                Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-                Log.e(TAG, "Unable to launch settings", e);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public int getAccessibilityAction() {
-        return LauncherAccessibilityDelegate.INFO;
-    }
-
-    @Override
-    protected boolean supportsDrop(ItemInfo info) {
-        // Only show the App Info drop target if developer settings are enabled.
-        boolean developmentSettingsEnabled = Settings.Global.getInt(
-                getContext().getContentResolver(),
-                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
-        if (!developmentSettingsEnabled) {
-            return false;
-        }
-        return info.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT &&
-                (info instanceof AppInfo ||
-                (info instanceof ShortcutInfo && !((ShortcutInfo) info).isPromise()) ||
-                (info instanceof LauncherAppWidgetInfo &&
-                        ((LauncherAppWidgetInfo) info).restoreStatus == 0) ||
-                info instanceof PendingAddItemInfo);
-    }
-}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index fe8a841..b9d45fb 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -47,7 +47,6 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.Thunk;
 
 import org.json.JSONException;
@@ -486,13 +485,10 @@
                 if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
                     app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
                 } else {
-                    app.getModel().updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
-                        @Override
-                        public ShortcutInfo get() {
-                            app.getIconCache().getTitleAndIcon(
-                                    si, activityInfo, false /* useLowResIcon */);
-                            return si;
-                        }
+                    app.getModel().updateAndBindShortcutInfo(() -> {
+                        app.getIconCache().getTitleAndIcon(
+                                si, activityInfo, false /* useLowResIcon */);
+                        return si;
                     });
                 }
                 return Pair.create((ItemInfo) si, (Object) activityInfo);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 246fa74..22bc162 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -22,12 +22,15 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Point;
+import android.support.annotation.VisibleForTesting;
 import android.util.DisplayMetrics;
 import android.util.Xml;
 import android.view.Display;
 import android.view.WindowManager;
 
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -40,8 +43,12 @@
 
 public class InvariantDeviceProfile {
 
-    // This is a static that we use for the default icon size on a 4/5-inch phone
-    private static float DEFAULT_ICON_SIZE_DP = 60;
+    // We do not need any synchronization for this variable as its only written on UI thread.
+    public static final MainThreadInitializedObject<InvariantDeviceProfile> INSTANCE =
+            new MainThreadInitializedObject<>((c) -> {
+                new ConfigMonitor(c).register();
+                return new InvariantDeviceProfile(c);
+            });
 
     private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
 
@@ -88,17 +95,18 @@
 
     public Point defaultWallpaperSize;
 
+    @VisibleForTesting
     public InvariantDeviceProfile() {
     }
 
-    public InvariantDeviceProfile(InvariantDeviceProfile p) {
+    private InvariantDeviceProfile(InvariantDeviceProfile p) {
         this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
                 p.numFolderRows, p.numFolderColumns,
                 p.iconSize, p.landscapeIconSize, p.iconTextSize, p.numHotseatIcons,
                 p.defaultLayoutId, p.demoModeLayoutId);
     }
 
-    InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
+    private InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc,
             float is, float lis, float its, int hs, int dlId, int dmlId) {
         name = n;
         minWidthDps = w;
@@ -116,7 +124,7 @@
     }
 
     @TargetApi(23)
-    InvariantDeviceProfile(Context context) {
+    private InvariantDeviceProfile(Context context) {
         WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         Display display = wm.getDefaultDisplay();
         DisplayMetrics dm = new DisplayMetrics();
@@ -162,9 +170,9 @@
         int largeSide = Math.max(realSize.x, realSize.y);
 
         landscapeProfile = new DeviceProfile(context, this, smallestSize, largestSize,
-                largeSide, smallSide, true /* isLandscape */);
+                largeSide, smallSide, true /* isLandscape */, false /* isMultiWindowMode */);
         portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize,
-                smallSide, largeSide, false /* isLandscape */);
+                smallSide, largeSide, false /* isLandscape */, false /* isMultiWindowMode */);
 
         // We need to ensure that there is enough extra space in the wallpaper
         // for the intended parallax effects
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
index bf985c3..4677d31 100644
--- a/src/com/android/launcher3/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -91,6 +91,11 @@
     public static final int FLAG_ADAPTIVE_ICON = 1 << 8;
 
     /**
+     * Flag indicating that the icon is badged.
+     */
+    public static final int FLAG_ICON_BADGED = 1 << 9;
+
+    /**
      * Status associated with the system state of the underlying item. This is calculated every
      * time a new info is created and not persisted on the disk.
      */
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b4093b7..44d3d53 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -16,30 +16,24 @@
 
 package com.android.launcher3;
 
+import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newTarget;
 
-import android.Manifest;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
-import android.app.AlertDialog;
+import android.app.ActivityOptions;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.content.ActivityNotFoundException;
@@ -47,21 +41,18 @@
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.ContextWrapper;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.StrictMode;
@@ -71,50 +62,46 @@
 import android.text.method.TextKeyListener;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.ActionMode;
 import android.view.Display;
-import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
 import android.view.LayoutInflater;
 import android.view.Menu;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.OvershootInterpolator;
 import android.widget.Toast;
 
 import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.badge.BadgeInfo;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.LauncherAppsCompatVO;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.folder.FolderIconPreviewVerifier;
 import com.android.launcher3.keyboard.CustomActionsPopup;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.logging.UserEventDispatcher.UserEventDelegate;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.states.InternalStateHandler;
+import com.android.launcher3.states.RotationHelper;
+import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -124,6 +111,8 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.MultiHashMap;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.PendingRequestArgs;
@@ -133,6 +122,7 @@
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -154,10 +144,8 @@
 /**
  * Default launcher application.
  */
-public class Launcher extends BaseActivity
-        implements LauncherExterns, View.OnClickListener, OnLongClickListener,
-                   LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
-                   WallpaperColorInfo.OnThemeChangeListener {
+public class Launcher extends BaseDraggingActivity implements LauncherExterns,
+        LauncherModel.Callbacks, LauncherProviderChangeListener, UserEventDelegate{
     public static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
@@ -167,11 +155,10 @@
     private static final int REQUEST_CREATE_APPWIDGET = 5;
 
     private static final int REQUEST_PICK_APPWIDGET = 9;
-    private static final int REQUEST_PICK_WALLPAPER = 10;
 
     private static final int REQUEST_BIND_APPWIDGET = 11;
-    private static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
-    private static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+    public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
+    public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
 
     private static final int REQUEST_PERMISSION_CALL_PHONE = 14;
 
@@ -183,10 +170,6 @@
      */
     protected static final int REQUEST_LAST = 100;
 
-    // The Intent extra that defines whether to ignore the launch animation
-    static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
-            "com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
-
     // Type: int
     private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen";
     // Type: int
@@ -198,14 +181,8 @@
     // Type: SparseArray<Parcelable>
     private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
 
-    // When starting an action mode, setting this tag will cause the action mode to be cancelled
-    // automatically when user interacts with the launcher.
-    public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
-
     private LauncherStateManager mStateManager;
 
-    private boolean mIsSafeModeEnabled;
-
     private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
 
     // How long to wait before the new-shortcut animation automatically pans the workspace
@@ -227,6 +204,7 @@
     private final int[] mTmpAddItemCellCoordinates = new int[2];
 
     @Thunk Hotseat mHotseat;
+    @Nullable private View mHotseatSearchBox;
 
     private DropTargetBar mDropTargetBar;
 
@@ -235,7 +213,7 @@
     AllAppsTransitionController mAllAppsController;
 
     // UI and state for the overview panel
-    private ViewGroup mOverviewPanel;
+    private View mOverviewPanel;
 
     @Thunk boolean mWorkspaceLoading = true;
 
@@ -248,9 +226,6 @@
     private IconCache mIconCache;
     private LauncherAccessibilityDelegate mAccessibilityDelegate;
 
-    private ObjectAnimator mScrimAnimator;
-    private boolean mShouldFadeInScrim;
-
     private PopupDataProvider mPopupDataProvider;
 
     private int mSynchronouslyBoundPage = PagedView.INVALID_PAGE;
@@ -267,14 +242,13 @@
      */
     private PendingRequestArgs mPendingRequestArgs;
 
-    private final PointF mLastDispatchTouchEvent = new PointF();
-
     public ViewGroupFocusHelper mFocusHandler;
-    private boolean mRotationEnabled = false;
-    private boolean mAppLaunchSuccess;
 
-    private RotationPrefChangeHandler mRotationPrefChangeHandler;
-    private ActionMode mCurrentActionMode;
+    private RotationHelper mRotationHelper;
+
+
+    private final Handler mHandler = new Handler();
+    private final Runnable mLogOnDelayedResume = this::logOnDelayedResume;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -294,27 +268,22 @@
         }
         TraceHelper.beginSection("Launcher-onCreate");
 
-        WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
-        wallpaperColorInfo.setOnThemeChangeListener(this);
-        overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText());
-
         super.onCreate(savedInstanceState);
         TraceHelper.partitionSection("Launcher-onCreate", "super call");
 
         LauncherAppState app = LauncherAppState.getInstance(this);
         mOldConfig = new Configuration(getResources().getConfiguration());
+        mModel = app.setLauncher(this);
         initDeviceProfile(app.getInvariantDeviceProfile());
 
         mSharedPrefs = Utilities.getPrefs(this);
-        mIsSafeModeEnabled = getPackageManager().isSafeMode();
-        mModel = app.setLauncher(this);
-        mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
         mIconCache = app.getIconCache();
         mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
 
         mDragController = new DragController(this);
         mAllAppsController = new AllAppsTransitionController(this);
         mStateManager = new LauncherStateManager(this);
+        UiFactory.onCreate(this);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
 
@@ -326,20 +295,11 @@
         setupViews();
         mPopupDataProvider = new PopupDataProvider(this);
 
-        mRotationEnabled = getResources().getBoolean(R.bool.allow_rotation);
-        // In case we are on a device with locked rotation, we should look at preferences to check
-        // if the user has specifically allowed rotation.
-        if (!mRotationEnabled) {
-            mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext());
-            mRotationPrefChangeHandler = new RotationPrefChangeHandler();
-            mSharedPrefs.registerOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
-        }
+        mRotationHelper = new RotationHelper(this);
+        mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
 
         boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent());
         if (internalStateHandled) {
-            // Temporarily enable the rotation
-            mRotationEnabled = true;
-
             if (savedInstanceState != null) {
                 // InternalStateHandler has already set the appropriate state.
                 // We dont need to do anything.
@@ -359,7 +319,7 @@
             if (!internalStateHandled) {
                 // If we are not binding synchronously, show a fade in animation when
                 // the first page bind completes.
-                mDragLayer.setAlpha(0);
+                mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD).setValue(0);
             }
         } else {
             // Pages bound synchronously.
@@ -371,59 +331,68 @@
         // For handling default keys
         setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
 
-        updateRequestedOrientation();
         setContentView(mLauncherView);
         getRootView().dispatchInsets();
 
         // Listen for broadcasts
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
-        registerReceiver(mReceiver, filter);
-        mShouldFadeInScrim = true;
+        registerReceiver(mScreenOffReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
 
         getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
                 Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
 
-        mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
-
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
         }
+        mRotationHelper.initialize();
 
         TraceHelper.endSection("Launcher-onCreate");
     }
 
-    public void updateRequestedOrientation() {
-        // On large interfaces, or on devices that a user has specifically enabled screen rotation,
-        // we want the screen to auto-rotate based on the current orientation
-        setRequestedOrientation(mRotationEnabled
-                ? SCREEN_ORIENTATION_UNSPECIFIED : SCREEN_ORIENTATION_NOSENSOR);
+    @Override
+    public void onEnterAnimationComplete() {
+        super.onEnterAnimationComplete();
+        UiFactory.onEnterAnimationComplete(this);
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         int diff = newConfig.diff(mOldConfig);
+
+        if ((diff & CONFIG_LOCALE) != 0) {
+            Folder.setLocaleDependentFields(getResources(), true /* force */);
+        }
+
         if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
             mUserEventDispatcher = null;
             initDeviceProfile(mDeviceProfile.inv);
             dispatchDeviceProfileChanged();
-
-            getRootView().dispatchInsets();
-            getStateManager().reapplyState();
+            reapplyUi();
+            mDragLayer.recreateControllers();
 
             // TODO: We can probably avoid rebind when only screen size changed.
-            int currentPage = mWorkspace.getNextPage();
-            if (mModel.startLoader(currentPage)) {
-                mWorkspace.setCurrentPage(currentPage);
-                setWorkspaceLoading(true);
-            }
+            rebindModel();
         }
 
         mOldConfig.setTo(newConfig);
+        UiFactory.onLauncherStateOrResumeChanged(this);
         super.onConfigurationChanged(newConfig);
     }
 
+    @Override
+    protected void reapplyUi() {
+        getRootView().dispatchInsets();
+        getStateManager().reapplyState(true /* cancelCurrentAnimation */);
+    }
+
+    @Override
+    public void rebindModel() {
+        int currentPage = mWorkspace.getNextPage();
+        if (mModel.startLoader(currentPage)) {
+            mWorkspace.setCurrentPage(currentPage);
+            setWorkspaceLoading(true);
+        }
+    }
+
     private void initDeviceProfile(InvariantDeviceProfile idp) {
         // Load configuration-specific DeviceProfile
         mDeviceProfile = idp.getDeviceProfile(this);
@@ -433,29 +402,18 @@
             display.getSize(mwSize);
             mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
         }
+        onDeviceProfileInitiated();
+        mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout(), true);
     }
 
-    @Override
-    public void onThemeChanged() {
-        recreate();
+    public RotationHelper getRotationHelper() {
+        return mRotationHelper;
     }
 
     public LauncherStateManager getStateManager() {
         return mStateManager;
     }
 
-    public LauncherAppTransitionManager getAppTransitionManager() {
-        return mAppTransitionManager;
-    }
-
-    protected void overrideTheme(boolean isDark, boolean supportsDarkText) {
-        if (isDark) {
-            setTheme(R.style.LauncherThemeDark);
-        } else if (supportsDarkText) {
-            setTheme(R.style.LauncherThemeDarkText);
-        }
-    }
-
     @Override
     public <T extends View> T findViewById(int id) {
         return mLauncherView.findViewById(id);
@@ -510,6 +468,22 @@
         return mPopupDataProvider;
     }
 
+    @Override
+    public BadgeInfo getBadgeInfoForItem(ItemInfo info) {
+        return mPopupDataProvider.getBadgeInfoForItem(info);
+    }
+
+    @Override
+    public void invalidateParent(ItemInfo info) {
+        FolderIconPreviewVerifier verifier = new FolderIconPreviewVerifier(getDeviceProfile().inv);
+        if (verifier.isItemInPreview(info.rank) && (info.container >= 0)) {
+            View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
+            if (folderIcon != null) {
+                folderIcon.invalidate();
+            }
+        }
+    }
+
     /**
      * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
      * a configuration step, this allows the proper animations to run after other transitions.
@@ -593,14 +567,6 @@
                         ON_ACTIVITY_RESULT_ANIMATION_DELAY);
             }
             return;
-        } else if (requestCode == REQUEST_PICK_WALLPAPER) {
-            if (resultCode == RESULT_OK && isInState(OVERVIEW)) {
-                // User could have free-scrolled between pages before picking a wallpaper; make sure
-                // we move to the closest one now.
-                mWorkspace.setCurrentPage(mWorkspace.getPageNearestToCenterOfScreen());
-                mStateManager.goToState(NORMAL, false);
-            }
-            return;
         }
 
         boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
@@ -779,14 +745,18 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onStop();
         }
+        getUserEventDispatcher().logActionCommand(Action.Command.STOP,
+                mStateManager.getState().containerType, -1);
+
         mAppWidgetHost.setListenIfResumed(false);
 
-        if (!mAppLaunchSuccess) {
-            getUserEventDispatcher().logActionCommand(Action.Command.STOP,
-                    mStateManager.getState().containerType);
-        }
         NotificationListener.removeNotificationsChangedListener();
         getStateManager().moveToRestState();
+
+        UiFactory.onLauncherStateOrResumeChanged(this);
+
+        // Workaround for b/78520668, explicitly trim memory once UI is hidden
+        onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
     }
 
     @Override
@@ -799,25 +769,15 @@
         }
         mAppWidgetHost.setListenIfResumed(true);
         NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
+        UiFactory.onStart(this);
+    }
 
-        if (mShouldFadeInScrim && mLauncherView.getBackground() != null) {
-            if (mScrimAnimator != null) {
-                mScrimAnimator.cancel();
-            }
-            mLauncherView.getBackground().setAlpha(0);
-            mScrimAnimator = ObjectAnimator.ofInt(mLauncherView.getBackground(),
-                    LauncherAnimUtils.DRAWABLE_ALPHA, 0, 255);
-            mScrimAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mScrimAnimator = null;
-                }
-            });
-            mScrimAnimator.setDuration(600);
-            mScrimAnimator.setStartDelay(getWindow().getTransitionBackgroundFadeDuration());
-            mScrimAnimator.start();
+    private void logOnDelayedResume() {
+        if (hasBeenResumed()) {
+            getUserEventDispatcher().logActionCommand(Action.Command.RESUME,
+                    mStateManager.getState().containerType, -1);
+            getUserEventDispatcher().startSession();
         }
-        mShouldFadeInScrim = false;
     }
 
     @Override
@@ -826,8 +786,9 @@
         super.onResume();
         TraceHelper.partitionSection("ON_RESUME", "superCall");
 
-        mAppLaunchSuccess = false;
-        getUserEventDispatcher().resetElapsedSessionMillis();
+        mHandler.removeCallbacks(mLogOnDelayedResume);
+        Utilities.postAsyncCallback(mHandler, mLogOnDelayedResume);
+
         setOnResumeCallback(null);
         // Process any items that were added while Launcher was away.
         InstallShortcutReceiver.disableAndFlushInstallQueue(
@@ -836,10 +797,11 @@
         // Refresh shortcuts if the permission changed.
         mModel.refreshShortcutsIfRequired();
 
-        DiscoveryBounce.showIfNeeded(this);
+        DiscoveryBounce.showForHomeIfNeeded(this);
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onResume();
         }
+        UiFactory.onLauncherStateOrResumeChanged(this);
 
         TraceHelper.endSection("ON_RESUME");
     }
@@ -859,6 +821,12 @@
     }
 
     @Override
+    protected void onUserLeaveHint() {
+        super.onUserLeaveHint();
+        UiFactory.onLauncherStateOrResumeChanged(this);
+    }
+
+    @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
         mStateManager.onWindowFocusChanged();
@@ -957,23 +925,17 @@
         mWorkspace = mDragLayer.findViewById(R.id.workspace);
         mWorkspace.initParentViews(mDragLayer);
         mOverviewPanel = findViewById(R.id.overview_panel);
+        mHotseat = findViewById(R.id.hotseat);
+        mHotseatSearchBox = findViewById(R.id.search_container_hotseat);
 
         mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
 
         // Setup the drag layer
-        mDragLayer.setup(this, mDragController);
+        mDragLayer.setup(mDragController, mWorkspace);
+        UiFactory.setOnTouchControllersChangedListener(this, mDragLayer::recreateControllers);
 
-        // Setup the hotseat
-        mHotseat = (Hotseat) findViewById(R.id.hotseat);
-        if (mHotseat != null) {
-            mHotseat.setOnLongClickListener(this);
-        }
-
-        // Setup the workspace
-        mWorkspace.setHapticFeedbackEnabled(false);
-        mWorkspace.setOnLongClickListener(this);
         mWorkspace.setup(mDragController);
         // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the
         // default state, otherwise we will update to the wrong offsets in RTL
@@ -991,7 +953,7 @@
         mDragController.setMoveTarget(mWorkspace);
         mDropTargetBar.setup(mDragController);
 
-        mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
+        mAllAppsController.setupViews(mAppsView);
     }
 
     /**
@@ -1015,7 +977,7 @@
         BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.app_icon, parent, false);
         favorite.applyFromShortcutInfo(info);
-        favorite.setOnClickListener(this);
+        favorite.setOnClickListener(ItemClickHandler.INSTANCE);
         favorite.setOnFocusChangeListener(mFocusHandler);
         return favorite;
     }
@@ -1102,12 +1064,7 @@
     }
 
     public FolderIcon findFolderIcon(final long folderIconId) {
-        return (FolderIcon) mWorkspace.getFirstMatch(new ItemOperator() {
-            @Override
-            public boolean evaluate(ItemInfo info, View view) {
-                return info != null && info.id == folderIconId;
-            }
-        });
+        return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId);
     }
 
     /**
@@ -1149,21 +1106,13 @@
         hostView.setOnFocusChangeListener(mFocusHandler);
     }
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                // Reset AllApps to its initial state only if we are not in the middle of
-                // processing a multi-step drop
-                if (mAppsView != null && mPendingRequestArgs == null) {
-                    mStateManager.goToState(NORMAL);
-                }
-                mShouldFadeInScrim = true;
-            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                // ACTION_USER_PRESENT is sent after onStart/onResume. This covers the case where
-                // the user unlocked and the Launcher is not in the foreground.
-                mShouldFadeInScrim = false;
+            // Reset AllApps to its initial state only if we are not in the middle of
+            // processing a multi-step drop
+            if (mPendingRequestArgs == null) {
+                mStateManager.goToState(NORMAL);
             }
         }
     };
@@ -1197,20 +1146,16 @@
         }
     }
 
-    public void onQuickstepGestureStarted(boolean isVisible) {
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onQuickstepGestureStarted(isVisible);
-        }
-    }
-
     public AllAppsTransitionController getAllAppsController() {
         return mAllAppsController;
     }
 
+    @Override
     public LauncherRootView getRootView() {
         return (LauncherRootView) mLauncherView;
     }
 
+    @Override
     public DragLayer getDragLayer() {
         return mDragLayer;
     }
@@ -1227,7 +1172,11 @@
         return mHotseat;
     }
 
-    public <T extends ViewGroup> T getOverviewPanel() {
+    public View getHotseatSearchBox() {
+        return mHotseatSearchBox;
+    }
+
+    public <T extends View> T getOverviewPanel() {
         return (T) mOverviewPanel;
     }
 
@@ -1280,17 +1229,22 @@
                 } else if (alreadyOnHome) {
                     Target target = newContainerTarget(mStateManager.getState().containerType);
                     target.pageIndex = mWorkspace.getCurrentPage();
-                    ued.logActionCommand(Action.Command.HOME_INTENT, target);
+                    ued.logActionCommand(Action.Command.HOME_INTENT, target,
+                            newContainerTarget(ContainerType.WORKSPACE));
                 }
 
                 // In all these cases, only animate if we're already on home
                 AbstractFloatingView.closeAllOpenViews(this, isStarted());
 
-                mStateManager.goToState(NORMAL);
+                if (!isInState(NORMAL)) {
+                    // Only change state, if not already the same. This prevents cancelling any
+                    // animations running as part of resume
+                    mStateManager.goToState(NORMAL);
+                }
 
                 // Reset the apps view
-                if (!alreadyOnHome && mAppsView != null) {
-                    mAppsView.reset();
+                if (!alreadyOnHome) {
+                    mAppsView.reset(isStarted() /* animate */);
                 }
 
                 if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
@@ -1304,7 +1258,7 @@
             }
 
             if (mLauncherCallbacks != null) {
-                mLauncherCallbacks.onHomeIntent();
+                mLauncherCallbacks.onHomeIntent(internalStateHandled);
             }
         }
 
@@ -1358,9 +1312,11 @@
     public void onDestroy() {
         super.onDestroy();
 
-        unregisterReceiver(mReceiver);
+        unregisterReceiver(mScreenOffReceiver);
         mWorkspace.removeFolderListeners();
 
+        UiFactory.setOnTouchControllersChangedListener(this, null);
+
         // Stop callbacks from LauncherModel
         // It's possible to receive onDestroy after a new Launcher activity has
         // been created. In this case, don't interfere with the new Launcher.
@@ -1368,10 +1324,7 @@
             mModel.stopLoader();
             LauncherAppState.getInstance(this).setLauncher(null);
         }
-
-        if (mRotationPrefChangeHandler != null) {
-            mSharedPrefs.unregisterOnSharedPreferenceChangeListener(mRotationPrefChangeHandler);
-        }
+        mRotationHelper.destroy();
 
         try {
             mAppWidgetHost.stopListening();
@@ -1380,7 +1333,6 @@
         }
 
         TextKeyListener.getInstance().release();
-        WallpaperColorInfo.getInstance(this).setOnThemeChangeListener(null);
 
         LauncherAnimUtils.onDestroyActivity();
 
@@ -1652,11 +1604,12 @@
         // by using if-else statements.
         UserEventDispatcher ued = getUserEventDispatcher();
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
-        if (topView != null) {
-            topView.onBackPressed();
+        if (topView != null && topView.onBackPressed()) {
+            // Handled by the floating view.
         } else if (!isInState(NORMAL)) {
             LauncherState lastState = mStateManager.getLastState();
-            ued.logActionCommand(Action.Command.BACK, mStateManager.getState().containerType);
+            ued.logActionCommand(Action.Command.BACK, mStateManager.getState().containerType,
+                    lastState.containerType);
             mStateManager.goToState(lastState);
         } else {
             // Back button is a no-op here, but give at least some feedback for the button press
@@ -1664,458 +1617,67 @@
         }
     }
 
-    /**
-     * Launches the intent referred by the clicked shortcut.
-     *
-     * @param v The view representing the clicked shortcut.
-     */
-    public void onClick(View v) {
-        // Make sure that rogue clicks don't get through while allapps is launching, or after the
-        // view has detached (it's possible for this to happen if the view is removed mid touch).
-        if (v.getWindowToken() == null) {
-            return;
-        }
-
-        if (!mWorkspace.isFinishedSwitchingState()) {
-            return;
-        }
-
-        if (v instanceof Workspace) {
-            if (isInState(OVERVIEW)) {
-                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
-                        LauncherLogProto.Action.Direction.NONE,
-                        LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
-                mStateManager.goToState(NORMAL);
-            }
-            return;
-        }
-
-        if (v instanceof CellLayout) {
-            if (isInState(OVERVIEW)) {
-                int page = mWorkspace.indexOfChild(v);
-                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
-                        LauncherLogProto.Action.Direction.NONE,
-                        LauncherLogProto.ContainerType.OVERVIEW, page);
-                mWorkspace.snapToPageFromOverView(page);
-                mStateManager.goToState(NORMAL);
-            }
-            return;
-        }
-
-        Object tag = v.getTag();
-        if (tag instanceof ShortcutInfo) {
-            onClickAppShortcut(v);
-        } else if (tag instanceof FolderInfo) {
-            if (v instanceof FolderIcon) {
-                onClickFolderIcon(v);
-            }
-        } else if (tag instanceof AppInfo) {
-            startAppShortcutOrInfoActivity(v);
-        } else if (tag instanceof LauncherAppWidgetInfo) {
-            if (v instanceof PendingAppWidgetHostView) {
-                onClickPendingWidget((PendingAppWidgetHostView) v);
-            }
-        }
+    @TargetApi(Build.VERSION_CODES.M)
+    @Override
+    public ActivityOptions getActivityLaunchOptions(View v) {
+        return mAppTransitionManager.getActivityLaunchOptions(this, v);
     }
 
-    @SuppressLint("ClickableViewAccessibility")
-    public boolean onTouch(View v, MotionEvent event) {
-        return false;
-    }
-
-    /**
-     * Event handler for the app widget view which has not fully restored.
-     */
-    public void onClickPendingWidget(final PendingAppWidgetHostView v) {
-        if (mIsSafeModeEnabled) {
-            Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
-            return;
-        }
-
-        final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
-        if (v.isReadyForClickSetup()) {
-            LauncherAppWidgetProviderInfo appWidgetInfo =
-                    mAppWidgetManager.findProvider(info.providerName, info.user);
-            if (appWidgetInfo == null) {
-                return;
-            }
-            WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
-
-            if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
-                if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
-                    // This should not happen, as we make sure that an Id is allocated during bind.
-                    return;
-                }
-                addFlowHandler.startBindFlow(this, info.appWidgetId, info,
-                        REQUEST_BIND_PENDING_APPWIDGET);
-            } else {
-                addFlowHandler.startConfigActivity(this, info, REQUEST_RECONFIGURE_APPWIDGET);
-            }
-        } else {
-            final String packageName = info.providerName.getPackageName();
-            onClickPendingAppItem(v, packageName, info.installProgress >= 0);
-        }
-    }
-
-    private void onClickPendingAppItem(final View v, final String packageName,
-            boolean downloadStarted) {
-        if (downloadStarted) {
-            // If the download has started, simply direct to the market app.
-            startMarketIntentForPackage(v, packageName);
-            return;
-        }
-        new AlertDialog.Builder(this)
-            .setTitle(R.string.abandoned_promises_title)
-            .setMessage(R.string.abandoned_promise_explanation)
-            .setPositiveButton(R.string.abandoned_search, new DialogInterface.OnClickListener() {
-                @Override
-                public void onClick(DialogInterface dialogInterface, int i) {
-                    startMarketIntentForPackage(v, packageName);
-                }
-            })
-            .setNeutralButton(R.string.abandoned_clean_this,
-                new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int id) {
-                        final UserHandle user = Process.myUserHandle();
-                        mWorkspace.removeAbandonedPromise(packageName, user);
-                    }
-                })
-            .create().show();
-    }
-
-    private void startMarketIntentForPackage(View v, String packageName) {
-        ItemInfo item = (ItemInfo) v.getTag();
-        Intent intent = new PackageManagerHelper(v.getContext()).getMarketIntent(packageName);
-        startActivitySafely(v, intent, item);
-    }
-
-    /**
-     * Event handler for an app shortcut click.
-     *
-     * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
-     */
-    protected void onClickAppShortcut(final View v) {
-        if (LOGD) Log.d(TAG, "onClickAppShortcut");
-        Object tag = v.getTag();
-        if (!(tag instanceof ShortcutInfo)) {
-            throw new IllegalArgumentException("Input must be a Shortcut");
-        }
-
-        // Open shortcut
-        final ShortcutInfo shortcut = (ShortcutInfo) tag;
-
-        if (shortcut.isDisabled()) {
-            final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
-            if ((disabledFlags &
-                    ~FLAG_DISABLED_SUSPENDED &
-                    ~FLAG_DISABLED_QUIET_USER) == 0) {
-                // If the app is only disabled because of the above flags, launch activity anyway.
-                // Framework will tell the user why the app is suspended.
-            } else {
-                if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
-                    // Use a message specific to this shortcut, if it has one.
-                    Toast.makeText(this, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
-                    return;
-                }
-                // Otherwise just use a generic error message.
-                int error = R.string.activity_not_available;
-                if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) {
-                    error = R.string.safemode_shortcut_error;
-                } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 ||
-                        (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) {
-                    error = R.string.shortcut_not_available;
-                }
-                Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
-                return;
-            }
-        }
-
-        // Check for abandoned promise
-        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
-            String packageName = shortcut.intent.getComponent() != null ?
-                    shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
-            if (!TextUtils.isEmpty(packageName)) {
-                onClickPendingAppItem(v, packageName,
-                        shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
-                return;
-            }
-        }
-
-        // Start activities
-        startAppShortcutOrInfoActivity(v);
-    }
-
-    private void startAppShortcutOrInfoActivity(View v) {
-        ItemInfo item = (ItemInfo) v.getTag();
-        Intent intent;
-        if (item instanceof PromiseAppInfo) {
-            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
-            intent = promiseAppInfo.getMarketIntent(this);
-        } else {
-            intent = item.getIntent();
-        }
-        if (intent == null) {
-            throw new IllegalArgumentException("Input must have a valid intent");
-        }
-        if (item instanceof ShortcutInfo) {
-            ShortcutInfo si = (ShortcutInfo) item;
-            if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
-                    && intent.getAction() == Intent.ACTION_VIEW) {
-                // make a copy of the intent that has the package set to null
-                // we do this because the platform sometimes disables instant
-                // apps temporarily (triggered by the user) and fallbacks to the
-                // web ui. This only works though if the package isn't set
-                intent = new Intent(intent);
-                intent.setPackage(null);
-            }
-        }
-        startActivitySafely(v, intent, item);
-    }
-
-    /**
-     * Event handler for a folder icon click.
-     *
-     * @param v The view that was clicked. Must be an instance of {@link FolderIcon}.
-     */
-    protected void onClickFolderIcon(View v) {
-        if (LOGD) Log.d(TAG, "onClickFolder");
-        if (!(v instanceof FolderIcon)){
-            throw new IllegalArgumentException("Input must be a FolderIcon");
-        }
-
-        Folder folder = ((FolderIcon) v).getFolder();
-        if (!folder.isOpen() && !folder.isDestroyed()) {
-            // Open the requested folder
-            folder.animateOpen();
-        }
-    }
-
-    /**
-     * Event handler for the wallpaper picker button that appears after a long press
-     * on the home screen.
-     */
-    public void onClickWallpaperPicker(View v) {
-        if (!Utilities.isWallpaperAllowed(this)) {
-            Toast.makeText(this, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
-            return;
-        }
-
-        int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
-        float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
-        setWaitingForResult(new PendingRequestArgs(new ItemInfo()));
-        Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
-                .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
-
-        String pickerPackage = getString(R.string.wallpaper_picker_package);
-        boolean hasTargetPackage = !TextUtils.isEmpty(pickerPackage);
-        if (hasTargetPackage) {
-            intent.setPackage(pickerPackage);
-        }
-
-        final Bundle launchOptions;
-        if (v != null) {
-            intent.setSourceBounds(getViewBounds(v));
-            // If there is no target package, use the default intent chooser animation
-            launchOptions = hasTargetPackage
-                    ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
-                    : null;
-        } else {
-            launchOptions = null;
-        }
-        try {
-            startActivityForResult(intent, REQUEST_PICK_WALLPAPER, launchOptions);
-        } catch (ActivityNotFoundException e) {
-            setWaitingForResult(null);
-            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-        }
-    }
-
-    private void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
-        try {
-            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
-            try {
-                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
-                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
-                // is enabled by default on NYC.
-                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
-                        .penaltyLog().build());
-
-                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                    String id = ((ShortcutInfo) info).getDeepShortcutId();
-                    String packageName = intent.getPackage();
-                    DeepShortcutManager.getInstance(this).startShortcut(
-                            packageName, id, intent.getSourceBounds(), optsBundle, info.user);
-                } else {
-                    // Could be launching some bookkeeping activity
-                    startActivity(intent, optsBundle);
-                }
-            } finally {
-                StrictMode.setVmPolicy(oldPolicy);
-            }
-        } catch (SecurityException e) {
-            // Due to legacy reasons, direct call shortcuts require Launchers to have the
-            // corresponding permission. Show the appropriate permission prompt if that
-            // is the case.
-            if (intent.getComponent() == null
-                    && Intent.ACTION_CALL.equals(intent.getAction())
-                    && checkSelfPermission(Manifest.permission.CALL_PHONE) !=
-                    PackageManager.PERMISSION_GRANTED) {
-
-                setWaitingForResult(PendingRequestArgs
-                        .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
-                requestPermissions(new String[]{Manifest.permission.CALL_PHONE},
-                        REQUEST_PERMISSION_CALL_PHONE);
-            } else {
-                // No idea why this was thrown.
-                throw e;
-            }
-        }
+    public LauncherAppTransitionManager getAppTransitionManager() {
+        return mAppTransitionManager;
     }
 
     @TargetApi(Build.VERSION_CODES.M)
-    public Bundle getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
-        return useDefaultLaunchOptions
-                ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
-                : mAppTransitionManager.getActivityLaunchOptions(this, v);
+    @Override
+    protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
+        // Due to legacy reasons, direct call shortcuts require Launchers to have the
+        // corresponding permission. Show the appropriate permission prompt if that
+        // is the case.
+        if (intent.getComponent() == null
+                && Intent.ACTION_CALL.equals(intent.getAction())
+                && checkSelfPermission(android.Manifest.permission.CALL_PHONE) !=
+                PackageManager.PERMISSION_GRANTED) {
+
+            setWaitingForResult(PendingRequestArgs
+                    .forIntent(REQUEST_PERMISSION_CALL_PHONE, intent, info));
+            requestPermissions(new String[]{android.Manifest.permission.CALL_PHONE},
+                    REQUEST_PERMISSION_CALL_PHONE);
+            return true;
+        } else {
+            return false;
+        }
     }
 
-    public Rect getViewBounds(View v) {
-        int[] pos = new int[2];
-        v.getLocationOnScreen(pos);
-        return new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight());
+    @Override
+    public void modifyUserEvent(LauncherLogProto.LauncherEvent event) {
+        if (event.srcTarget != null && event.srcTarget.length > 0 &&
+                event.srcTarget[1].containerType == ContainerType.PREDICTION) {
+            Target[] targets = new Target[3];
+            targets[0] = event.srcTarget[0];
+            targets[1] = event.srcTarget[1];
+            targets[2] = newTarget(Target.Type.CONTAINER);
+            event.srcTarget = targets;
+            LauncherState state = mStateManager.getState();
+            if (state == LauncherState.ALL_APPS) {
+                event.srcTarget[2].containerType = ContainerType.ALLAPPS;
+            } else if (state == LauncherState.OVERVIEW) {
+                event.srcTarget[2].containerType = ContainerType.TASKSWITCHER;
+            }
+        }
     }
 
     public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
-        mAppLaunchSuccess = false;
-        if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
-            Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
-            return mAppLaunchSuccess;
+        boolean success = super.startActivitySafely(v, intent, item);
+        if (success && v instanceof BubbleTextView) {
+            // This is set to the view that launched the activity that navigated the user away
+            // from launcher. Since there is no callback for when the activity has finished
+            // launching, enable the press state and keep this reference to reset the press
+            // state when we return to launcher.
+            BubbleTextView btv = (BubbleTextView) v;
+            btv.setStayPressed(true);
+            setOnResumeCallback(btv);
         }
-
-        // Only launch using the new animation if the shortcut has not opted out (this is a
-        // private contract between launcher and may be ignored in the future).
-        boolean useLaunchAnimation = (v != null) &&
-                !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
-        Bundle optsBundle = useLaunchAnimation
-                ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
-                : null;
-
-        UserHandle user = item == null ? null : item.user;
-
-        // Prepare intent
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (v != null) {
-            intent.setSourceBounds(getViewBounds(v));
-        }
-        try {
-            boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
-                    && (item instanceof ShortcutInfo)
-                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
-                    || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
-                    && !((ShortcutInfo) item).isPromise();
-            if (isShortcut) {
-                // Shortcuts need some special checks due to legacy reasons.
-                startShortcutIntentSafely(intent, optsBundle, item);
-            } else if (user == null || user.equals(Process.myUserHandle())) {
-                // Could be launching some bookkeeping activity
-                startActivity(intent, optsBundle);
-            } else {
-                LauncherAppsCompat.getInstance(this).startActivityForProfile(
-                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
-            }
-
-            if (v instanceof BubbleTextView) {
-                // This is set to the view that launched the activity that navigated the user away
-                // from launcher. Since there is no callback for when the activity has finished
-                // launching, enable the press state and keep this reference to reset the press
-                // state when we return to launcher.
-                BubbleTextView btv = (BubbleTextView) v;
-                btv.setStayPressed(true);
-                setOnResumeCallback(btv);
-            }
-            mAppLaunchSuccess = true;
-            getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
-        } catch (ActivityNotFoundException|SecurityException e) {
-            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
-        }
-        return mAppLaunchSuccess;
-    }
-
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        mLastDispatchTouchEvent.set(ev.getX(), ev.getY());
-        return super.dispatchTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        if (!isDraggingEnabled()) return false;
-        if (isWorkspaceLocked()) return false;
-        if (!isInState(NORMAL) && !isInState(OVERVIEW)) return false;
-
-        boolean ignoreLongPressToOverview =
-                mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEvent.x);
-
-        if (v instanceof Workspace) {
-            if (!isInState(OVERVIEW)) {
-                if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) {
-                    getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
-                            Action.Direction.NONE, ContainerType.WORKSPACE,
-                            mWorkspace.getCurrentPage());
-                    UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
-                    mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
-                            HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-                    return true;
-                } else {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        }
-
-        CellLayout.CellInfo longClickCellInfo = null;
-        View itemUnderLongClick = null;
-        if (v.getTag() instanceof ItemInfo) {
-            ItemInfo info = (ItemInfo) v.getTag();
-            longClickCellInfo = new CellLayout.CellInfo(v, info);
-            itemUnderLongClick = longClickCellInfo.cell;
-            mPendingRequestArgs = null;
-        }
-
-        // The hotseat touch handling does not go through Workspace, and we always allow long press
-        // on hotseat items.
-        if (!mDragController.isDragging()) {
-            if (itemUnderLongClick == null) {
-                // User long pressed on empty space
-                if (mWorkspace.isPageRearrangeEnabled()) {
-                    mWorkspace.startReordering(v);
-                    getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
-                            Action.Direction.NONE, ContainerType.OVERVIEW);
-                } else {
-                    if (ignoreLongPressToOverview) {
-                        return false;
-                    }
-                    getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
-                            Action.Direction.NONE, ContainerType.WORKSPACE,
-                            mWorkspace.getCurrentPage());
-                    UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
-                }
-                mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
-                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-            } else {
-                final boolean isAllAppsButton =
-                        !FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) &&
-                                mDeviceProfile.inv.isAllAppsButtonRank(mHotseat.getOrderInHotseat(
-                                        longClickCellInfo.cellX, longClickCellInfo.cellY));
-                if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {
-                    // User long pressed on an item
-                    mWorkspace.startDrag(longClickCellInfo, new DragOptions());
-                }
-            }
-        }
-        return true;
+        return success;
     }
 
     boolean isHotseatLayout(View layout) {
@@ -2153,6 +1715,7 @@
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onTrimMemory(level);
         }
+        UiFactory.onTrimMemory(this, level);
     }
 
     @Override
@@ -2217,9 +1780,10 @@
         // Clear the workspace because it's going to be rebound
         mWorkspace.clearDropTargets();
         mWorkspace.removeAllWorkspaceScreens();
+        mAppWidgetHost.clearViews();
 
         if (mHotseat != null) {
-            mHotseat.resetLayout();
+            mHotseat.resetLayout(mDeviceProfile.isVerticalBarLayout());
         }
         TraceHelper.endSection("startBinding");
     }
@@ -2373,6 +1937,8 @@
                     mWorkspace.postDelayed(new Runnable() {
                         public void run() {
                             if (mWorkspace != null) {
+                                AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+
                                 mWorkspace.snapToPage(newScreenIndex);
                                 mWorkspace.postDelayed(startBounceAnimRunnable,
                                         NEW_APPS_ANIMATION_DELAY);
@@ -2558,9 +2124,18 @@
 
     @Override
     public void finishFirstPageBind(final ViewOnDrawExecutor executor) {
-        if (mDragLayer.getAlpha() < 1) {
-            mDragLayer.animate().alpha(1).withEndAction(
-                    executor == null ? null : executor::onLoadAnimationCompleted).start();
+        AlphaProperty property = mDragLayer.getAlphaProperty(ALPHA_INDEX_LAUNCHER_LOAD);
+        if (property.getValue() < 1) {
+            ObjectAnimator anim = ObjectAnimator.ofFloat(property, MultiValueAlpha.VALUE, 1);
+            if (executor != null) {
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        executor.onLoadAnimationCompleted();
+                    }
+                });
+            }
+            anim.start();
         } else if (executor != null) {
             executor.onLoadAnimationCompleted();
         }
@@ -2702,10 +2277,6 @@
         mModel.refreshAndBindWidgetsAndShortcuts(packageUser);
     }
 
-    public boolean isRotationEnabled () {
-        return mRotationEnabled;
-    }
-
     /**
      * $ adb shell dumpsys activity com.android.launcher3.Launcher [--all]
      */
@@ -2735,18 +2306,20 @@
                     writer.println(prefix + "    " + tag.toString());
                 }
             }
-
-            try {
-                FileLog.flushAll(writer);
-            } catch (Exception e) {
-                // Ignore
-            }
         }
 
         writer.println(prefix + "Misc:");
         writer.print(prefix + "\tmWorkspaceLoading=" + mWorkspaceLoading);
         writer.print(" mPendingRequestArgs=" + mPendingRequestArgs);
         writer.println(" mPendingActivityResult=" + mPendingActivityResult);
+        writer.println(" mRotationHelper: " + mRotationHelper);
+        dumpMisc(writer);
+
+        try {
+            FileLog.flushAll(writer);
+        } catch (Exception e) {
+            // Ignore
+        }
 
         mModel.dumpState(prefix, fd, writer, args);
 
@@ -2764,16 +2337,21 @@
         if (isInState(NORMAL)) {
             shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.all_apps_button_label),
                     KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON));
+            shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.widget_button_text),
+                    KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON));
         }
-        View currentFocus = getCurrentFocus();
-        if (new CustomActionsPopup(this, currentFocus).canShow()) {
-            shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
-                    KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
-        }
-        if (currentFocus.getTag() instanceof ItemInfo
-                && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) {
-            shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.action_deep_shortcut),
-                    KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
+        final View currentFocus = getCurrentFocus();
+        if (currentFocus != null) {
+            if (new CustomActionsPopup(this, currentFocus).canShow()) {
+                shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
+                        KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
+            }
+            if (currentFocus.getTag() instanceof ItemInfo
+                    && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) {
+                shortcutInfos.add(new KeyboardShortcutInfo(
+                        getString(R.string.shortcuts_menu_with_notifications_description),
+                        KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
+            }
         }
         if (!shortcutInfos.isEmpty()) {
             data.add(new KeyboardShortcutGroup(getString(R.string.home_screen), shortcutInfos));
@@ -2809,6 +2387,12 @@
                         return true;
                     }
                     break;
+                case KeyEvent.KEYCODE_W:
+                    if (isInState(NORMAL)) {
+                        OptionsPopupView.openWidgets(this);
+                        return true;
+                    }
+                    break;
             }
         }
         return super.onKeyShortcut(keyCode, event);
@@ -2826,8 +2410,7 @@
 
                 // Setting the touch point to (-1, -1) will show the options popup in the center of
                 // the screen.
-                mLastDispatchTouchEvent.set(-1, -1);
-                UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent);
+                OptionsPopupView.showDefaultOptions(this, -1, -1);
             }
             return true;
         }
@@ -2835,42 +2418,7 @@
     }
 
     public static Launcher getLauncher(Context context) {
-        if (context instanceof Launcher) {
-            return (Launcher) context;
-        }
-        return ((Launcher) ((ContextWrapper) context).getBaseContext());
-    }
-
-    private class RotationPrefChangeHandler implements OnSharedPreferenceChangeListener {
-
-        @Override
-        public void onSharedPreferenceChanged(
-                SharedPreferences sharedPreferences, String key) {
-            if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(key)) {
-                // Recreate the activity so that it initializes the rotation preference again.
-                recreate();
-            }
-        }
-    }
-
-    @Override
-    public void onActionModeStarted(ActionMode mode) {
-        super.onActionModeStarted(mode);
-        mCurrentActionMode = mode;
-    }
-
-    @Override
-    public void onActionModeFinished(ActionMode mode) {
-        super.onActionModeFinished(mode);
-        mCurrentActionMode = null;
-    }
-
-    public boolean finishAutoCancelActionMode() {
-        if (mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag()) {
-            mCurrentActionMode.finish();
-            return true;
-        }
-        return false;
+        return (Launcher) fromContext(context);
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 9869fdf..03ffded 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -39,6 +39,9 @@
     public static final int SPRING_LOADED_TRANSITION_MS = 150;
     public static final int SPRING_LOADED_EXIT_DELAY = 500;
 
+    // The progress of an animation to all apps must be at least this far along to snap to all apps.
+    public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
+
     static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>();
     static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
         public void onAnimationStart(Animator animation) {
@@ -165,16 +168,8 @@
                 }
             };
 
-    public static final Property<View, Float> ELEVATION =
-            new Property<View, Float>(Float.class, "elevation") {
-                @Override
-                public Float get(View view) {
-                    return view.getElevation();
-                }
-
-                @Override
-                public void set(View view, Float elevation) {
-                    view.setElevation(elevation);
-                }
-            };
+    /** Increase the duration if we prevented the fling, as we are going against a high velocity. */
+    public static int blockedFlingDurationFactor(float velocity) {
+        return (int) Utilities.boundToRange(Math.abs(velocity) / 2, 2f, 6f);
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index a46692b..5159de1 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,12 +16,13 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.Looper;
 import android.util.Log;
 
 import com.android.launcher3.compat.LauncherAppsCompat;
@@ -29,21 +30,17 @@
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.util.ConfigMonitor;
+import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.SettingsObserver;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
-
 public class LauncherAppState {
 
     public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
 
     // We do not need any synchronization for this variable as its only written on UI thread.
-    private static LauncherAppState INSTANCE;
+    private static final MainThreadInitializedObject<LauncherAppState> INSTANCE =
+            new MainThreadInitializedObject<>((c) -> new LauncherAppState(c));
 
     private final Context mContext;
     private final LauncherModel mModel;
@@ -53,27 +50,11 @@
     private final SettingsObserver mNotificationBadgingObserver;
 
     public static LauncherAppState getInstance(final Context context) {
-        if (INSTANCE == null) {
-            if (Looper.myLooper() == Looper.getMainLooper()) {
-                INSTANCE = new LauncherAppState(context.getApplicationContext());
-            } else {
-                try {
-                    return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
-                        @Override
-                        public LauncherAppState call() throws Exception {
-                            return LauncherAppState.getInstance(context);
-                        }
-                    }).get();
-                } catch (InterruptedException|ExecutionException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        }
-        return INSTANCE;
+        return INSTANCE.get(context);
     }
 
     public static LauncherAppState getInstanceNoCreate() {
-        return INSTANCE;
+        return INSTANCE.getNoCreate();
     }
 
     public Context getContext() {
@@ -89,7 +70,7 @@
         Preconditions.assertUIThread();
         mContext = context;
 
-        mInvariantDeviceProfile = new InvariantDeviceProfile(mContext);
+        mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(mContext);
         mIconCache = new IconCache(mContext, mInvariantDeviceProfile);
         mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
         mModel = new LauncherModel(this, mIconCache, AppFilter.newInstance(mContext));
@@ -112,7 +93,6 @@
 
         mContext.registerReceiver(mModel, filter);
         UserManagerCompat.getInstance(mContext).enableAndResetCache();
-        new ConfigMonitor(mContext).register();
 
         if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
             mNotificationBadgingObserver = null;
@@ -171,7 +151,7 @@
      * Shorthand for {@link #getInvariantDeviceProfile()}
      */
     public static InvariantDeviceProfile getIDP(Context context) {
-        return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
+        return InvariantDeviceProfile.INSTANCE.get(context);
     }
 
     private static LauncherProvider getLocalProvider(Context context) {
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 43d5e62..970e558 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -21,20 +21,21 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.view.View;
 
+import com.android.launcher3.util.ResourceBasedOverride;
+
 /**
  * Manages the opening and closing app transitions from Launcher.
  */
-public class LauncherAppTransitionManager {
+public class LauncherAppTransitionManager implements ResourceBasedOverride {
 
     public static LauncherAppTransitionManager newInstance(Context context) {
-        return Utilities.getOverrideObject(LauncherAppTransitionManager.class,
+        return Overrides.getObject(LauncherAppTransitionManager.class,
                 context, R.string.app_transition_manager_class);
     }
 
-    public Bundle getDefaultActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         if (Utilities.ATLEAST_MARSHMALLOW) {
             int left = 0, top = 0;
             int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
@@ -49,23 +50,14 @@
                     height = bounds.height();
                 }
             }
-            return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height)
-                    .toBundle();
+            return ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
         } else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
             // On L devices, we use the device default slide-up transition.
             // On L MR1 devices, we use a custom version of the slide-up transition which
             // doesn't have the delay present in the device default.
             return ActivityOptions.makeCustomAnimation(launcher, R.anim.task_open_enter,
-                    R.anim.no_anim).toBundle();
+                    R.anim.no_anim);
         }
         return null;
     }
-
-    public Bundle getActivityLaunchOptions(Launcher launcher, View v) {
-        return getDefaultActivityLaunchOptions(launcher, v);
-    }
-
-    /** Cancels the current Launcher transition animation */
-    public void finishLauncherAnimation() {
-    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index 7bc7139..56671a1 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -236,7 +236,7 @@
     }
 
     @Override
-    protected void clearViews() {
+    public void clearViews() {
         super.clearViews();
         mViews.clear();
     }
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index c713992..80758c9 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -94,4 +94,12 @@
     public boolean isCustomWidget() {
         return provider.getClassName().startsWith(CLS_CUSTOM_WIDGET_PREFIX);
     }
+
+    public int getWidgetFeatures() {
+        if (Utilities.ATLEAST_P) {
+            return widgetFeatures;
+        } else {
+            return 0;
+        }
+    }
  }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index 35faaea..34bdb3c 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -18,7 +18,6 @@
 
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.Menu;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -50,7 +49,7 @@
     void onAttachedToWindow();
     void onDetachedFromWindow();
     void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args);
-    void onHomeIntent();
+    void onHomeIntent(boolean internalStateHandled);
     boolean handleBackPressed();
     void onTrimMemory(int level);
 
@@ -70,12 +69,4 @@
      * Extensions points for adding / replacing some other aspects of the Launcher experience.
      */
     boolean hasSettings();
-
-    /**
-     * Called when launcher integrated quickstep and some quickstep gesture started. It can be
-     * called multiple times for a single gesture an UI or background thread.
-     *
-     * @param isVisible if Launcher was visible when the gesture started.
-     */
-    void onQuickstepGestureStarted(boolean isVisible);
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index a4d188f..19aa795 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -135,6 +135,8 @@
     };
 
     public interface Callbacks {
+        public void rebindModel();
+
         public int getCurrentWorkspaceScreen();
         public void clearPendingBinds();
         public void startBinding();
@@ -196,8 +198,9 @@
         enqueueModelUpdateTask(new AddWorkspaceItemsTask(itemList));
     }
 
-    public ModelWriter getWriter(boolean hasVerticalHotseat) {
-        return new ModelWriter(mApp.getContext(), sBgDataModel, hasVerticalHotseat);
+    public ModelWriter getWriter(boolean hasVerticalHotseat, boolean verifyChanges) {
+        return new ModelWriter(mApp.getContext(), this, sBgDataModel,
+                hasVerticalHotseat, verifyChanges);
     }
 
     static void checkItemInfoLocked(
@@ -444,11 +447,7 @@
             if (mCallbacks != null && mCallbacks.get() != null) {
                 final Callbacks oldCallbacks = mCallbacks.get();
                 // Clear any pending bind-runnables from the synchronized load process.
-                mUiExecutor.execute(new Runnable() {
-                            public void run() {
-                                oldCallbacks.clearPendingBinds();
-                            }
-                        });
+                mUiExecutor.execute(oldCallbacks::clearPendingBinds);
 
                 // If there is already one running, tell it to stop.
                 stopLoader();
@@ -621,15 +620,12 @@
     }
 
     public void updateAndBindShortcutInfo(final ShortcutInfo si, final ShortcutInfoCompat info) {
-        updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
-            @Override
-            public ShortcutInfo get() {
-                si.updateFromDeepShortcutInfo(info, mApp.getContext());
-                LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
-                li.createShortcutIcon(info).applyTo(si);
-                li.recycle();
-                return si;
-            }
+        updateAndBindShortcutInfo(() -> {
+            si.updateFromDeepShortcutInfo(info, mApp.getContext());
+            LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
+            li.createShortcutIcon(info).applyTo(si);
+            li.recycle();
+            return si;
         });
     }
 
@@ -641,6 +637,7 @@
             @Override
             public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
                 ShortcutInfo info = shortcutProvider.get();
+                getModelWriter().updateItemInDatabase(info);
                 ArrayList<ShortcutInfo> update = new ArrayList<>();
                 update.add(info);
                 bindUpdatedShortcuts(update, info.user);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 138ea0f..7d208d4 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -34,7 +34,6 @@
 import android.database.Cursor;
 import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
 import android.net.Uri;
@@ -59,8 +58,7 @@
 import com.android.launcher3.provider.LauncherDbUtils;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
 import com.android.launcher3.provider.RestoreDbTask;
-import com.android.launcher3.util.ManagedProfileHeuristic;
-import com.android.launcher3.util.NoLocaleSqliteContext;
+import com.android.launcher3.util.NoLocaleSQLiteHelper;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.Thunk;
 
@@ -541,7 +539,7 @@
     /**
      * The class is subclassed in tests to create an in-memory db.
      */
-    public static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
+    public static class DatabaseHelper extends NoLocaleSQLiteHelper implements LayoutParserCallback {
         private final Handler mWidgetHostResetHandler;
         private final Context mContext;
         private long mMaxItemId = -1;
@@ -567,7 +565,7 @@
          */
         public DatabaseHelper(
                 Context context, Handler widgetHostResetHandler, String tableName) {
-            super(new NoLocaleSqliteContext(context), tableName, null, SCHEMA_VERSION);
+            super(context, tableName, SCHEMA_VERSION);
             mContext = context;
             mWidgetHostResetHandler = widgetHostResetHandler;
         }
@@ -623,10 +621,6 @@
 
             // Set the flag for empty DB
             Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
-
-            // When a new DB is created, remove all previously stored managed profile information.
-            ManagedProfileHeuristic.processAllUsers(Collections.<UserHandle>emptyList(),
-                    mContext);
         }
 
         public long getDefaultUserSerial() {
@@ -790,7 +784,7 @@
                 case 23:
                     // No-op
                 case 24:
-                    ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext);
+                    // No-op
                 case 25:
                     convertShortcutsToLauncherActivities(db);
                 case 26:
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index fc4de2d..3cf6d62 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -1,5 +1,8 @@
 package com.android.launcher3;
 
+import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
+
 import android.annotation.TargetApi;
 import android.app.ActivityManager;
 import android.content.Context;
@@ -11,24 +14,17 @@
 import android.view.View;
 import android.view.ViewDebug;
 
-import com.android.launcher3.util.Themes;
-
-import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
-import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
-
 public class LauncherRootView extends InsettableFrameLayout {
 
     private final Launcher mLauncher;
 
     private final Paint mOpaquePaint;
+
     @ViewDebug.ExportedProperty(category = "launcher")
-    private boolean mDrawSideInsetBar;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private int mLeftInsetBarWidth;
-    @ViewDebug.ExportedProperty(category = "launcher")
-    private int mRightInsetBarWidth;
+    private final Rect mConsumedInsets = new Rect();
 
     private View mAlignedView;
+    private WindowStateListener mWindowStateListener;
 
     public LauncherRootView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -53,18 +49,26 @@
     @TargetApi(23)
     @Override
     protected boolean fitSystemWindows(Rect insets) {
-        mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
+        mConsumedInsets.setEmpty();
+        boolean drawInsetBar = false;
+        if (mLauncher.isInMultiWindowModeCompat()
+                && (insets.left > 0 || insets.right > 0 || insets.bottom > 0)) {
+            mConsumedInsets.left = insets.left;
+            mConsumedInsets.right = insets.right;
+            mConsumedInsets.bottom = insets.bottom;
+            insets = new Rect(0, insets.top, 0, 0);
+            drawInsetBar = true;
+        } else  if ((insets.right > 0 || insets.left > 0) &&
                 (!Utilities.ATLEAST_MARSHMALLOW ||
-                        getContext().getSystemService(ActivityManager.class).isLowRamDevice());
-        if (mDrawSideInsetBar) {
-            mLeftInsetBarWidth = insets.left;
-            mRightInsetBarWidth = insets.right;
+                        getContext().getSystemService(ActivityManager.class).isLowRamDevice())) {
+            mConsumedInsets.left = insets.left;
+            mConsumedInsets.right = insets.right;
             insets = new Rect(0, insets.top, 0, insets.bottom);
-        } else {
-            mLeftInsetBarWidth = mRightInsetBarWidth = 0;
+            drawInsetBar = true;
         }
+
         mLauncher.getSystemUiController().updateUiState(
-                UI_STATE_ROOT_VIEW, mDrawSideInsetBar ? FLAG_DARK_NAV : 0);
+                UI_STATE_ROOT_VIEW, drawInsetBar ? FLAG_DARK_NAV : 0);
 
         // Update device profile before notifying th children.
         mLauncher.getDeviceProfile().updateInsets(insets);
@@ -72,16 +76,19 @@
         setInsets(insets);
 
         if (mAlignedView != null) {
-            // Apply margins on aligned view to handle left/right insets.
+            // Apply margins on aligned view to handle consumed insets.
             MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams();
-            if (lp.leftMargin != mLeftInsetBarWidth || lp.rightMargin != mRightInsetBarWidth) {
-                lp.leftMargin = mLeftInsetBarWidth;
-                lp.rightMargin = mRightInsetBarWidth;
+            if (lp.leftMargin != mConsumedInsets.left || lp.rightMargin != mConsumedInsets.right ||
+                    lp.bottomMargin != mConsumedInsets.bottom) {
+                lp.leftMargin = mConsumedInsets.left;
+                lp.rightMargin = mConsumedInsets.right;
+                lp.topMargin = mConsumedInsets.top;
+                lp.bottomMargin = mConsumedInsets.bottom;
                 mAlignedView.setLayoutParams(lp);
             }
         }
         if (resetState) {
-            mLauncher.getStateManager().reapplyState();
+            mLauncher.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
         }
 
         return true; // I'll take it from here
@@ -94,11 +101,10 @@
         if (!insets.equals(mInsets)) {
             super.setInsets(insets);
         }
-        setBackground(insets.top == 0 ? null
-                : Themes.getAttrDrawable(getContext(), R.attr.workspaceStatusBarScrim));
     }
 
     public void dispatchInsets() {
+        mLauncher.getDeviceProfile().updateInsets(mInsets);
         super.setInsets(mInsets);
     }
 
@@ -107,14 +113,43 @@
         super.dispatchDraw(canvas);
 
         // If the right inset is opaque, draw a black rectangle to ensure that is stays opaque.
-        if (mDrawSideInsetBar) {
-            if (mRightInsetBarWidth > 0) {
-                int width = getWidth();
-                canvas.drawRect(width - mRightInsetBarWidth, 0, width, getHeight(), mOpaquePaint);
-            }
-            if (mLeftInsetBarWidth > 0) {
-                canvas.drawRect(0, 0, mLeftInsetBarWidth, getHeight(), mOpaquePaint);
-            }
+        if (mConsumedInsets.right > 0) {
+            int width = getWidth();
+            canvas.drawRect(width - mConsumedInsets.right, 0, width, getHeight(), mOpaquePaint);
         }
+        if (mConsumedInsets.left > 0) {
+            canvas.drawRect(0, 0, mConsumedInsets.left, getHeight(), mOpaquePaint);
+        }
+        if (mConsumedInsets.bottom > 0) {
+            int height = getHeight();
+            canvas.drawRect(0, height - mConsumedInsets.bottom, getWidth(), height, mOpaquePaint);
+        }
+    }
+
+    public void setWindowStateListener(WindowStateListener listener) {
+        mWindowStateListener = listener;
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (mWindowStateListener != null) {
+            mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
+        }
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+        if (mWindowStateListener != null) {
+            mWindowStateListener.onWindowVisibilityChanged(visibility);
+        }
+    }
+
+    public interface WindowStateListener {
+
+        void onWindowFocusChanged(boolean hasFocus);
+
+        void onWindowVisibilityChanged(int visibility);
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
index a9b4955..e5042c4 100644
--- a/src/com/android/launcher3/LauncherScroller.java
+++ b/src/com/android/launcher3/LauncherScroller.java
@@ -18,541 +18,37 @@
 
 import android.animation.TimeInterpolator;
 import android.content.Context;
-import android.hardware.SensorManager;
-import android.os.Build;
-import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.widget.Scroller;
 
 /**
- * This class differs from the framework {@link android.widget.Scroller} in that
- * you can modify the Interpolator post-construction.
+ * Extension of {@link android.widget.Scroller} with the ability to modify the
+ * Interpolator post-construction.
  */
-public class LauncherScroller  {
-    private int mMode;
+public class LauncherScroller extends Scroller {
 
-    private int mStartX;
-    private int mStartY;
-    private int mFinalX;
-    private int mFinalY;
+    private final InterpolatorWrapper mInterpolatorWrapper;
 
-    private int mMinX;
-    private int mMaxX;
-    private int mMinY;
-    private int mMaxY;
-
-    private int mCurrX;
-    private int mCurrY;
-    private long mStartTime;
-    private int mDuration;
-    private float mDurationReciprocal;
-    private float mDeltaX;
-    private float mDeltaY;
-    private boolean mFinished;
-    private TimeInterpolator mInterpolator;
-    private boolean mFlywheel;
-
-    private float mVelocity;
-    private float mCurrVelocity;
-    private int mDistance;
-
-    private float mFlingFriction = ViewConfiguration.getScrollFriction();
-
-    private static final int DEFAULT_DURATION = 250;
-    private static final int SCROLL_MODE = 0;
-    private static final int FLING_MODE = 1;
-
-    private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
-    private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
-    private static final float START_TENSION = 0.5f;
-    private static final float END_TENSION = 1.0f;
-    private static final float P1 = START_TENSION * INFLEXION;
-    private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
-
-    private static final int NB_SAMPLES = 100;
-    private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
-    private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
-
-    private float mDeceleration;
-    private final float mPpi;
-
-    // A context-specific coefficient adjusted to physical values.
-    private float mPhysicalCoeff;
-
-    static {
-        float x_min = 0.0f;
-        float y_min = 0.0f;
-        for (int i = 0; i < NB_SAMPLES; i++) {
-            final float alpha = (float) i / NB_SAMPLES;
-
-            float x_max = 1.0f;
-            float x, tx, coef;
-            while (true) {
-                x = x_min + (x_max - x_min) / 2.0f;
-                coef = 3.0f * x * (1.0f - x);
-                tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
-                if (Math.abs(tx - alpha) < 1E-5) break;
-                if (tx > alpha) x_max = x;
-                else x_min = x;
-            }
-            SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
-
-            float y_max = 1.0f;
-            float y, dy;
-            while (true) {
-                y = y_min + (y_max - y_min) / 2.0f;
-                coef = 3.0f * y * (1.0f - y);
-                dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
-                if (Math.abs(dy - alpha) < 1E-5) break;
-                if (dy > alpha) y_max = y;
-                else y_min = y;
-            }
-            SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
-        }
-        SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
-
-        // This controls the viscous fluid effect (how much of it)
-        sViscousFluidScale = 8.0f;
-        // must be set to 1.0 (used in viscousFluid())
-        sViscousFluidNormalize = 1.0f;
-        sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
-
+    public LauncherScroller(Context context) {
+        this(context, new InterpolatorWrapper());
     }
 
-    private static float sViscousFluidScale;
-    private static float sViscousFluidNormalize;
+    private LauncherScroller(Context context, InterpolatorWrapper interpolatorWrapper) {
+        super(context, interpolatorWrapper);
+        mInterpolatorWrapper = interpolatorWrapper;
+    }
 
     public void setInterpolator(TimeInterpolator interpolator) {
-        mInterpolator = interpolator;
+        mInterpolatorWrapper.interpolator = interpolator;
     }
 
-    /**
-     * Create a Scroller with the default duration and interpolator.
-     */
-    public LauncherScroller(Context context) {
-        this(context, null);
-    }
+    private static class InterpolatorWrapper implements Interpolator {
 
-    /**
-     * Create a Scroller with the specified interpolator. If the interpolator is
-     * null, the default (viscous) interpolator will be used. "Flywheel" behavior will
-     * be in effect for apps targeting Honeycomb or newer.
-     */
-    public LauncherScroller(Context context, Interpolator interpolator) {
-        this(context, interpolator,
-                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
-    }
+        public TimeInterpolator interpolator;
 
-    /**
-     * Create a Scroller with the specified interpolator. If the interpolator is
-     * null, the default (viscous) interpolator will be used. Specify whether or
-     * not to support progressive "flywheel" behavior in flinging.
-     */
-    public LauncherScroller(Context context, Interpolator interpolator, boolean flywheel) {
-        mFinished = true;
-        mInterpolator = interpolator;
-        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
-        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
-        mFlywheel = flywheel;
-
-        mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
-    }
-
-    /**
-     * The amount of friction applied to flings. The default value
-     * is {@link ViewConfiguration#getScrollFriction}.
-     *
-     * @param friction A scalar dimension-less value representing the coefficient of
-     *         friction.
-     */
-    public final void setFriction(float friction) {
-        mDeceleration = computeDeceleration(friction);
-        mFlingFriction = friction;
-    }
-
-    private float computeDeceleration(float friction) {
-        return SensorManager.GRAVITY_EARTH   // g (m/s^2)
-                      * 39.37f               // inch/meter
-                      * mPpi                 // pixels per inch
-                      * friction;
-    }
-
-    /**
-     *
-     * Returns whether the scroller has finished scrolling.
-     *
-     * @return True if the scroller has finished scrolling, false otherwise.
-     */
-    public final boolean isFinished() {
-        return mFinished;
-    }
-
-    /**
-     * Force the finished field to a particular value.
-     *
-     * @param finished The new finished value.
-     */
-    public final void forceFinished(boolean finished) {
-        mFinished = finished;
-    }
-
-    /**
-     * Returns how long the scroll event will take, in milliseconds.
-     *
-     * @return The duration of the scroll in milliseconds.
-     */
-    public final int getDuration() {
-        return mDuration;
-    }
-
-    /**
-     * Returns the current X offset in the scroll.
-     *
-     * @return The new X offset as an absolute distance from the origin.
-     */
-    public final int getCurrX() {
-        return mCurrX;
-    }
-
-    /**
-     * Returns the current Y offset in the scroll.
-     *
-     * @return The new Y offset as an absolute distance from the origin.
-     */
-    public final int getCurrY() {
-        return mCurrY;
-    }
-
-    /**
-     * Returns the current velocity.
-     *
-     * @return The original velocity less the deceleration. Result may be
-     * negative.
-     */
-    public float getCurrVelocity() {
-        return mMode == FLING_MODE ?
-                mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
-    }
-
-    /**
-     * Returns the start X offset in the scroll.
-     *
-     * @return The start X offset as an absolute distance from the origin.
-     */
-    public final int getStartX() {
-        return mStartX;
-    }
-
-    /**
-     * Returns the start Y offset in the scroll.
-     *
-     * @return The start Y offset as an absolute distance from the origin.
-     */
-    public final int getStartY() {
-        return mStartY;
-    }
-
-    /**
-     * Returns where the scroll will end. Valid only for "fling" scrolls.
-     *
-     * @return The final X offset as an absolute distance from the origin.
-     */
-    public final int getFinalX() {
-        return mFinalX;
-    }
-
-    /**
-     * Returns where the scroll will end. Valid only for "fling" scrolls.
-     *
-     * @return The final Y offset as an absolute distance from the origin.
-     */
-    public final int getFinalY() {
-        return mFinalY;
-    }
-
-    /**
-     * Call this when you want to know the new location.  If it returns true,
-     * the animation is not yet finished.
-     */
-    public boolean computeScrollOffset() {
-        if (mFinished) {
-            return false;
+        @Override
+        public float getInterpolation(float v) {
+            return interpolator == null ? v : interpolator.getInterpolation(v);
         }
-
-        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
-
-        if (timePassed < mDuration) {
-            switch (mMode) {
-            case SCROLL_MODE:
-                float x = timePassed * mDurationReciprocal;
-
-                if (mInterpolator == null)
-                    x = viscousFluid(x);
-                else
-                    x = mInterpolator.getInterpolation(x);
-
-                mCurrX = mStartX + Math.round(x * mDeltaX);
-                mCurrY = mStartY + Math.round(x * mDeltaY);
-                break;
-            case FLING_MODE:
-                final float t = (float) timePassed / mDuration;
-                final int index = (int) (NB_SAMPLES * t);
-                float distanceCoef = 1.f;
-                float velocityCoef = 0.f;
-                if (index < NB_SAMPLES) {
-                    final float t_inf = (float) index / NB_SAMPLES;
-                    final float t_sup = (float) (index + 1) / NB_SAMPLES;
-                    final float d_inf = SPLINE_POSITION[index];
-                    final float d_sup = SPLINE_POSITION[index + 1];
-                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
-                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;
-                }
-
-                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
-
-                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
-                // Pin to mMinX <= mCurrX <= mMaxX
-                mCurrX = Math.min(mCurrX, mMaxX);
-                mCurrX = Math.max(mCurrX, mMinX);
-
-                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
-                // Pin to mMinY <= mCurrY <= mMaxY
-                mCurrY = Math.min(mCurrY, mMaxY);
-                mCurrY = Math.max(mCurrY, mMinY);
-
-                if (mCurrX == mFinalX && mCurrY == mFinalY) {
-                    mFinished = true;
-                }
-
-                break;
-            }
-        }
-        else {
-            mCurrX = mFinalX;
-            mCurrY = mFinalY;
-            mFinished = true;
-        }
-        return true;
-    }
-
-    /**
-     * Start scrolling by providing a starting point and the distance to travel.
-     * The scroll will use the default value of 250 milliseconds for the
-     * duration.
-     *
-     * @param startX Starting horizontal scroll offset in pixels. Positive
-     *        numbers will scroll the content to the left.
-     * @param startY Starting vertical scroll offset in pixels. Positive numbers
-     *        will scroll the content up.
-     * @param dx Horizontal distance to travel. Positive numbers will scroll the
-     *        content to the left.
-     * @param dy Vertical distance to travel. Positive numbers will scroll the
-     *        content up.
-     */
-    public void startScroll(int startX, int startY, int dx, int dy) {
-        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
-    }
-
-    /**
-     * Start scrolling by providing a starting point, the distance to travel,
-     * and the duration of the scroll.
-     *
-     * @param startX Starting horizontal scroll offset in pixels. Positive
-     *        numbers will scroll the content to the left.
-     * @param startY Starting vertical scroll offset in pixels. Positive numbers
-     *        will scroll the content up.
-     * @param dx Horizontal distance to travel. Positive numbers will scroll the
-     *        content to the left.
-     * @param dy Vertical distance to travel. Positive numbers will scroll the
-     *        content up.
-     * @param duration Duration of the scroll in milliseconds.
-     */
-    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
-        mMode = SCROLL_MODE;
-        mFinished = false;
-        mDuration = duration;
-        mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        mStartX = startX;
-        mStartY = startY;
-        mFinalX = startX + dx;
-        mFinalY = startY + dy;
-        mDeltaX = dx;
-        mDeltaY = dy;
-        mDurationReciprocal = 1.0f / (float) mDuration;
-    }
-
-    /**
-     * Start scrolling based on a fling gesture. The distance travelled will
-     * depend on the initial velocity of the fling.
-     *
-     * @param startX Starting point of the scroll (X)
-     * @param startY Starting point of the scroll (Y)
-     * @param velocityX Initial velocity of the fling (X) measured in pixels per
-     *        second.
-     * @param velocityY Initial velocity of the fling (Y) measured in pixels per
-     *        second
-     * @param minX Minimum X value. The scroller will not scroll past this
-     *        point.
-     * @param maxX Maximum X value. The scroller will not scroll past this
-     *        point.
-     * @param minY Minimum Y value. The scroller will not scroll past this
-     *        point.
-     * @param maxY Maximum Y value. The scroller will not scroll past this
-     *        point.
-     */
-    public void fling(int startX, int startY, int velocityX, int velocityY,
-            int minX, int maxX, int minY, int maxY) {
-        // Continue a scroll or fling in progress
-        if (mFlywheel && !mFinished) {
-            float oldVel = getCurrVelocity();
-
-            float dx = (float) (mFinalX - mStartX);
-            float dy = (float) (mFinalY - mStartY);
-            float hyp = (float) Math.hypot(dx, dy);
-
-            float ndx = dx / hyp;
-            float ndy = dy / hyp;
-
-            float oldVelocityX = ndx * oldVel;
-            float oldVelocityY = ndy * oldVel;
-            if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
-                    Math.signum(velocityY) == Math.signum(oldVelocityY)) {
-                velocityX += oldVelocityX;
-                velocityY += oldVelocityY;
-            }
-        }
-
-        mMode = FLING_MODE;
-        mFinished = false;
-
-        float velocity = (float) Math.hypot(velocityX, velocityY);
-
-        mVelocity = velocity;
-        mDuration = getSplineFlingDuration(velocity);
-        mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        mStartX = startX;
-        mStartY = startY;
-
-        float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
-        float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
-
-        double totalDistance = getSplineFlingDistance(velocity);
-        mDistance = (int) (totalDistance * Math.signum(velocity));
-
-        mMinX = minX;
-        mMaxX = maxX;
-        mMinY = minY;
-        mMaxY = maxY;
-
-        mFinalX = startX + (int) Math.round(totalDistance * coeffX);
-        // Pin to mMinX <= mFinalX <= mMaxX
-        mFinalX = Math.min(mFinalX, mMaxX);
-        mFinalX = Math.max(mFinalX, mMinX);
-
-        mFinalY = startY + (int) Math.round(totalDistance * coeffY);
-        // Pin to mMinY <= mFinalY <= mMaxY
-        mFinalY = Math.min(mFinalY, mMaxY);
-        mFinalY = Math.max(mFinalY, mMinY);
-    }
-
-    private double getSplineDeceleration(float velocity) {
-        return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff));
-    }
-
-    private int getSplineFlingDuration(float velocity) {
-        final double l = getSplineDeceleration(velocity);
-        final double decelMinusOne = DECELERATION_RATE - 1.0;
-        return (int) (1000.0 * Math.exp(l / decelMinusOne));
-    }
-
-    private double getSplineFlingDistance(float velocity) {
-        final double l = getSplineDeceleration(velocity);
-        final double decelMinusOne = DECELERATION_RATE - 1.0;
-        return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
-    }
-
-    static float viscousFluid(float x)
-    {
-        x *= sViscousFluidScale;
-        if (x < 1.0f) {
-            x -= (1.0f - (float)Math.exp(-x));
-        } else {
-            float start = 0.36787944117f;   // 1/e == exp(-1)
-            x = 1.0f - (float)Math.exp(1.0f - x);
-            x = start + x * (1.0f - start);
-        }
-        x *= sViscousFluidNormalize;
-        return x;
-    }
-
-    /**
-     * Stops the animation. Contrary to {@link #forceFinished(boolean)},
-     * aborting the animating cause the scroller to move to the final x and y
-     * position
-     *
-     * @see #forceFinished(boolean)
-     */
-    public void abortAnimation() {
-        mCurrX = mFinalX;
-        mCurrY = mFinalY;
-        mFinished = true;
-    }
-
-    /**
-     * Extend the scroll animation. This allows a running animation to scroll
-     * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
-     *
-     * @param extend Additional time to scroll in milliseconds.
-     * @see #setFinalX(int)
-     * @see #setFinalY(int)
-     */
-    public void extendDuration(int extend) {
-        int passed = timePassed();
-        mDuration = passed + extend;
-        mDurationReciprocal = 1.0f / mDuration;
-        mFinished = false;
-    }
-
-    /**
-     * Returns the time elapsed since the beginning of the scrolling.
-     *
-     * @return The elapsed time in milliseconds.
-     */
-    public int timePassed() {
-        return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
-    }
-
-    /**
-     * Sets the final position (X) for this scroller.
-     *
-     * @param newX The new X offset as an absolute distance from the origin.
-     * @see #extendDuration(int)
-     * @see #setFinalY(int)
-     */
-    public void setFinalX(int newX) {
-        mFinalX = newX;
-        mDeltaX = mFinalX - mStartX;
-        mFinished = false;
-    }
-
-    /**
-     * Sets the final position (Y) for this scroller.
-     *
-     * @param newY The new Y offset as an absolute distance from the origin.
-     * @see #extendDuration(int)
-     * @see #setFinalX(int)
-     */
-    public void setFinalY(int newY) {
-        mFinalY = newY;
-        mDeltaY = mFinalY - mStartY;
-        mFinished = false;
-    }
-
-    /**
-     * @hide
-     */
-    public boolean isScrollingInDirection(float xvel, float yvel) {
-        return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&
-                Math.signum(yvel) == Math.signum(mFinalY - mStartY);
     }
 }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 472a5a9..8a15b24 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -20,12 +20,14 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
 
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
 
-import android.view.View;
+import android.graphics.Rect;
 import android.view.animation.Interpolator;
 
-import com.android.launcher3.uioverrides.AllAppsState;
 import com.android.launcher3.states.SpringLoadedState;
+import com.android.launcher3.uioverrides.AllAppsState;
+import com.android.launcher3.uioverrides.FastOverviewState;
 import com.android.launcher3.uioverrides.OverviewState;
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -38,12 +40,29 @@
  */
 public class LauncherState {
 
-    protected static final int FLAG_SHOW_SCRIM = 1 << 0;
-    protected static final int FLAG_MULTI_PAGE = 1 << 1;
-    protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
-    protected static final int FLAG_DISABLE_RESTORE = 1 << 3;
-    protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4;
-    protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5;
+
+    /**
+     * Set of elements indicating various workspace elements which change visibility across states
+     * Note that workspace is not included here as in that case, we animate individual pages
+     */
+    public static final int NONE = 0;
+    public static final int HOTSEAT_ICONS = 1 << 0;
+    public static final int HOTSEAT_SEARCH_BOX = 1 << 1;
+    public static final int ALL_APPS_HEADER = 1 << 2;
+    public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions
+    public static final int ALL_APPS_CONTENT = 1 << 4;
+    public static final int VERTICAL_SWIPE_INDICATOR = 1 << 5;
+
+    protected static final int FLAG_MULTI_PAGE = 1 << 0;
+    protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 1;
+    protected static final int FLAG_DISABLE_RESTORE = 1 << 2;
+    protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 3;
+    protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 4;
+    protected static final int FLAG_PAGE_BACKGROUNDS = 1 << 5;
+    protected static final int FLAG_DISABLE_INTERACTION = 1 << 6;
+    protected static final int FLAG_OVERVIEW_UI = 1 << 7;
+    protected static final int FLAG_HIDE_BACK_BUTTON = 1 << 8;
+    protected static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 9;
 
     protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER =
             new PageAlphaProvider(ACCEL_2) {
@@ -53,19 +72,24 @@
                 }
             };
 
-    private static final LauncherState[] sAllStates = new LauncherState[4];
+    private static final LauncherState[] sAllStates = new LauncherState[5];
 
     /**
      * TODO: Create a separate class for NORMAL state.
      */
-    public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
-            0, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
+    public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE, 0,
+            FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_HIDE_BACK_BUTTON |
+            FLAG_HAS_SYS_UI_SCRIM);
 
-    public static final LauncherState ALL_APPS = new AllAppsState(1);
+    /**
+     * Various Launcher states arranged in the increasing order of UI layers
+     */
+    public static final LauncherState SPRING_LOADED = new SpringLoadedState(1);
+    public static final LauncherState OVERVIEW = new OverviewState(2);
+    public static final LauncherState FAST_OVERVIEW = new FastOverviewState(3);
+    public static final LauncherState ALL_APPS = new AllAppsState(4);
 
-    public static final LauncherState SPRING_LOADED = new SpringLoadedState(2);
-
-    public static final LauncherState OVERVIEW = new OverviewState(3);
+    protected static final Rect sTempRect = new Rect();
 
     public final int ordinal;
 
@@ -95,7 +119,8 @@
      *
      * @see WorkspaceStateTransitionAnimation
      */
-    public final boolean hasScrim;
+    public final boolean hasWorkspacePageBackground;
+
     public final int transitionDuration;
 
     /**
@@ -109,11 +134,29 @@
      */
     public final boolean disablePageClipping;
 
+    /**
+     * True if launcher can not be directly interacted in this state;
+     */
+    public final boolean disableInteraction;
+
+    /**
+     * True if the state has overview panel visible.
+     */
+    public final boolean overviewUi;
+
+    /**
+     * True if the back button should be hidden when in this state (assuming no floating views are
+     * open, launcher has window focus, etc).
+     */
+    public final boolean hideBackButton;
+
+    public final boolean hasSysUiScrim;
+
     public LauncherState(int id, int containerType, int transitionDuration, int flags) {
         this.containerType = containerType;
         this.transitionDuration = transitionDuration;
 
-        this.hasScrim = (flags & FLAG_SHOW_SCRIM) != 0;
+        this.hasWorkspacePageBackground = (flags & FLAG_PAGE_BACKGROUNDS) != 0;
         this.hasMultipleVisiblePages = (flags & FLAG_MULTI_PAGE) != 0;
         this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
@@ -121,6 +164,10 @@
         this.disableRestore = (flags & FLAG_DISABLE_RESTORE) != 0;
         this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
         this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
+        this.disableInteraction = (flags & FLAG_DISABLE_INTERACTION) != 0;
+        this.overviewUi = (flags & FLAG_OVERVIEW_UI) != 0;
+        this.hideBackButton = (flags & FLAG_HIDE_BACK_BUTTON) != 0;
+        this.hasSysUiScrim = (flags & FLAG_HAS_SYS_UI_SCRIM) != 0;
 
         this.ordinal = id;
         sAllStates[id] = this;
@@ -134,8 +181,13 @@
         return new float[] {1, 0, 0};
     }
 
-    public float getHoseatAlpha(Launcher launcher) {
-        return 1f;
+    /**
+     * Returns 2 floats designating how to transition overview:
+     *   scale for the current and adjacent pages
+     *   translationY factor where 0 is top aligned and 0.5 is centered vertically
+     */
+    public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+        return new float[] {1.1f, 0f};
     }
 
     public void onStateEnabled(Launcher launcher) {
@@ -144,8 +196,11 @@
 
     public void onStateDisabled(Launcher launcher) { }
 
-    public View getFinalFocus(Launcher launcher) {
-        return launcher.getWorkspace();
+    public int getVisibleElements(Launcher launcher) {
+        if (launcher.getDeviceProfile().isVerticalBarLayout()) {
+            return HOTSEAT_ICONS | VERTICAL_SWIPE_INDICATOR;
+        }
+        return HOTSEAT_ICONS | HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR;
     }
 
     /**
@@ -157,6 +212,10 @@
         return 1f;
     }
 
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
+        return 0;
+    }
+
     public String getDescription(Launcher launcher) {
         return launcher.getWorkspace().getCurrentPageDescription();
     }
@@ -183,9 +242,13 @@
      * Called when the start transition ends and the user settles on this particular state.
      */
     public void onStateTransitionEnd(Launcher launcher) {
-        if (this == NORMAL) {
+        if (this == NORMAL || this == SPRING_LOADED) {
             UiFactory.resetOverview(launcher);
         }
+        if (this == NORMAL) {
+            // Clear any rotation locks when going to normal state
+            launcher.getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
+        }
     }
 
     protected static void dispatchWindowStateChanged(Launcher launcher) {
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index e0b84bf..3c7c1aa 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -16,20 +16,37 @@
 
 package com.android.launcher3;
 
+import static android.view.View.VISIBLE;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
+import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.os.Handler;
 import android.os.Looper;
-import android.view.View;
+import android.support.annotation.IntDef;
 
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
 import com.android.launcher3.uioverrides.UiFactory;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
 /**
  * TODO: figure out what kind of tests we can write for this
  *
@@ -75,9 +92,25 @@
 
     public static final String TAG = "StateManager";
 
+    // We separate the state animations into "atomic" and "non-atomic" components. The atomic
+    // components may be run atomically - that is, all at once, instead of user-controlled. However,
+    // atomic components are not restricted to this purpose; they can be user-controlled alongside
+    // non atomic components as well.
+    @IntDef(flag = true, value = {
+            NON_ATOMIC_COMPONENT,
+            ATOMIC_COMPONENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AnimationComponents {}
+    public static final int NON_ATOMIC_COMPONENT = 1 << 0;
+    public static final int ATOMIC_COMPONENT = 1 << 1;
+
+    public static final int ANIM_ALL = NON_ATOMIC_COMPONENT | ATOMIC_COMPONENT;
+
     private final AnimationConfig mConfig = new AnimationConfig();
     private final Handler mUiHandler;
     private final Launcher mLauncher;
+    private final ArrayList<StateListener> mListeners = new ArrayList<>();
 
     private StateHandler[] mStateHandlers;
     private LauncherState mState = NORMAL;
@@ -87,8 +120,6 @@
 
     private LauncherState mRestState;
 
-    private StateListener mStateListener;
-
     public LauncherStateManager(Launcher l) {
         mUiHandler = new Handler(Looper.getMainLooper());
         mLauncher = l;
@@ -105,15 +136,19 @@
         return mStateHandlers;
     }
 
-    public void setStateListener(StateListener stateListener) {
-        mStateListener = stateListener;
+    public void addStateListener(StateListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeStateListener(StateListener listener) {
+        mListeners.remove(listener);
     }
 
     /**
      * @see #goToState(LauncherState, boolean, Runnable)
      */
     public void goToState(LauncherState state) {
-        goToState(state, mLauncher.isStarted() /* animated */, 0, null);
+        goToState(state, !mLauncher.isForceInvisible() && mLauncher.isStarted() /* animated */);
     }
 
     /**
@@ -149,6 +184,13 @@
     }
 
     public void reapplyState() {
+        reapplyState(false);
+    }
+
+    public void reapplyState(boolean cancelCurrentAnimation) {
+        if (cancelCurrentAnimation) {
+            cancelAnimation();
+        }
         if (mConfig.mCurrentAnimation == null) {
             for (StateHandler handler : getStateHandlers()) {
                 handler.setState(mState);
@@ -157,21 +199,30 @@
     }
 
     private void goToState(LauncherState state, boolean animated, long delay,
-            Runnable onCompleteRunnable) {
-        goToState(state, animated, delay, -1, onCompleteRunnable);
-    }
-
-    public void goToState(LauncherState state, boolean animated, long delay, long overrideDuration,
-            Runnable onCompleteRunnable) {
-        if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null) {
-            // Run any queued runnable
-            if (onCompleteRunnable != null) {
-                onCompleteRunnable.run();
+            final Runnable onCompleteRunnable) {
+        if (mLauncher.isInState(state)) {
+            if (mConfig.mCurrentAnimation == null) {
+                // Run any queued runnable
+                if (onCompleteRunnable != null) {
+                    onCompleteRunnable.run();
+                }
+                return;
+            } else if (!mConfig.userControlled && animated && mConfig.mTargetState == state) {
+                // We are running the same animation as requested
+                if (onCompleteRunnable != null) {
+                    mConfig.mCurrentAnimation.addListener(new AnimationSuccessListener() {
+                        @Override
+                        public void onAnimationSuccess(Animator animator) {
+                            onCompleteRunnable.run();
+                        }
+                    });
+                }
+                return;
             }
-            return;
         }
 
-        // Cancel the current animation
+        // Cancel the current animation. This will reset mState to mCurrentStableState, so store it.
+        LauncherState fromState = mState;
         mConfig.reset();
 
         if (!animated) {
@@ -179,8 +230,9 @@
             for (StateHandler handler : getStateHandlers()) {
                 handler.setState(state);
             }
-            if (mStateListener != null) {
-                mStateListener.onStateSetImmediately(state);
+
+            for (int i = mListeners.size() - 1; i >= 0; i--) {
+                mListeners.get(i).onStateSetImmediately(state);
             }
             onStateTransitionEnd(state);
 
@@ -193,14 +245,13 @@
 
         // Since state NORMAL can be reached from multiple states, just assume that the
         // transition plays in reverse and use the same duration as previous state.
-        mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
-        if (overrideDuration > -1) {
-            mConfig.duration = overrideDuration;
-        }
+        mConfig.duration = state == NORMAL ? fromState.transitionDuration : state.transitionDuration;
 
+        AnimatorSetBuilder builder = new AnimatorSetBuilder();
+        prepareForAtomicAnimation(fromState, state, builder);
         AnimatorSet animation = createAnimationToNewWorkspaceInternal(
-                state, new AnimatorSetBuilder(), onCompleteRunnable);
-        Runnable runnable = new StartAnimRunnable(animation, state.getFinalFocus(mLauncher));
+                state, builder, onCompleteRunnable);
+        Runnable runnable = new StartAnimRunnable(animation);
         if (delay > 0) {
             mUiHandler.postDelayed(runnable, delay);
         } else {
@@ -209,6 +260,61 @@
     }
 
     /**
+     * Prepares for a non-user controlled animation from fromState to toState. Preparations include:
+     * - Setting interpolators for various animations included in the state transition.
+     * - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
+     */
+    public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
+            AnimatorSetBuilder builder) {
+        if (fromState == NORMAL && toState.overviewUi) {
+            builder.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
+            builder.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
+
+            // Start from a higher overview scale, but only if we're invisible so we don't jump.
+            UiFactory.prepareToShowOverview(mLauncher);
+        } else if (fromState.overviewUi && toState == NORMAL) {
+            builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+            builder.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+            builder.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
+            builder.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
+            Workspace workspace = mLauncher.getWorkspace();
+
+            // Start from a higher workspace scale, but only if we're invisible so we don't jump.
+            boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
+            if (isWorkspaceVisible) {
+                CellLayout currentChild = (CellLayout) workspace.getChildAt(
+                        workspace.getCurrentPage());
+                isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
+                        && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
+            }
+            if (!isWorkspaceVisible) {
+                workspace.setScaleX(0.92f);
+                workspace.setScaleY(0.92f);
+            }
+        }
+    }
+
+    /**
+     * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
+     * state transition. The UI is force-set to fromState before creating the controller.
+     * @param fromState the initial state for the transition.
+     * @param state the final state for the transition.
+     * @param duration intended duration for normal playback. Use higher duration for better
+     *                accuracy.
+     */
+    public AnimatorPlaybackController createAnimationToNewWorkspace(
+            LauncherState fromState, LauncherState state, long duration) {
+        mConfig.reset();
+        for (StateHandler handler : getStateHandlers()) {
+            handler.setState(fromState);
+        }
+
+        return createAnimationToNewWorkspace(state, duration);
+    }
+
+    /**
      * Creates a {@link AnimatorPlaybackController} that can be used for a controlled
      * state transition.
      * @param state the final state for the transition.
@@ -217,20 +323,31 @@
      */
     public AnimatorPlaybackController createAnimationToNewWorkspace(
             LauncherState state, long duration) {
-        return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration);
+        return createAnimationToNewWorkspace(state, duration, LauncherStateManager.ANIM_ALL);
     }
 
     public AnimatorPlaybackController createAnimationToNewWorkspace(
-            LauncherState state, AnimatorSetBuilder builder, long duration) {
+            LauncherState state, long duration, @AnimationComponents int animComponents) {
+        return createAnimationToNewWorkspace(state, new AnimatorSetBuilder(), duration, null,
+                animComponents);
+    }
+
+    public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
+            AnimatorSetBuilder builder, long duration, Runnable onCancelRunnable,
+            @AnimationComponents int animComponents) {
         mConfig.reset();
         mConfig.userControlled = true;
+        mConfig.animComponents = animComponents;
         mConfig.duration = duration;
-        return AnimatorPlaybackController.wrap(
-                createAnimationToNewWorkspaceInternal(state, builder, null), duration);
+        mConfig.playbackController = AnimatorPlaybackController.wrap(
+                createAnimationToNewWorkspaceInternal(state, builder, null), duration,
+                onCancelRunnable);
+        return mConfig.playbackController;
     }
 
     protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
             AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
+
         for (StateHandler handler : getStateHandlers()) {
             builder.startTag(handler);
             handler.setStateWithAnimation(state, builder, mConfig);
@@ -243,16 +360,8 @@
             public void onAnimationStart(Animator animation) {
                 // Change the internal state only when the transition actually starts
                 onStateTransitionStart(state);
-                if (mStateListener != null) {
-                    mStateListener.onStateTransitionStart(state);
-                }
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (mStateListener != null) {
-                    mStateListener.onStateTransitionComplete(mState);
+                for (int i = mListeners.size() - 1; i >= 0; i--) {
+                    mListeners.get(i).onStateTransitionStart(state);
                 }
             }
 
@@ -263,14 +372,19 @@
                     onCompleteRunnable.run();
                 }
                 onStateTransitionEnd(state);
+                for (int i = mListeners.size() - 1; i >= 0; i--) {
+                    mListeners.get(i).onStateTransitionComplete(state);
+                }
             }
         });
-        mConfig.setAnimation(animation);
+        mConfig.setAnimation(animation, state);
         return mConfig.mCurrentAnimation;
     }
 
     private void onStateTransitionStart(LauncherState state) {
-        mState.onStateDisabled(mLauncher);
+        if (mState != state) {
+            mState.onStateDisabled(mLauncher);
+        }
         mState = state;
         mState.onStateEnabled(mLauncher);
         mLauncher.getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
@@ -279,13 +393,7 @@
             // Only disable clipping if needed, otherwise leave it as previous value.
             mLauncher.getWorkspace().setClipChildren(false);
         }
-
-        // If we are still animating to launcher from an app,
-        // finish it and let this state animation take over.
-        LauncherAppTransitionManager transitionManager = mLauncher.getAppTransitionManager();
-        if (transitionManager != null) {
-            transitionManager.finishLauncherAnimation();
-        }
+        UiFactory.onLauncherStateOrResumeChanged(mLauncher);
     }
 
     private void onStateTransitionEnd(LauncherState state) {
@@ -297,14 +405,15 @@
 
         state.onStateTransitionEnd(mLauncher);
         mLauncher.getWorkspace().setClipChildren(!state.disablePageClipping);
-        mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
         mLauncher.finishAutoCancelActionMode();
 
         if (state == NORMAL) {
             setRestState(null);
         }
 
-        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+        UiFactory.onLauncherStateOrResumeChanged(mLauncher);
+
+        mLauncher.getDragLayer().requestFocus();
     }
 
     public void onWindowFocusChanged() {
@@ -316,6 +425,10 @@
     }
 
     public void moveToRestState() {
+        if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
+            // The user is doing something. Lets not mess it up
+            return;
+        }
         if (mState.disableRestore) {
             goToState(getRestState());
             // Reset history
@@ -338,14 +451,55 @@
         mConfig.reset();
     }
 
+    public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) {
+        clearCurrentAnimation();
+        setCurrentAnimation(controller.getTarget());
+        mConfig.userControlled = true;
+        mConfig.playbackController = controller;
+    }
+
+    /**
+     * Sets the animation as the current state animation, i.e., canceled when
+     * starting another animation and may block some launcher interactions while running.
+     *
+     * @param childAnimations Set of animations with the new target is controlling.
+     */
+    public void setCurrentAnimation(AnimatorSet anim, Animator... childAnimations) {
+        for (Animator childAnim : childAnimations) {
+            if (childAnim == null) {
+                continue;
+            }
+            if (mConfig.playbackController != null
+                    && mConfig.playbackController.getTarget() == childAnim) {
+                clearCurrentAnimation();
+                break;
+            } else if (mConfig.mCurrentAnimation == childAnim) {
+                clearCurrentAnimation();
+                break;
+            }
+        }
+        boolean reapplyNeeded = mConfig.mCurrentAnimation != null;
+        cancelAnimation();
+        if (reapplyNeeded) {
+            reapplyState();
+        }
+        mConfig.setAnimation(anim, null);
+    }
+
+    private void clearCurrentAnimation() {
+        if (mConfig.mCurrentAnimation != null) {
+            mConfig.mCurrentAnimation.removeListener(mConfig);
+            mConfig.mCurrentAnimation = null;
+        }
+        mConfig.playbackController = null;
+    }
+
     private class StartAnimRunnable implements Runnable {
 
         private final AnimatorSet mAnim;
-        private final View mViewToFocus;
 
-        public StartAnimRunnable(AnimatorSet anim, View viewToFocus) {
+        public StartAnimRunnable(AnimatorSet anim) {
             mAnim = anim;
-            mViewToFocus = viewToFocus;
         }
 
         @Override
@@ -353,9 +507,6 @@
             if (mConfig.mCurrentAnimation != mAnim) {
                 return;
             }
-            if (mViewToFocus != null) {
-                mViewToFocus.requestFocus();
-            }
             mAnim.start();
         }
     }
@@ -363,31 +514,66 @@
     public static class AnimationConfig extends AnimatorListenerAdapter {
         public long duration;
         public boolean userControlled;
+        public AnimatorPlaybackController playbackController;
+        public @AnimationComponents int animComponents = ANIM_ALL;
+        private PropertySetter mPropertySetter;
 
         private AnimatorSet mCurrentAnimation;
+        private LauncherState mTargetState;
 
+        /**
+         * Cancels the current animation and resets config variables.
+         */
         public void reset() {
             duration = 0;
             userControlled = false;
+            animComponents = ANIM_ALL;
+            mPropertySetter = null;
+            mTargetState = null;
 
-            if (mCurrentAnimation != null) {
+            if (playbackController != null) {
+                playbackController.getAnimationPlayer().cancel();
+                playbackController.dispatchOnCancel();
+            } else if (mCurrentAnimation != null) {
                 mCurrentAnimation.setDuration(0);
                 mCurrentAnimation.cancel();
-                mCurrentAnimation = null;
             }
+
+            mCurrentAnimation = null;
+            playbackController = null;
+        }
+
+        public PropertySetter getPropertySetter(AnimatorSetBuilder builder) {
+            if (mPropertySetter == null) {
+                mPropertySetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER
+                        : new AnimatedPropertySetter(duration, builder);
+            }
+            return mPropertySetter;
         }
 
         @Override
         public void onAnimationEnd(Animator animation) {
+            if (playbackController != null && playbackController.getTarget() == animation) {
+                playbackController = null;
+            }
             if (mCurrentAnimation == animation) {
                 mCurrentAnimation = null;
             }
         }
 
-        public void setAnimation(AnimatorSet animation) {
+        public void setAnimation(AnimatorSet animation, LauncherState targetState) {
             mCurrentAnimation = animation;
+            mTargetState = targetState;
             mCurrentAnimation.addListener(this);
         }
+
+        public boolean playAtomicComponent() {
+            return (animComponents & ATOMIC_COMPONENT) != 0;
+        }
+
+        public boolean playNonAtomicComponent() {
+            return (animComponents & NON_ATOMIC_COMPONENT) != 0;
+        }
     }
 
     public interface StateHandler {
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
index 462eadb..0028f97 100644
--- a/src/com/android/launcher3/MainProcessInitializer.java
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -20,14 +20,15 @@
 
 import com.android.launcher3.graphics.IconShapeOverride;
 import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.util.ResourceBasedOverride;
 
 /**
  * Utility class to handle one time initializations of the main process
  */
-public class MainProcessInitializer {
+public class MainProcessInitializer implements ResourceBasedOverride {
 
     public static void initialize(Context context) {
-        Utilities.getOverrideObject(
+        Overrides.getObject(
                 MainProcessInitializer.class, context, R.string.main_process_initializer_class)
                 .init(context);
     }
diff --git a/src/com/android/launcher3/OverviewButtonClickListener.java b/src/com/android/launcher3/OverviewButtonClickListener.java
deleted file mode 100644
index dd670d2..0000000
--- a/src/com/android/launcher3/OverviewButtonClickListener.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.android.launcher3;
-
-import android.view.View;
-
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-
-/**
- * A specialized listener for Overview buttons where both clicks and long clicks are logged
- * handled the same via {@link #handleViewClick(View)}.
- */
-public abstract class OverviewButtonClickListener implements View.OnClickListener,
-        View.OnLongClickListener {
-
-    private int mControlType; /** ControlType enum as defined in {@link Action.Touch} */
-
-    public OverviewButtonClickListener(int controlType) {
-        mControlType = controlType;
-    }
-
-    public void attachTo(View v) {
-        v.setOnClickListener(this);
-        v.setOnLongClickListener(this);
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (shouldPerformClick(view)) {
-            handleViewClick(view, Action.Touch.TAP);
-        }
-    }
-
-    @Override
-    public boolean onLongClick(View view) {
-        if (shouldPerformClick(view)) {
-            handleViewClick(view, Action.Touch.LONGPRESS);
-        }
-        return true;
-    }
-
-    private boolean shouldPerformClick(View view) {
-        return !Launcher.getLauncher(view.getContext()).getWorkspace().isSwitchingState();
-    }
-
-    private void handleViewClick(View view, int action) {
-        handleViewClick(view);
-        Launcher.getLauncher(view.getContext()).getUserEventDispatcher()
-                .logActionOnControl(action, mControlType);
-    }
-
-    public abstract void handleViewClick(View view);
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ccb0a95..db5dc66 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -19,19 +19,14 @@
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -46,9 +41,10 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.Interpolator;
+import android.widget.ScrollView;
 
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PropertyListBuilder;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.touch.OverScroll;
 import com.android.launcher3.util.Thunk;
@@ -62,10 +58,9 @@
 public abstract class PagedView<T extends View & PageIndicator> extends ViewGroup {
     private static final String TAG = "PagedView";
     private static final boolean DEBUG = false;
-    protected static final int INVALID_PAGE = -1;
 
-    // the min drag distance for a fling to register, to prevent random page shifts
-    private static final int MIN_LENGTH_FOR_FLING = 25;
+    protected static final int INVALID_PAGE = -1;
+    protected static final ComputePageScrollsLogic SIMPLE_SCROLL_LOGIC = (v) -> v.getVisibility() != GONE;
 
     public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
     public static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
@@ -98,7 +93,6 @@
 
     @ViewDebug.ExportedProperty(category = "launcher")
     protected int mCurrentPage;
-    private int mChildCountOnLastLayout;
 
     @ViewDebug.ExportedProperty(category = "launcher")
     protected int mNextPage = INVALID_PAGE;
@@ -108,31 +102,21 @@
     private VelocityTracker mVelocityTracker;
     protected int mPageSpacing = 0;
 
-    private float mParentDownMotionX;
-    private float mParentDownMotionY;
     private float mDownMotionX;
     private float mDownMotionY;
-    private float mDownScrollX;
-    private float mDragViewBaselineLeft;
     private float mLastMotionX;
     private float mLastMotionXRemainder;
-    private float mLastMotionY;
     private float mTotalMotionX;
 
-    private boolean mCancelTap;
-
-    private int[] mPageScrolls;
+    protected int[] mPageScrolls;
 
     protected final static int TOUCH_STATE_REST = 0;
     protected final static int TOUCH_STATE_SCROLLING = 1;
     protected final static int TOUCH_STATE_PREV_PAGE = 2;
     protected final static int TOUCH_STATE_NEXT_PAGE = 3;
-    protected final static int TOUCH_STATE_REORDERING = 4;
 
     protected int mTouchState = TOUCH_STATE_REST;
 
-    protected OnLongClickListener mLongClickListener;
-
     protected int mTouchSlop;
     private int mMaximumVelocity;
     protected boolean mAllowOverScroll = true;
@@ -156,37 +140,17 @@
     @Thunk int mPageIndicatorViewId;
     protected T mPageIndicator;
 
-    // Reordering
-    // We use the min scale to determine how much to expand the actually PagedView measured
-    // dimensions such that when we are zoomed out, the view is not clipped
-    private static int REORDERING_DROP_REPOSITION_DURATION = 200;
-    @Thunk static int REORDERING_REORDER_REPOSITION_DURATION = 300;
-    private static int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80;
-
-    @Thunk View mDragView;
-    private Runnable mSidePageHoverRunnable;
-    @Thunk int mSidePageHoverIndex = -1;
-    // This variable's scope is only for the duration of startReordering() and endReordering()
-    private boolean mReorderingStarted = false;
-    // This variable's scope is for the duration of startReordering() and after the zoomIn()
-    // animation after endReordering()
-    private boolean mIsReordering;
-    // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition
-    private static final int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2;
-    private int mPostReorderingPreZoomInRemainingAnimationCount;
-    private Runnable mPostReorderingPreZoomInRunnable;
-
     // Convenience/caching
-    private static final Matrix sTmpInvMatrix = new Matrix();
-    private static final float[] sTmpPoint = new float[2];
     private static final Rect sTmpRect = new Rect();
 
     protected final Rect mInsets = new Rect();
-    protected final boolean mIsRtl;
+    protected boolean mIsRtl;
 
     // Similar to the platform implementation of isLayoutValid();
     protected boolean mIsLayoutValid;
 
+    private int[] mTmpIntPair = new int[2];
+
     public PagedView(Context context) {
         this(context, null);
     }
@@ -224,7 +188,10 @@
         mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * density);
         mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * density);
         mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
-        setWillNotDraw(false);
+
+        if (Utilities.ATLEAST_OREO) {
+            setDefaultFocusHighlightEnabled(false);
+        }
     }
 
     protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -236,48 +203,6 @@
         if (mPageIndicatorViewId > -1) {
             mPageIndicator = parent.findViewById(mPageIndicatorViewId);
             mPageIndicator.setMarkersCount(getChildCount());
-            mPageIndicator.setPageDescription(getPageIndicatorDescription());
-        }
-    }
-
-    // Convenience methods to map points from self to parent and vice versa
-    private float[] mapPointFromViewToParent(View v, float x, float y) {
-        sTmpPoint[0] = x;
-        sTmpPoint[1] = y;
-        v.getMatrix().mapPoints(sTmpPoint);
-        sTmpPoint[0] += v.getLeft();
-        sTmpPoint[1] += v.getTop();
-        return sTmpPoint;
-    }
-    private float[] mapPointFromParentToView(View v, float x, float y) {
-        sTmpPoint[0] = x - v.getLeft();
-        sTmpPoint[1] = y - v.getTop();
-        v.getMatrix().invert(sTmpInvMatrix);
-        sTmpInvMatrix.mapPoints(sTmpPoint);
-        return sTmpPoint;
-    }
-
-    private void updateDragViewTranslationDuringDrag() {
-        if (mDragView != null) {
-            float x = (mLastMotionX - mDownMotionX) + (getScrollX() - mDownScrollX) +
-                    (mDragViewBaselineLeft - mDragView.getLeft());
-            float y = mLastMotionY - mDownMotionY;
-            mDragView.setTranslationX(x);
-            mDragView.setTranslationY(y);
-
-            if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): "
-                    + x + ", " + y);
-        }
-    }
-
-    @Override
-    public void setScaleX(float scaleX) {
-        super.setScaleX(scaleX);
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
         }
     }
 
@@ -336,6 +261,7 @@
         // updating current page on the pass.
         if (resetNextPage) {
             mNextPage = INVALID_PAGE;
+            pageEndTransition();
         }
     }
 
@@ -345,6 +271,7 @@
         // updating current page on the pass.
         if (resetNextPage) {
             mNextPage = INVALID_PAGE;
+            pageEndTransition();
         }
     }
 
@@ -381,12 +308,8 @@
     }
 
     private void updatePageIndicator() {
-        // Update the page indicator (when we aren't reordering)
         if (mPageIndicator != null) {
-            mPageIndicator.setPageDescription(getPageIndicatorDescription());
-            if (!isReordering(false)) {
-                mPageIndicator.setActiveMarker(getNextPage());
-            }
+            mPageIndicator.setActiveMarker(getNextPage());
         }
     }
     protected void pageBeginTransition() {
@@ -422,21 +345,6 @@
         mWasInOverscroll = false;
     }
 
-    /**
-     * Registers the specified listener on each page contained in this workspace.
-     *
-     * @param l The listener used to respond to long clicks.
-     */
-    @Override
-    public void setOnLongClickListener(OnLongClickListener l) {
-        mLongClickListener = l;
-        final int count = getPageCount();
-        for (int i = 0; i < count; i++) {
-            getPageAt(i).setOnLongClickListener(l);
-        }
-        super.setOnLongClickListener(l);
-    }
-
     protected int getUnboundedScrollX() {
         return mUnboundedScrollX;
     }
@@ -491,14 +399,6 @@
             mOverScrollX = x;
             super.scrollTo(x, y);
         }
-
-        // Update the last motion events when scrolling
-        if (isReordering(true)) {
-            float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY);
-            mLastMotionX = p[0];
-            mLastMotionY = p[1];
-            updateDragViewTranslationDuringDrag();
-        }
     }
 
     private void sendScrollAccessibilityEvent() {
@@ -522,15 +422,20 @@
         return computeScrollHelper(true);
     }
 
+    protected void announcePageForAccessibility() {
+        if (isAccessibilityEnabled(getContext())) {
+            // Notify the user when the page changes
+            announceForAccessibility(getCurrentPageDescription());
+        }
+    }
+
     protected boolean computeScrollHelper(boolean shouldInvalidate) {
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
             if (getUnboundedScrollX() != mScroller.getCurrX()
                     || getScrollY() != mScroller.getCurrY()
                     || mOverScrollX != mScroller.getCurrX()) {
-                float scaleX = mFreeScroll ? getScaleX() : 1f;
-                int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX));
-                scrollTo(scrollX, mScroller.getCurrY());
+                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
             }
             if (shouldInvalidate) {
                 invalidate();
@@ -550,12 +455,9 @@
                 pageEndTransition();
             }
 
-            onPostReorderingAnimationCompleted();
-            if (isAccessibilityEnabled(getContext())) {
-                // Notify the user when the page changes
-                announceForAccessibility(getCurrentPageDescription());
+            if (canAnnouncePageDescription()) {
+                announcePageForAccessibility();
             }
-            return true;
         }
         return false;
     }
@@ -639,50 +541,21 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         mIsLayoutValid = true;
-        if (getChildCount() == 0) {
-            return;
-        }
-
-        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
         final int childCount = getChildCount();
-
-        final int startIndex = mIsRtl ? childCount - 1 : 0;
-        final int endIndex = mIsRtl ? -1 : childCount;
-        final int delta = mIsRtl ? -1 : 1;
-
-        int verticalPadding = getPaddingTop() + getPaddingBottom();
-
-        int scrollOffsetLeft = mInsets.left + getPaddingLeft();
-        int childLeft = scrollOffsetLeft;
-
         boolean pageScrollChanged = false;
-        if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
+        if (mPageScrolls == null || childCount != mPageScrolls.length) {
             mPageScrolls = new int[childCount];
             pageScrollChanged = true;
         }
 
-        for (int i = startIndex; i != endIndex; i += delta) {
-            final View child = getPageAt(i);
-            if (child.getVisibility() != View.GONE) {
-                int childTop = getPaddingTop() + mInsets.top;
-                childTop += (getMeasuredHeight() - mInsets.top - mInsets.bottom - verticalPadding
-                        - child.getMeasuredHeight()) / 2;
+        if (childCount == 0) {
+            return;
+        }
 
-                final int childWidth = child.getMeasuredWidth();
-                final int childHeight = child.getMeasuredHeight();
+        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
 
-                if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
-                child.layout(childLeft, childTop,
-                        childLeft + child.getMeasuredWidth(), childTop + childHeight);
-
-                final int pageScroll = childLeft - scrollOffsetLeft;
-                if (mPageScrolls[i] != pageScroll) {
-                    pageScrollChanged = true;
-                    mPageScrolls[i] = pageScroll;
-                }
-
-                childLeft += childWidth + mPageSpacing + getChildGap();
-            }
+        if (getPageScrolls(mPageScrolls, true, SIMPLE_SCROLL_LOGIC)) {
+            pageScrollChanged = true;
         }
 
         final LayoutTransition transition = getLayoutTransition();
@@ -717,11 +590,54 @@
         if (mScroller.isFinished() && pageScrollChanged) {
             setCurrentPage(getNextPage());
         }
-        mChildCountOnLastLayout = childCount;
+    }
 
-        if (isReordering(true)) {
-            updateDragViewTranslationDuringDrag();
+    /**
+     * Initializes {@code outPageScrolls} with scroll positions for view at that index. The length
+     * of {@code outPageScrolls} should be same as the the childCount
+     *
+     */
+    protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
+            ComputePageScrollsLogic scrollLogic) {
+        final int childCount = getChildCount();
+
+        final int startIndex = mIsRtl ? childCount - 1 : 0;
+        final int endIndex = mIsRtl ? -1 : childCount;
+        final int delta = mIsRtl ? -1 : 1;
+
+        final int verticalCenter = (getPaddingTop() + getMeasuredHeight() + mInsets.top
+                - mInsets.bottom - getPaddingBottom()) / 2;
+
+        final int scrollOffsetLeft = mInsets.left + getPaddingLeft();
+        final int scrollOffsetRight = getWidth() - getPaddingRight() - mInsets.right;
+        boolean pageScrollChanged = false;
+
+        for (int i = startIndex, childLeft = scrollOffsetLeft; i != endIndex; i += delta) {
+            final View child = getPageAt(i);
+            if (scrollLogic.shouldIncludeView(child)) {
+                final int childWidth = child.getMeasuredWidth();
+                final int childRight = childLeft + childWidth;
+
+                if (layoutChildren) {
+                    final int childHeight = child.getMeasuredHeight();
+                    final int childTop = verticalCenter - childHeight / 2;
+                    child.layout(childLeft, childTop, childRight, childTop + childHeight);
+                }
+
+                // In case the pages are of different width, align the page to left or right edge
+                // based on the orientation.
+                final int pageScroll = mIsRtl
+                        ? (childLeft - scrollOffsetLeft)
+                        : Math.max(0, childRight  - scrollOffsetRight);
+                if (outPageScrolls[i] != pageScroll) {
+                    pageScrollChanged = true;
+                    outPageScrolls[i] = pageScroll;
+                }
+
+                childLeft += childWidth + mPageSpacing + getChildGap();
+            }
         }
+        return pageScrollChanged;
     }
 
     protected int getChildGap() {
@@ -758,11 +674,13 @@
 
     @Override
     public void onViewAdded(View child) {
+        super.onViewAdded(child);
         dispatchPageCountChanged();
     }
 
     @Override
     public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
         mCurrentPage = validateNewPage(mCurrentPage);
         dispatchPageCountChanged();
     }
@@ -776,7 +694,11 @@
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         int page = indexToPage(indexOfChild(child));
         if (page != mCurrentPage || !mScroller.isFinished()) {
-            snapToPage(page);
+            if (immediate) {
+                setCurrentPage(page);
+            } else {
+                snapToPage(page);
+            }
             return true;
         }
         return false;
@@ -813,11 +735,13 @@
         if (direction == View.FOCUS_LEFT) {
             if (getCurrentPage() > 0) {
                 snapToPage(getCurrentPage() - 1);
+                getChildAt(getCurrentPage() - 1).requestFocus(direction);
                 return true;
             }
         } else if (direction == View.FOCUS_RIGHT) {
             if (getCurrentPage() < getPageCount() - 1) {
                 snapToPage(getCurrentPage() + 1);
+                getChildAt(getCurrentPage() + 1).requestFocus(direction);
                 return true;
             }
         }
@@ -939,12 +863,7 @@
                 // Remember location of down touch
                 mDownMotionX = x;
                 mDownMotionY = y;
-                mDownScrollX = getScrollX();
                 mLastMotionX = x;
-                mLastMotionY = y;
-                float[] p = mapPointFromViewToParent(this, x, y);
-                mParentDownMotionX = p[0];
-                mParentDownMotionY = p[1];
                 mLastMotionXRemainder = 0;
                 mTotalMotionX = 0;
                 mActivePointerId = ev.getPointerId(0);
@@ -992,6 +911,10 @@
         return mTouchState != TOUCH_STATE_REST;
     }
 
+    public boolean isHandlingTouch() {
+        return mTouchState != TOUCH_STATE_REST;
+    }
+
     protected void determineScrollingStart(MotionEvent ev) {
         determineScrollingStart(ev, 1.0f);
     }
@@ -1103,22 +1026,12 @@
         dampedOverScroll(amount);
     }
 
-    /**
-     * return true if freescroll has been enabled, false otherwise
-     */
-    protected void enableFreeScroll() {
-        enableFreeScroll(false);
-    }
 
     protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
         setEnableFreeScroll(true);
         mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
     }
 
-    protected void disableFreeScroll() {
-        setEnableFreeScroll(false);
-    }
-
     private void setEnableFreeScroll(boolean freeScroll) {
         boolean wasFreeScroll = mFreeScroll;
         mFreeScroll = freeScroll;
@@ -1136,27 +1049,6 @@
         mAllowOverScroll = enable;
     }
 
-    private int getNearestHoverOverPageIndex() {
-        if (mDragView != null) {
-            int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2)
-                    + mDragView.getTranslationX());
-            int minDistance = Integer.MAX_VALUE;
-            int minIndex = indexOfChild(mDragView);
-            int maxPageNo = getChildCount() - 1;
-            for (int i = 0; i <= maxPageNo; i++) {
-                View page = getPageAt(i);
-                int pageX = (page.getLeft() + page.getMeasuredWidth() / 2);
-                int d = Math.abs(dragX - pageX);
-                if (d < minDistance) {
-                    minIndex = i;
-                    minDistance = d;
-                }
-            }
-            return minIndex;
-        }
-        return -1;
-    }
-
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         super.onTouchEvent(ev);
@@ -1180,11 +1072,7 @@
 
             // Remember where the motion event started
             mDownMotionX = mLastMotionX = ev.getX();
-            mDownMotionY = mLastMotionY = ev.getY();
-            mDownScrollX = getScrollX();
-            float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-            mParentDownMotionX = p[0];
-            mParentDownMotionY = p[1];
+            mDownMotionY = ev.getY();
             mLastMotionXRemainder = 0;
             mTotalMotionX = 0;
             mActivePointerId = ev.getPointerId(0);
@@ -1217,82 +1105,6 @@
                 } else {
                     awakenScrollBars();
                 }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-
-                // Find the closest page to the touch point
-                final int dragViewIndex = indexOfChild(mDragView);
-
-                if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
-                if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
-                if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
-
-                final int pageUnderPointIndex = getNearestHoverOverPageIndex();
-                // Do not allow any page to be moved to 0th position.
-                if (pageUnderPointIndex > 0 && pageUnderPointIndex != indexOfChild(mDragView)) {
-                    if (0 <= pageUnderPointIndex && pageUnderPointIndex <= getPageCount() - 1 &&
-                            pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
-                        mSidePageHoverIndex = pageUnderPointIndex;
-                        mSidePageHoverRunnable = new Runnable() {
-                            @Override
-                            public void run() {
-                                // Setup the scroll to the correct page before we swap the views
-                                snapToPage(pageUnderPointIndex);
-
-                                // For each of the pages between the paged view and the drag view,
-                                // animate them from the previous position to the new position in
-                                // the layout (as a result of the drag view moving in the layout)
-                                int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
-                                int lowerIndex = (dragViewIndex < pageUnderPointIndex) ?
-                                        dragViewIndex + 1 : pageUnderPointIndex;
-                                int upperIndex = (dragViewIndex > pageUnderPointIndex) ?
-                                        dragViewIndex - 1 : pageUnderPointIndex;
-                                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                                    View v = getChildAt(i);
-                                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                                    // drag view all subsequent views to pageUnderPointIndex will
-                                    // shift down.
-                                    int oldX = getChildOffset(i);
-                                    int newX = getChildOffset(i + shiftDelta);
-
-                                    // Animate the view translation from its old position to its new
-                                    // position
-                                    ObjectAnimator anim = (ObjectAnimator) v.getTag();
-                                    if (anim != null) {
-                                        anim.cancel();
-                                    }
-
-                                    v.setTranslationX(oldX - newX);
-                                    anim = LauncherAnimUtils.ofFloat(v, View.TRANSLATION_X, 0);
-                                    anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
-                                    anim.start();
-                                    v.setTag(anim);
-                                }
-
-                                removeView(mDragView);
-                                addView(mDragView, pageUnderPointIndex);
-                                mSidePageHoverIndex = -1;
-                                if (mPageIndicator != null) {
-                                    mPageIndicator.setActiveMarker(getNextPage());
-                                }
-                            }
-                        };
-                        postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
-                    }
-                } else {
-                    removeCallbacks(mSidePageHoverRunnable);
-                    mSidePageHoverIndex = -1;
-                }
             } else {
                 determineScrollingStart(ev);
             }
@@ -1312,9 +1124,7 @@
                         SIGNIFICANT_MOVE_THRESHOLD;
 
                 mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
-
-                boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
-                        shouldFlingForVelocity(velocityX);
+                boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
 
                 if (!mFreeScroll) {
                     // In the case that the page is moved far to one direction and then is flung
@@ -1360,11 +1170,19 @@
                     mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
                     int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
                     int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
-                    if (mSettleOnPageInFreeScroll && unscaledScrollX > firstPageScroll
-                            && unscaledScrollX < lastPageScroll) {
-                        // Make sure we land directly on a page. If flinging past one of the ends,
-                        // don't change the velocity as it will get stopped at the end anyway.
-                        mScroller.setFinalX((int) (getScrollForPage(mNextPage) * getScaleX()));
+                    if (mSettleOnPageInFreeScroll && unscaledScrollX > 0
+                            && unscaledScrollX < mMaxScrollX) {
+                        // If scrolling ends in the half of the added space that is closer to the
+                        // end, settle to the end. Otherwise snap to the nearest page.
+                        // If flinging past one of the ends, don't change the velocity as it will
+                        // get stopped at the end anyway.
+                        final int finalX = unscaledScrollX < firstPageScroll / 2 ?
+                                0 :
+                                unscaledScrollX > (lastPageScroll + mMaxScrollX) / 2 ?
+                                        mMaxScrollX :
+                                        getScrollForPage(mNextPage);
+
+                        mScroller.setFinalX((int) (finalX * getScaleX()));
                         // Ensure the scroll/snap doesn't happen too fast;
                         int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
                                 - mScroller.getDuration();
@@ -1395,25 +1213,8 @@
                 } else {
                     snapToDestination();
                 }
-            } else if (mTouchState == TOUCH_STATE_REORDERING) {
-                // Update the last motion position
-                mLastMotionX = ev.getX();
-                mLastMotionY = ev.getY();
-
-                // Update the parent down so that our zoom animations take this new movement into
-                // account
-                float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
-                mParentDownMotionX = pt[0];
-                mParentDownMotionY = pt[1];
-                updateDragViewTranslationDuringDrag();
-            } else {
-                if (!mCancelTap) {
-                    onUnhandledTap(ev);
-                }
             }
 
-            // Remove the callback to wait for the side page hover timeout
-            removeCallbacks(mSidePageHoverRunnable);
             // End any intermediate reordering states
             resetTouchState();
             break;
@@ -1441,8 +1242,6 @@
 
     private void resetTouchState() {
         releaseVelocityTracker();
-        endReordering();
-        mCancelTap = false;
         mTouchState = TOUCH_STATE_REST;
         mActivePointerId = INVALID_POINTER;
     }
@@ -1456,10 +1255,6 @@
     protected void onScrollInteractionEnd() {
     }
 
-    protected void onUnhandledTap(MotionEvent ev) {
-        Launcher.getLauncher(getContext()).onClick(this);
-    }
-
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
@@ -1516,7 +1311,6 @@
             // TODO: Make this decision more intelligent.
             final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
             mLastMotionX = mDownMotionX = ev.getX(newPointerIndex);
-            mLastMotionY = ev.getY(newPointerIndex);
             mLastMotionXRemainder = 0;
             mActivePointerId = ev.getPointerId(newPointerIndex);
             if (mVelocityTracker != null) {
@@ -1627,7 +1421,7 @@
         return snapToPage(whichPage, duration, false, null);
     }
 
-    protected boolean snapToPage(int whichPage, int duration, TimeInterpolator interpolator) {
+    public boolean snapToPage(int whichPage, int duration, TimeInterpolator interpolator) {
         return snapToPage(whichPage, duration, false, interpolator);
     }
 
@@ -1646,6 +1440,16 @@
 
     protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate,
             TimeInterpolator interpolator) {
+        if (mFirstLayout) {
+            setCurrentPage(whichPage);
+            return false;
+        }
+
+        if (FeatureFlags.IS_DOGFOOD_BUILD) {
+            duration *= Settings.System.getFloat(getContext().getContentResolver(),
+                    Settings.System.WINDOW_ANIMATION_SCALE, 1);
+        }
+
         whichPage = validateNewPage(whichPage);
 
         mNextPage = whichPage;
@@ -1685,145 +1489,31 @@
         return Math.abs(delta) > 0;
     }
 
-    public void scrollLeft() {
-        if (getNextPage() > 0) snapToPage(getNextPage() - 1);
-    }
-
-    public void scrollRight() {
-        if (getNextPage() < getChildCount() -1) snapToPage(getNextPage() + 1);
-    }
-
-    @Override
-    public boolean performLongClick() {
-        mCancelTap = true;
-        return super.performLongClick();
-    }
-
-    public static class SavedState extends BaseSavedState {
-        int currentPage = -1;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        @Thunk SavedState(Parcel in) {
-            super(in);
-            currentPage = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(currentPage);
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR =
-                new Parcelable.Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    // Animate the drag view back to the original position
-    private void animateDragViewToOriginalPosition() {
-        if (mDragView != null) {
-            Animator anim = LauncherAnimUtils.ofPropertyValuesHolder(mDragView,
-                    new PropertyListBuilder()
-                            .scale(1)
-                            .translationX(0)
-                            .translationY(0)
-                            .build())
-                    .setDuration(REORDERING_DROP_REPOSITION_DURATION);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    onPostReorderingAnimationCompleted();
-                }
-            });
-            anim.start();
-        }
-    }
-
-    public void onStartReordering() {
-        // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
-        mTouchState = TOUCH_STATE_REORDERING;
-        mIsReordering = true;
-
-        // We must invalidate to trigger a redraw to update the layers such that the drag view
-        // is always drawn on top
-        invalidate();
-    }
-
-    @Thunk void onPostReorderingAnimationCompleted() {
-        // Trigger the callback when reordering has settled
-        --mPostReorderingPreZoomInRemainingAnimationCount;
-        if (mPostReorderingPreZoomInRunnable != null &&
-                mPostReorderingPreZoomInRemainingAnimationCount == 0) {
-            mPostReorderingPreZoomInRunnable.run();
-            mPostReorderingPreZoomInRunnable = null;
-        }
-    }
-
-    public void onEndReordering() {
-        mIsReordering = false;
-    }
-
-    public boolean startReordering(View v) {
-        int dragViewIndex = indexOfChild(v);
-
-        // Do not allow the first page to be moved around
-        if (mTouchState != TOUCH_STATE_REST || dragViewIndex <= 0) return false;
-
-        // Check if we are within the reordering range
-        if (0 <= dragViewIndex && dragViewIndex <= getPageCount() - 1) {
-            // Find the drag view under the pointer
-            mDragView = getChildAt(dragViewIndex);
-            mDragView.animate().scaleX(1.15f).scaleY(1.15f).setDuration(100).start();
-            mDragViewBaselineLeft = mDragView.getLeft();
-            mReorderingStarted = true;
-
-            snapToPage(getPageNearestToCenterOfScreen());
-            disableFreeScroll();
-            onStartReordering();
+    public boolean scrollLeft() {
+        if (getNextPage() > 0) {
+            snapToPage(getNextPage() - 1);
             return true;
         }
         return false;
     }
 
-    boolean isReordering(boolean testTouchState) {
-        boolean state = mIsReordering;
-        if (testTouchState) {
-            state &= (mTouchState == TOUCH_STATE_REORDERING);
+    public boolean scrollRight() {
+        if (getNextPage() < getChildCount() - 1) {
+            snapToPage(getNextPage() + 1);
+            return true;
         }
-        return state;
+        return false;
     }
-    void endReordering() {
-        // For simplicity, we call endReordering sometimes even if reordering was never started.
-        // In that case, we don't want to do anything.
-        if (!mReorderingStarted) return;
-        mReorderingStarted = false;
 
-        mPostReorderingPreZoomInRunnable = new Runnable() {
-            public void run() {
-                // If we haven't flung-to-delete the current child,
-                // then we just animate the drag view back into position
-                onEndReordering();
+    @Override
+    public CharSequence getAccessibilityClassName() {
+        // Some accessibility services have special logic for ScrollView. Since we provide same
+        // accessibility info as ScrollView, inform the service to handle use the same way.
+        return ScrollView.class.getName();
+    }
 
-                enableFreeScroll();
-            }
-        };
-
-        mPostReorderingPreZoomInRemainingAnimationCount =
-                NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
-        // Snap to the current page
-        snapToPage(indexOfChild(mDragView), 0);
-        // Animate the drag view back to the front position
-        animateDragViewToOriginalPosition();
+    protected boolean isPageOrderFlipped() {
+        return false;
     }
 
     /* Accessibility */
@@ -1831,14 +1521,16 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
+        final boolean pagesFlipped = isPageOrderFlipped();
         info.setScrollable(getPageCount() > 1);
         if (getCurrentPage() < getPageCount() - 1) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
+                    : AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
         }
         if (getCurrentPage() > 0) {
-            info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+            info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
+                    : AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
         }
-        info.setClassName(getClass().getName());
 
         // Accessibility-wise, PagedView doesn't support long click, so disabling it.
         // Besides disabling the accessibility long-click, this also prevents this view from getting
@@ -1866,25 +1558,25 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
+        final boolean pagesFlipped = isPageOrderFlipped();
         switch (action) {
             case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                if (getCurrentPage() < getPageCount() - 1) {
-                    scrollRight();
+                if (pagesFlipped ? scrollLeft() : scrollRight()) {
                     return true;
                 }
             } break;
             case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                if (getCurrentPage() > 0) {
-                    scrollLeft();
+                if (pagesFlipped ? scrollRight() : scrollLeft()) {
                     return true;
                 }
-            } break;
+            }
+            break;
         }
         return false;
     }
 
-    protected String getPageIndicatorDescription() {
-        return getCurrentPageDescription();
+    protected boolean canAnnouncePageDescription() {
+        return true;
     }
 
     protected String getCurrentPageDescription() {
@@ -1892,8 +1584,45 @@
                 getNextPage() + 1, getChildCount());
     }
 
-    @Override
-    public boolean onHoverEvent(android.view.MotionEvent event) {
-        return true;
+    protected float getDownMotionX() {
+        return mDownMotionX;
+    }
+
+    protected float getDownMotionY() {
+        return mDownMotionY;
+    }
+
+    protected interface ComputePageScrollsLogic {
+
+        boolean shouldIncludeView(View view);
+    }
+
+    public int[] getVisibleChildrenRange() {
+        float visibleLeft = 0;
+        float visibleRight = visibleLeft + getMeasuredWidth();
+        float scaleX = getScaleX();
+        if (scaleX < 1 && scaleX > 0) {
+            float mid = getMeasuredWidth() / 2;
+            visibleLeft = mid - ((mid - visibleLeft) / scaleX);
+            visibleRight = mid + ((visibleRight - mid) / scaleX);
+        }
+
+        int leftChild = -1;
+        int rightChild = -1;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getPageAt(i);
+
+            float left = child.getLeft() + child.getTranslationX() - getScrollX();
+            if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) {
+                if (leftChild == -1) {
+                    leftChild = i;
+                }
+                rightChild = i;
+            }
+        }
+        mTmpIntPair[0] = leftChild;
+        mTmpIntPair[1] = rightChild;
+        return mTmpIntPair;
     }
 }
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
similarity index 61%
rename from src/com/android/launcher3/UninstallDropTarget.java
rename to src/com/android/launcher3/SecondaryDropTarget.java
index 68a441a..76e85e2 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -1,8 +1,17 @@
 package com.android.launcher3;
 
+import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE;
+
 import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_MASK;
 import static com.android.launcher3.ItemInfoWithIcon.FLAG_SYSTEM_NO;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
+import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
 
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -20,27 +29,35 @@
 import android.widget.Toast;
 
 import com.android.launcher3.Launcher.OnResumeCallback;
-import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.LoggerUtils;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.Themes;
 
 import java.net.URISyntaxException;
 
-public class UninstallDropTarget extends ButtonDropTarget implements OnAlarmListener {
+/**
+ * Drop target which provides a secondary option for an item.
+ *    For app targets: shows as uninstall
+ *    For configurable widgets: shows as setup
+ */
+public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmListener {
 
-    private static final String TAG = "UninstallDropTarget";
+    private static final String TAG = "SecondaryDropTarget";
 
     private static final long CACHE_EXPIRE_TIMEOUT = 5000;
     private final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);
 
     private final Alarm mCacheExpireAlarm;
 
-    public UninstallDropTarget(Context context, AttributeSet attrs) {
+    protected int mCurrentAccessibilityAction = -1;
+    public SecondaryDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
+    public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         mCacheExpireAlarm = new Alarm();
@@ -50,13 +67,24 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        setupUi();
+        setupUi(UNINSTALL);
     }
 
-    protected void setupUi() {
-        // Get the hover color
-        mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
-        setDrawable(R.drawable.ic_uninstall_shadow);
+    protected void setupUi(int action) {
+        if (action == mCurrentAccessibilityAction) {
+            return;
+        }
+        mCurrentAccessibilityAction = action;
+
+        if (action == UNINSTALL) {
+            mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
+            setDrawable(R.drawable.ic_uninstall_shadow);
+            updateText(R.string.uninstall_drop_target_label);
+        } else {
+            mHoverColor = Themes.getColorAccent(getContext());
+            setDrawable(R.drawable.ic_setup_shadow);
+            updateText(R.string.gadget_setup_text);
+        }
     }
 
     @Override
@@ -66,11 +94,33 @@
 
     @Override
     public int getAccessibilityAction() {
-        return LauncherAccessibilityDelegate.UNINSTALL;
+        return mCurrentAccessibilityAction;
+    }
+
+    @Override
+    public Target getDropTargetForLogging() {
+        Target t = LoggerUtils.newTarget(Target.Type.CONTROL);
+        t.controlType = mCurrentAccessibilityAction == UNINSTALL ? ControlType.UNINSTALL_TARGET
+                : ControlType.SETTINGS_BUTTON;
+        return t;
     }
 
     @Override
     protected boolean supportsDrop(ItemInfo info) {
+        return supportsAccessibilityDrop(info, getViewUnderDrag(info));
+    }
+
+    @Override
+    public boolean supportsAccessibilityDrop(ItemInfo info, View view) {
+        if (view instanceof AppWidgetHostView) {
+            if (getReconfigurableWidgetId(view) != INVALID_APPWIDGET_ID) {
+                setupUi(RECONFIGURE);
+                return true;
+            }
+            return false;
+        }
+
+        setupUi(UNINSTALL);
         Boolean uninstallDisabled = mUninstallDisabledCache.get(info.user);
         if (uninstallDisabled == null) {
             UserManager userManager =
@@ -126,7 +176,7 @@
 
     @Override
     public void completeDrop(final DragObject d) {
-        ComponentName target = performDropAction(d.dragInfo);
+        ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo);
         if (d.dragSource instanceof DeferredOnComplete) {
             DeferredOnComplete deferred = (DeferredOnComplete) d.dragSource;
             if (target != null) {
@@ -138,11 +188,48 @@
         }
     }
 
+    private View getViewUnderDrag(ItemInfo info) {
+        if (info instanceof LauncherAppWidgetInfo && info.container == CONTAINER_DESKTOP &&
+                mLauncher.getWorkspace().getDragInfo() != null) {
+            return mLauncher.getWorkspace().getDragInfo().cell;
+        }
+        return null;
+    }
+
+    /**
+     * Verifies that the view is an reconfigurable widget and returns the corresponding widget Id,
+     * otherwise return {@code INVALID_APPWIDGET_ID}
+     */
+    private int getReconfigurableWidgetId(View view) {
+        if (!(view instanceof AppWidgetHostView)) {
+            return INVALID_APPWIDGET_ID;
+        }
+        AppWidgetHostView hostView = (AppWidgetHostView) view;
+        AppWidgetProviderInfo widgetInfo = hostView.getAppWidgetInfo();
+        if (widgetInfo == null || widgetInfo.configure == null) {
+            return INVALID_APPWIDGET_ID;
+        }
+        if ( (LauncherAppWidgetProviderInfo.fromProviderInfo(getContext(), widgetInfo)
+                .getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) == 0) {
+            return INVALID_APPWIDGET_ID;
+        }
+        return hostView.getAppWidgetId();
+    }
+
     /**
      * Performs the drop action and returns the target component for the dragObject or null if
      * the action was not performed.
      */
-    protected ComponentName performDropAction(ItemInfo info) {
+    protected ComponentName performDropAction(View view, ItemInfo info) {
+        if (mCurrentAccessibilityAction == RECONFIGURE) {
+            int widgetId = getReconfigurableWidgetId(view);
+            if (widgetId != INVALID_APPWIDGET_ID) {
+                mLauncher.getAppWidgetHost().startConfigActivity(mLauncher, widgetId, -1);
+            }
+            return null;
+        }
+        // else: mCurrentAccessibilityAction == UNINSTALL
+
         ComponentName cn = getUninstallTarget(info);
         if (cn == null) {
             // System applications cannot be installed. For now, show a toast explaining that.
@@ -164,7 +251,7 @@
 
     @Override
     public void onAccessibilityDrop(View view, ItemInfo item) {
-        performDropAction(item);
+        performDropAction(view, item);
     }
 
     /**
@@ -203,7 +290,7 @@
                     .getApplicationInfo(mPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES,
                             mDragObject.dragInfo.user) == null) {
                 mDragObject.dragSource = mOriginal;
-                mOriginal.onDropCompleted(UninstallDropTarget.this, mDragObject, true);
+                mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
             } else {
                 sendFailure();
             }
@@ -212,7 +299,7 @@
         public void sendFailure() {
             mDragObject.dragSource = mOriginal;
             mDragObject.cancelled = true;
-            mOriginal.onDropCompleted(UninstallDropTarget.this, mDragObject, false);
+            mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, false);
         }
     }
 }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index edb7ff5..b0da6b9 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -67,11 +67,9 @@
         SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
         UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
 
-        if (Process.myUserHandle().equals(user)) {
-            if (TextUtils.isEmpty(info.getAppPackageName()) ||
-                    info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
-                return;
-            }
+        if (TextUtils.isEmpty(info.getAppPackageName()) ||
+                info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
+            return;
         }
 
         queueAppIconAddition(context, info.getAppPackageName(), user);
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index d40ac8f..8589b7e 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -16,31 +16,46 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
+import static com.android.launcher3.states.RotationHelper.getAllowRotationDefaultValue;
+
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.os.Build;
 import android.os.Bundle;
 import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
 import android.provider.Settings;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.Adapter;
+import android.widget.ListView;
 
 import com.android.launcher3.graphics.IconShapeOverride;
 import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.ListViewHighlighter;
 import com.android.launcher3.util.SettingsObserver;
 import com.android.launcher3.views.ButtonPreference;
 
+import java.util.Objects;
+
 /**
  * Settings activity for Launcher. Currently implements the following setting: Allow rotation
  */
-public class SettingsActivity extends Activity {
+public class SettingsActivity extends Activity
+        implements PreferenceFragment.OnPreferenceStartFragmentCallback {
 
     private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
     /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
@@ -48,50 +63,66 @@
     /** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
     private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
 
+    private static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
+    private static final String EXTRA_SHOW_FRAGMENT_ARGS = ":settings:show_fragment_args";
+    private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
+    private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         if (savedInstanceState == null) {
+            Fragment f = Fragment.instantiate(this, getString(R.string.settings_fragment_name));
             // Display the fragment as the main content.
             getFragmentManager().beginTransaction()
-                    .replace(android.R.id.content, new LauncherSettingsFragment())
+                    .replace(android.R.id.content, f)
                     .commit();
         }
     }
 
+    protected PreferenceFragment getNewFragment() {
+        return new LauncherSettingsFragment();
+    }
+
+    @Override
+    public boolean onPreferenceStartFragment(
+            PreferenceFragment preferenceFragment, Preference pref) {
+        Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
+        if (f instanceof DialogFragment) {
+            ((DialogFragment) f).show(getFragmentManager(), pref.getKey());
+        } else {
+            getFragmentManager()
+                    .beginTransaction()
+                    .replace(android.R.id.content, f)
+                    .addToBackStack(pref.getKey())
+                    .commit();
+        }
+        return true;
+    }
+
     /**
      * This fragment shows the launcher preferences.
      */
     public static class LauncherSettingsFragment extends PreferenceFragment {
 
-        private SystemDisplayRotationLockObserver mRotationLockObserver;
         private IconBadgingObserver mIconBadgingObserver;
 
+        private String mPreferenceKey;
+        private boolean mPreferenceHighlighted = false;
+
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
+            if (savedInstanceState != null) {
+                mPreferenceHighlighted = savedInstanceState.getBoolean(SAVE_HIGHLIGHTED_KEY);
+            }
+
             getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
             addPreferencesFromResource(R.xml.launcher_preferences);
 
             ContentResolver resolver = getActivity().getContentResolver();
 
-            // Setup allow rotation preference
-            Preference rotationPref = findPreference(Utilities.ALLOW_ROTATION_PREFERENCE_KEY);
-            if (getResources().getBoolean(R.bool.allow_rotation)) {
-                // Launcher supports rotation by default. No need to show this setting.
-                getPreferenceScreen().removePreference(rotationPref);
-            } else {
-                mRotationLockObserver = new SystemDisplayRotationLockObserver(rotationPref, resolver);
-
-                // Register a content observer to listen for system setting changes while
-                // this UI is active.
-                mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION);
-
-                // Initialize the UI once
-                rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
-            }
-
             ButtonPreference iconBadgingPref =
                     (ButtonPreference) findPreference(ICON_BADGING_PREFERENCE_KEY);
             if (!Utilities.ATLEAST_OREO) {
@@ -115,41 +146,94 @@
                     getPreferenceScreen().removePreference(iconShapeOverride);
                 }
             }
+
+            // Setup allow rotation preference
+            Preference rotationPref = findPreference(ALLOW_ROTATION_PREFERENCE_KEY);
+            if (getResources().getBoolean(R.bool.allow_rotation)) {
+                // Launcher supports rotation by default. No need to show this setting.
+                getPreferenceScreen().removePreference(rotationPref);
+            } else {
+                // Initialize the UI once
+                rotationPref.setDefaultValue(getAllowRotationDefaultValue());
+            }
+        }
+
+        @Override
+        public void onSaveInstanceState(Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
+        }
+
+        @Override
+        public void onResume() {
+            super.onResume();
+
+            Intent intent = getActivity().getIntent();
+            mPreferenceKey = intent.getStringExtra(EXTRA_FRAGMENT_ARG_KEY);
+            if (isAdded() && !mPreferenceHighlighted && !TextUtils.isEmpty(mPreferenceKey)) {
+                getView().postDelayed(this::highlightPreference, DELAY_HIGHLIGHT_DURATION_MILLIS);
+            }
+        }
+
+        private void highlightPreference() {
+            Preference pref = findPreference(mPreferenceKey);
+            if (pref == null || getPreferenceScreen() == null) {
+                return;
+            }
+            PreferenceScreen screen = getPreferenceScreen();
+            if (Utilities.ATLEAST_OREO) {
+                screen = selectPreferenceRecursive(pref, screen);
+            }
+            if (screen == null) {
+                return;
+            }
+
+            View root = screen.getDialog() != null
+                    ? screen.getDialog().getWindow().getDecorView() : getView();
+            ListView list = root.findViewById(android.R.id.list);
+            if (list == null || list.getAdapter() == null) {
+                return;
+            }
+            Adapter adapter = list.getAdapter();
+
+            // Find the position
+            int position = -1;
+            for (int i = adapter.getCount() - 1; i >= 0; i--) {
+                if (pref == adapter.getItem(i)) {
+                    position = i;
+                    break;
+                }
+            }
+            new ListViewHighlighter(list, position);
+            mPreferenceHighlighted = true;
         }
 
         @Override
         public void onDestroy() {
-            if (mRotationLockObserver != null) {
-                mRotationLockObserver.unregister();
-                mRotationLockObserver = null;
-            }
             if (mIconBadgingObserver != null) {
                 mIconBadgingObserver.unregister();
                 mIconBadgingObserver = null;
             }
             super.onDestroy();
         }
-    }
 
-    /**
-     * Content observer which listens for system auto-rotate setting changes, and enables/disables
-     * the launcher rotation setting accordingly.
-     */
-    private static class SystemDisplayRotationLockObserver extends SettingsObserver.System {
+        @TargetApi(Build.VERSION_CODES.O)
+        private PreferenceScreen selectPreferenceRecursive(
+                Preference pref, PreferenceScreen topParent) {
+            if (!(pref.getParent() instanceof PreferenceScreen)) {
+                return null;
+            }
 
-        private final Preference mRotationPref;
-
-        public SystemDisplayRotationLockObserver(
-                Preference rotationPref, ContentResolver resolver) {
-            super(resolver);
-            mRotationPref = rotationPref;
-        }
-
-        @Override
-        public void onSettingChanged(boolean enabled) {
-            mRotationPref.setEnabled(enabled);
-            mRotationPref.setSummary(enabled
-                    ? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc);
+            PreferenceScreen parent = (PreferenceScreen) pref.getParent();
+            if (Objects.equals(parent.getKey(), topParent.getKey())) {
+                return parent;
+            } else if (selectPreferenceRecursive(parent, topParent) != null) {
+                ((PreferenceScreen) parent.getParent())
+                        .onItemClick(null, null, parent.getOrder(), 0);
+                return parent;
+            } else {
+                return null;
+            }
         }
     }
 
@@ -222,9 +306,13 @@
         @Override
         public void onClick(DialogInterface dialogInterface, int i) {
             ComponentName cn = new ComponentName(getActivity(), NotificationListener.class);
+            Bundle showFragmentArgs = new Bundle();
+            showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString());
+
             Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)
                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-                    .putExtra(":settings:fragment_args_key", cn.flattenToString());
+                    .putExtra(EXTRA_FRAGMENT_ARG_KEY, cn.flattenToString())
+                    .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs);
             getActivity().startActivity(intent);
         }
     }
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 1a63326..baf6d87 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -16,9 +16,12 @@
 
 package com.android.launcher3;
 
+import static android.view.MotionEvent.ACTION_DOWN;
+
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Rect;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -174,6 +177,15 @@
     }
 
     @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) {
+            // Dont let children handle touch, if we are not visible.
+            return true;
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    @Override
     public boolean shouldDelayChildPressedState() {
         return false;
     }
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index ec608ca..8588c7a 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -79,7 +79,7 @@
      * A message to display when the user tries to start a disabled shortcut.
      * This is currently only used for deep shortcuts.
      */
-    CharSequence disabledMessage;
+    public CharSequence disabledMessage;
 
     public int status;
 
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index d559b44..7c5bb1a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.app.ActivityManager;
 import android.app.WallpaperManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -31,12 +32,14 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Message;
 import android.os.PowerManager;
 import android.os.TransactionTooLargeException;
-import android.support.v4.os.BuildCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -46,13 +49,13 @@
 import android.util.Pair;
 import android.util.TypedValue;
 import android.view.View;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.config.FeatureFlags;
 
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.HashSet;
@@ -80,7 +83,8 @@
     private static final Matrix sMatrix = new Matrix();
     private static final Matrix sInverseMatrix = new Matrix();
 
-    public static final boolean ATLEAST_P = BuildCompat.isAtLeastP();
+    public static final boolean ATLEAST_P =
+            Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
 
     public static final boolean ATLEAST_OREO_MR1 =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1;
@@ -100,11 +104,14 @@
     public static final boolean ATLEAST_LOLLIPOP_MR1 =
             Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
 
+    public static final int SINGLE_FRAME_MS = 16;
+
     /**
      * Indicates if the device has a debug build. Should only be used to store additional info or
      * add extra logging and not for changing the app behavior.
      */
-    public static final boolean IS_DEBUG_DEVICE = Build.TYPE.toLowerCase().contains("debug");
+    public static final boolean IS_DEBUG_DEVICE = Build.TYPE.toLowerCase().contains("debug")
+            || Build.TYPE.toLowerCase().equals("eng");
 
     // An intent extra to indicate the horizontal scroll of the wallpaper.
     public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
@@ -124,29 +131,13 @@
             CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
             TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
 
-    public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+    public static final boolean IS_RUNNING_IN_TEST_HARNESS =
+                    ActivityManager.isRunningInTestHarness();
 
     public static boolean isPropertyEnabled(String propertyName) {
         return Log.isLoggable(propertyName, Log.VERBOSE);
     }
 
-    public static boolean isAllowRotationPrefEnabled(Context context) {
-        return getPrefs(context).getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
-                getAllowRotationDefaultValue(context));
-    }
-
-    public static boolean getAllowRotationDefaultValue(Context context) {
-        if (ATLEAST_NOUGAT) {
-            // If the device was scaled, used the original dimensions to determine if rotation
-            // is allowed of not.
-            Resources res = context.getResources();
-            int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
-                    * res.getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEVICE_STABLE;
-            return originalSmallestWidth >= 600;
-        }
-        return false;
-    }
-
     /**
      * Given a coordinate relative to the descendant, find the coordinate in a parent view's
      * coordinates.
@@ -232,6 +223,19 @@
         return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]};
     }
 
+    public static void scaleRectFAboutCenter(RectF r, float scale) {
+        if (scale != 1.0f) {
+            float cx = r.centerX();
+            float cy = r.centerY();
+            r.offset(-cx, -cy);
+            r.left = r.left * scale;
+            r.top = r.top * scale ;
+            r.right = r.right * scale;
+            r.bottom = r.bottom * scale;
+            r.offset(cx, cy);
+        }
+    }
+
     public static void scaleRectAboutCenter(Rect r, float scale) {
         if (scale != 1.0f) {
             int cx = r.centerX();
@@ -272,6 +276,25 @@
         return scale;
     }
 
+    /**
+     * Maps t from one range to another range.
+     * @param t The value to map.
+     * @param fromMin The lower bound of the range that t is being mapped from.
+     * @param fromMax The upper bound of the range that t is being mapped from.
+     * @param toMin The lower bound of the range that t is being mapped to.
+     * @param toMax The upper bound of the range that t is being mapped to.
+     * @return The mapped value of t.
+     */
+    public static float mapToRange(float t, float fromMin, float fromMax, float toMin, float toMax,
+            Interpolator interpolator) {
+        if (fromMin == fromMax || toMin == toMax) {
+            Log.e(TAG, "mapToRange: range has 0 length");
+            return toMin;
+        }
+        float progress = Math.abs(t - fromMin) / Math.abs(fromMax - fromMin);
+        return mapRange(interpolator.getInterpolation(progress), toMin, toMax);
+    }
+
     public static float mapRange(float value, float min, float max) {
         return min + (value * (max - min));
     }
@@ -463,6 +486,13 @@
     }
 
     /**
+     * @see #boundToRange(int, int, int).
+     */
+    public static long boundToRange(long value, long lowerBound, long upperBound) {
+        return Math.max(lowerBound, Math.min(value, upperBound));
+    }
+
+    /**
      * Wraps a message with a TTS span, so that a different message is spoken than
      * what is getting displayed.
      * @param msg original message
@@ -492,7 +522,11 @@
                 LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE);
     }
 
-    public static boolean isPowerSaverOn(Context context) {
+    public static boolean isPowerSaverPreventingAnimation(Context context) {
+        if (ATLEAST_P) {
+            // Battery saver mode no longer prevents animations.
+            return false;
+        }
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         return powerManager.isPowerSaveMode();
     }
@@ -550,25 +584,6 @@
                 || e.getCause() instanceof DeadObjectException;
     }
 
-    public static <T> T getOverrideObject(Class<T> clazz, Context context, int resId) {
-        String className = context.getString(resId);
-        if (!TextUtils.isEmpty(className)) {
-            try {
-                Class<?> cls = Class.forName(className);
-                return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
-            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
-                    | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
-                Log.e(TAG, "Bad overriden class", e);
-            }
-        }
-
-        try {
-            return clazz.newInstance();
-        } catch (InstantiationException|IllegalAccessException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     /**
      * Returns a HashSet with a single element. We use this instead of Collections.singleton()
      * because HashSet ensures all operations, such as remove, are supported.
@@ -579,4 +594,12 @@
         return hashSet;
     }
 
+    /**
+     * Utility method to post a runnable on the handler, skipping the synchronization barriers.
+     */
+    public static void postAsyncCallback(Handler handler, Runnable callback) {
+        Message msg = Message.obtain(handler, callback);
+        msg.setAsynchronous(true);
+        handler.sendMessage(msg);
+    }
 }
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index a658d58..7af4bf9 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -338,7 +338,8 @@
         int previewWidth;
         int previewHeight;
 
-        if (widgetPreviewExists) {
+        if (widgetPreviewExists && drawable.getIntrinsicWidth() > 0
+                && drawable.getIntrinsicHeight() > 0) {
             previewWidth = drawable.getIntrinsicWidth();
             previewHeight = drawable.getIntrinsicHeight();
         } else {
@@ -358,8 +359,8 @@
             scale = maxPreviewWidth / (float) (previewWidth);
         }
         if (scale != 1f) {
-            previewWidth = (int) (scale * previewWidth);
-            previewHeight = (int) (scale * previewHeight);
+            previewWidth = Math.max((int)(scale * previewWidth), 1);
+            previewHeight = Math.max((int)(scale * previewHeight), 1);
         }
 
         // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0b11707..37d0056 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -59,7 +60,6 @@
 import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
-import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
 import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
 import com.android.launcher3.anim.AnimatorSetBuilder;
 import com.android.launcher3.anim.Interpolators;
@@ -79,7 +79,8 @@
 import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.touch.WorkspaceTouchListener;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -192,7 +193,7 @@
 
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
     private static final int FOLDER_CREATION_TIMEOUT = 0;
-    public static final int REORDER_TIMEOUT = 350;
+    public static final int REORDER_TIMEOUT = 650;
     private final Alarm mFolderCreationAlarm = new Alarm();
     private final Alarm mReorderAlarm = new Alarm();
     private PreviewBackground mFolderCreateBg;
@@ -239,7 +240,6 @@
     private Runnable mOnOverlayHiddenCallback;
 
     private boolean mForceDrawAdjacentPages = false;
-    private boolean mPageRearrangeEnabled = false;
 
     // Total over scrollX in the overlay direction.
     private float mOverlayTranslation;
@@ -247,8 +247,6 @@
     // Handles workspace state transitions
     private final WorkspaceStateTransitionAnimation mStateTransitionAnimation;
 
-    private AccessibilityDelegate mPagesAccessibilityDelegate;
-
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -280,6 +278,7 @@
 
         // Disable multitouch across the workspace/all apps/customize tray
         setMotionEventSplittingEnabled(true);
+        setOnTouchListener(new WorkspaceTouchListener(mLauncher, this));
     }
 
     @Override
@@ -287,7 +286,9 @@
         mInsets.set(insets);
 
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);
+        mMaxDistanceForFolderCreation = grid.isTablet
+                ? 0.75f * grid.iconSizePx
+                : 0.55f * grid.iconSizePx;
         mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
 
         Rect padding = grid.workspacePadding;
@@ -345,6 +346,11 @@
         }
     }
 
+    public float getWallpaperOffsetForCenterPage() {
+        int pageScroll = getScrollForPage(getPageNearestToCenterOfScreen());
+        return mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
+    }
+
     public Rect estimateItemPosition(CellLayout cl, int hCell, int vCell, int hSpan, int vSpan) {
         Rect r = new Rect();
         cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
@@ -439,12 +445,6 @@
         setWallpaperDimension();
     }
 
-    @Override
-    public void initParentViews(View parent) {
-        super.initParentViews(parent);
-        mPageIndicator.setAccessibilityDelegate(UiFactory.newPageIndicatorAccessibilityDelegate());
-    }
-
     private void setupLayoutTransition() {
         // We want to show layout transitions when pages are deleted, to close the gap.
         mLayoutTransition = new LayoutTransition();
@@ -469,12 +469,11 @@
         }
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
-        cl.setClickable(true);
         cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         super.onViewAdded(child);
     }
 
-    boolean isTouchActive() {
+    public boolean isTouchActive() {
         return mTouchState != TOUCH_STATE_REST;
     }
 
@@ -515,6 +514,7 @@
         }
 
         // Remove the pages and clear the screen models
+        removeFolderListeners();
         removeAllViews();
         mScreenOrder.clear();
         mWorkspaceScreens.clear();
@@ -549,10 +549,7 @@
         // created CellLayout.
         CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
                         R.layout.workspace_screen, this, false /* attachToRoot */);
-        newScreen.setOnLongClickListener(mLongClickListener);
-        newScreen.setOnClickListener(mLauncher);
-        newScreen.setSoundEffectsEnabled(false);
-
+        newScreen.getShortcutsAndWidgets().setId(R.id.workspace_page_container);
         int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
         int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
         newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
@@ -887,7 +884,6 @@
         final CellLayout layout;
         if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
             layout = mLauncher.getHotseat().getLayout();
-            child.setOnKeyListener(new HotseatIconKeyEventListener());
 
             // Hide folder title in the hotseat
             if (child instanceof FolderIcon) {
@@ -899,7 +895,6 @@
                 ((FolderIcon) child).setTextVisible(true);
             }
             layout = getScreenWithId(screenId);
-            child.setOnKeyListener(new IconKeyEventListener());
         }
 
         ViewGroup.LayoutParams genericLp = child.getLayoutParams();
@@ -930,10 +925,8 @@
             Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
         }
 
-        if (!(child instanceof Folder)) {
-            child.setHapticFeedbackEnabled(false);
-            child.setOnLongClickListener(mLongClickListener);
-        }
+        child.setHapticFeedbackEnabled(false);
+        child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
         if (child instanceof DropTarget) {
             mDragController.addDropTarget((DropTarget) child);
         }
@@ -977,19 +970,9 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
-        case MotionEvent.ACTION_DOWN:
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
             mXDown = ev.getX();
             mYDown = ev.getY();
-            break;
-        case MotionEvent.ACTION_POINTER_UP:
-        case MotionEvent.ACTION_UP:
-            if (mTouchState == TOUCH_STATE_REST) {
-                final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
-                if (currentPage != null) {
-                    onWallpaperTap(ev);
-                }
-            }
         }
         return super.onInterceptTouchEvent(ev);
     }
@@ -1053,7 +1036,7 @@
     }
 
     protected void onScrollInteractionBegin() {
-        super.onScrollInteractionEnd();
+        super.onScrollInteractionBegin();
         mScrollInteractionBegan = true;
     }
 
@@ -1152,30 +1135,37 @@
      * The overlay scroll is being controlled locally, just update our overlay effect
      */
     public void onOverlayScrollChanged(float scroll) {
-
         if (Float.compare(scroll, 1f) == 0) {
             if (!mOverlayShown) {
                 mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
                         Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
             }
             mOverlayShown = true;
+            // Not announcing the overlay page for accessibility since it announces itself.
         } else if (Float.compare(scroll, 0f) == 0) {
             if (mOverlayShown) {
                 mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
                         Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
+            } else if (Float.compare(mOverlayTranslation, 0f) != 0) {
+                // When arriving to 0 overscroll from non-zero overscroll, announce page for
+                // accessibility since default announcements were disabled while in overscroll
+                // state.
+                // Not doing this if mOverlayShown because in that case the accessibility service
+                // will announce the launcher window description upon regaining focus after
+                // switching from the overlay screen.
+                announcePageForAccessibility();
             }
             mOverlayShown = false;
             tryRunOverlayCallback();
         }
+
         float offset = 0f;
-        float slip = 0f;
 
         scroll = Math.max(scroll - offset, 0);
         scroll = Math.min(1, scroll / (1 - offset));
 
         float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(scroll);
         float transX = mLauncher.getDragLayer().getMeasuredWidth() * scroll;
-        transX *= 1 - slip;
 
         if (mIsRtl) {
             transX = -transX;
@@ -1186,7 +1176,7 @@
         // different effects based on device performance. On at least one relatively high-end
         // device I've tried, translating the launcher causes things to get quite laggy.
         mLauncher.getDragLayer().setTranslationX(transX);
-        mLauncher.getDragLayer().setAlpha(alpha);
+        mLauncher.getDragLayer().getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha);
     }
 
     /**
@@ -1308,7 +1298,9 @@
     }
 
     private void updatePageAlphaValues() {
-        if (!workspaceInModalState() && !mIsSwitchingState) {
+        // We need to check the isDragging case because updatePageAlphaValues is called between
+        // goToState(SPRING_LOADED) and onStartStateTransition.
+        if (!workspaceInModalState() && !mIsSwitchingState && !mDragController.isDragging()) {
             int screenCenter = getScrollX() + getMeasuredWidth() / 2;
             for (int i = 0; i < getChildCount(); i++) {
                 CellLayout child = (CellLayout) getChildAt(i);
@@ -1373,8 +1365,7 @@
     }
 
     private void updateChildrenLayersEnabled() {
-        boolean enableChildrenLayers =
-                isPageRearrangeEnabled() || mIsSwitchingState || isPageInTransition();
+        boolean enableChildrenLayers = mIsSwitchingState || isPageInTransition();
 
         if (enableChildrenLayers != mChildrenLayersEnabled) {
             mChildrenLayersEnabled = enableChildrenLayers;
@@ -1393,28 +1384,9 @@
         if (mChildrenLayersEnabled) {
             final int screenCount = getChildCount();
 
-            float visibleLeft = 0;
-            float visibleRight = visibleLeft + getMeasuredWidth();
-            float scaleX = getScaleX();
-            if (scaleX < 1 && scaleX > 0) {
-                float mid = getMeasuredWidth() / 2;
-                visibleLeft = mid - ((mid - visibleLeft) / scaleX);
-                visibleRight = mid + ((visibleRight - mid) / scaleX);
-            }
-
-            int leftScreen = -1;
-            int rightScreen = -1;
-            for (int i = 0; i < screenCount; i++) {
-                final View child = getPageAt(i);
-
-                float left = child.getLeft() + child.getTranslationX() - getScrollX();
-                if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) {
-                    if (leftScreen == -1) {
-                        leftScreen = i;
-                    }
-                    rightScreen = i;
-                }
-            }
+            final int[] visibleScreens = getVisibleChildrenRange();
+            int leftScreen = visibleScreens[0];
+            int rightScreen = visibleScreens[1];
             if (mForceDrawAdjacentPages) {
                 // In overview mode, make sure that the two side pages are visible.
                 leftScreen = Utilities.boundToRange(getCurrentPage() - 1, 0, rightScreen);
@@ -1440,7 +1412,7 @@
         }
     }
 
-    protected void onWallpaperTap(MotionEvent ev) {
+    public void onWallpaperTap(MotionEvent ev) {
         final int[] position = mTempXY;
         getLocationOnScreen(position);
 
@@ -1458,40 +1430,6 @@
         mOutlineProvider = outlineProvider;
     }
 
-    public void onStartReordering() {
-        super.onStartReordering();
-        // Reordering handles its own animations, disable the automatic ones.
-        disableLayoutTransitions();
-    }
-
-    public void onEndReordering() {
-        super.onEndReordering();
-
-        if (mLauncher.isWorkspaceLoading()) {
-            // Invalid and dangerous operation if workspace is loading
-            return;
-        }
-
-        ArrayList<Long> prevScreenOrder = (ArrayList<Long>) mScreenOrder.clone();
-        mScreenOrder.clear();
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            CellLayout cl = ((CellLayout) getChildAt(i));
-            mScreenOrder.add(getIdForScreen(cl));
-        }
-
-        for (int i = 0; i < prevScreenOrder.size(); i++) {
-            if (mScreenOrder.get(i) != prevScreenOrder.get(i)) {
-                mLauncher.getUserEventDispatcher().logOverviewReorder();
-                break;
-            }
-        }
-        LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
-
-        // Re-enable auto layout transitions for page deletion.
-        enableLayoutTransitions();
-    }
-
     public void snapToPageFromOverView(int whichPage) {
         snapToPage(whichPage, OVERVIEW_TRANSITION_MS, Interpolators.ZOOM_IN);
     }
@@ -1551,47 +1489,17 @@
         if (!mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
             int total = getPageCount();
             for (int i = 0; i < total; i++) {
-                updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i), i);
+                updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i));
             }
             setImportantForAccessibility(accessibilityFlag);
         }
     }
 
-    private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page, int pageNo) {
-        if (isPageRearrangeEnabled()) {
-            page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
-            page.getShortcutsAndWidgets().setImportantForAccessibility(
-                    IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-            page.setContentDescription(getPageDescription(pageNo));
-
-            // No custom action for the first page.
-            if (!FeatureFlags.QSB_ON_FIRST_SCREEN || pageNo > 0) {
-                if (mPagesAccessibilityDelegate == null) {
-                    mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this);
-                }
-                page.setAccessibilityDelegate(mPagesAccessibilityDelegate);
-            }
-        } else {
-            page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-            page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
-            page.setContentDescription(null);
-            page.setAccessibilityDelegate(null);
-        }
-    }
-
-    public void setPageRearrangeEnabled(boolean isEnabled) {
-        if (mPageRearrangeEnabled != isEnabled) {
-            mPageRearrangeEnabled = isEnabled;
-            if (isEnabled) {
-                enableFreeScroll();
-            } else {
-                disableFreeScroll();
-            }
-        }
-    }
-
-    public boolean isPageRearrangeEnabled() {
-        return mPageRearrangeEnabled;
+    private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page) {
+        page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+        page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
+        page.setContentDescription(null);
+        page.setAccessibilityDelegate(null);
     }
 
     public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) {
@@ -1607,10 +1515,6 @@
                 protected void enableAccessibleDrag(boolean enable) {
                     super.enableAccessibleDrag(enable);
                     setEnableForLayout(mLauncher.getHotseat().getLayout(),enable);
-
-                    // We need to allow our individual children to become click handlers in this
-                    // case, so temporarily unset the click handlers.
-                    setOnClickListener(enable ? null : mLauncher);
                 }
             });
         }
@@ -1630,9 +1534,16 @@
                 new DragPreviewProvider(child), options);
     }
 
-
     public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
             DragPreviewProvider previewProvider, DragOptions dragOptions) {
+        float iconScale = 1f;
+        if (child instanceof BubbleTextView) {
+            Drawable icon = ((BubbleTextView) child).getIcon();
+            if (icon instanceof FastBitmapDrawable) {
+                iconScale = ((FastBitmapDrawable) icon).getAnimatedScale();
+            }
+        }
+
         child.clearFocus();
         child.setPressed(false);
         mOutlineProvider = previewProvider;
@@ -1679,12 +1590,12 @@
             if (popupContainer != null) {
                 dragOptions.preDragCondition = popupContainer.createPreDragCondition();
 
-                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("dragging started");
             }
         }
 
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
-                dragObject, dragVisualizeOffset, dragRect, scale, dragOptions);
+                dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, dragOptions);
         dv.setIntrinsicIconScaleFactor(dragOptions.intrinsicIconScaleFactor);
         return dv;
     }
@@ -2229,7 +2140,7 @@
         }
         // Invalidating the scrim will also force this CellLayout
         // to be invalidated so that it is highlighted if necessary.
-        mLauncher.getDragLayer().invalidateScrim();
+        mLauncher.getDragLayer().getScrim().invalidate();
     }
 
     public CellLayout getCurrentDragOverlappingLayout() {
@@ -2478,7 +2389,12 @@
 
     private void manageFolderFeedback(CellLayout targetLayout,
             int[] targetCell, float distance, DragObject dragObject) {
-        if (distance > mMaxDistanceForFolderCreation) return;
+        if (distance > mMaxDistanceForFolderCreation) {
+            if (mDragMode != DRAG_MODE_NONE) {
+                setDragMode(DRAG_MODE_NONE);
+            }
+            return;
+        }
 
         final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
         ItemInfo info = dragObject.dragInfo;
@@ -2959,8 +2875,9 @@
                         + "Workspace#onDropCompleted. Please file a bug. ");
             }
         }
-        if (d.cancelled && mDragInfo != null && mDragInfo.cell != null) {
-            mDragInfo.cell.setVisibility(VISIBLE);
+        View cell = getHomescreenIconByItemId(d.originalDragInfo.id);
+        if (d.cancelled && cell != null) {
+            cell.setVisibility(VISIBLE);
         }
         mDragInfo = null;
     }
@@ -3033,25 +2950,29 @@
     }
 
     @Override
-    public void scrollLeft() {
+    public boolean scrollLeft() {
+        boolean result = false;
         if (!workspaceInModalState() && !mIsSwitchingState) {
-            super.scrollLeft();
+            result = super.scrollLeft();
         }
         Folder openFolder = Folder.getOpen(mLauncher);
         if (openFolder != null) {
             openFolder.completeDragExit();
         }
+        return result;
     }
 
     @Override
-    public void scrollRight() {
+    public boolean scrollRight() {
+        boolean result = false;
         if (!workspaceInModalState() && !mIsSwitchingState) {
-            super.scrollRight();
+            result = super.scrollRight();
         }
         Folder openFolder = Folder.getOpen(mLauncher);
         if (openFolder != null) {
             openFolder.completeDragExit();
         }
+        return result;
     }
 
     /**
@@ -3109,16 +3030,6 @@
         });
     }
 
-    public View getViewForTag(final Object tag) {
-        return getFirstMatch(new ItemOperator() {
-
-            @Override
-            public boolean evaluate(ItemInfo info, View v) {
-                return info == tag;
-            }
-        });
-    }
-
     public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {
         return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {
 
@@ -3320,8 +3231,7 @@
                         && v instanceof FolderIcon) {
                     FolderBadgeInfo folderBadgeInfo = new FolderBadgeInfo();
                     for (ShortcutInfo si : ((FolderInfo) info).contents) {
-                        folderBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider()
-                                .getBadgeInfoForItem(si));
+                        folderBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(si));
                     }
                     ((FolderIcon) v).setBadgeInfo(folderBadgeInfo);
                 }
@@ -3418,8 +3328,10 @@
     }
 
     @Override
-    protected String getPageIndicatorDescription() {
-        return getResources().getString(R.string.all_apps_button_label);
+    protected boolean canAnnouncePageDescription() {
+        // Disable announcements while overscrolling potentially to overlay screen because if we end
+        // up on the overlay screen, it will take care of announcing itself.
+        return Float.compare(mOverlayTranslation, 0f) == 0;
     }
 
     @Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 21f5d67..e734e70 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,80 +18,30 @@
 
 import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SCRIM_PROGRESS;
+import static com.android.launcher3.graphics.WorkspaceAndHotseatScrim.SYSUI_PROGRESS;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.util.Property;
 import android.view.View;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.LauncherState.PageAlphaProvider;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
-
-/**
- * A convenience class to update a view's visibility state after an alpha animation.
- */
-class AlphaUpdateListener extends AnimatorListenerAdapter implements ValueAnimator.AnimatorUpdateListener {
-    private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
-
-    private View mView;
-    private boolean mAccessibilityEnabled;
-    private boolean mCanceled = false;
-
-    public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
-        mView = v;
-        mAccessibilityEnabled = accessibilityEnabled;
-    }
-
-    @Override
-    public void onAnimationUpdate(ValueAnimator arg0) {
-        updateVisibility(mView, mAccessibilityEnabled);
-    }
-
-    public static void updateVisibility(View view, boolean accessibilityEnabled) {
-        // We want to avoid the extra layout pass by setting the views to GONE unless
-        // accessibility is on, in which case not setting them to GONE causes a glitch.
-        int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
-        if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
-            view.setVisibility(invisibleState);
-        } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
-                && view.getVisibility() != View.VISIBLE) {
-            view.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
-    public void onAnimationCancel(Animator animation) {
-        mCanceled = true;
-    }
-
-    @Override
-    public void onAnimationEnd(Animator arg0) {
-        if (mCanceled) return;
-        updateVisibility(mView, mAccessibilityEnabled);
-    }
-
-    @Override
-    public void onAnimationStart(Animator arg0) {
-        // We want the views to be visible for animation, so fade-in/out is visible
-        mView.setVisibility(View.VISIBLE);
-    }
-}
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 
 /**
  * Manages the animations between each of the workspace states.
  */
 public class WorkspaceStateTransitionAnimation {
 
-    public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
-
-    public final int mWorkspaceScrimAlpha;
-
     private final Launcher mLauncher;
     private final Workspace mWorkspace;
 
@@ -100,19 +50,16 @@
     public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
         mLauncher = launcher;
         mWorkspace = workspace;
-        mWorkspaceScrimAlpha = launcher.getResources()
-                .getInteger(R.integer.config_workspaceScrimAlpha);
     }
 
     public void setState(LauncherState toState) {
-        setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER);
+        setWorkspaceProperty(toState, NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(),
+                new AnimationConfig());
     }
 
     public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
             AnimationConfig config) {
-        AnimatedPropertySetter propertySetter =
-                new AnimatedPropertySetter(config.duration, builder);
-        setWorkspaceProperty(toState, propertySetter);
+        setWorkspaceProperty(toState, config.getPropertySetter(builder), builder, config);
     }
 
     public float getFinalScale() {
@@ -122,110 +69,72 @@
     /**
      * Starts a transition animation for the workspace.
      */
-    private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter) {
+    private void setWorkspaceProperty(LauncherState state, PropertySetter propertySetter,
+            AnimatorSetBuilder builder, AnimationConfig config) {
         float[] scaleAndTranslation = state.getWorkspaceScaleAndTranslation(mLauncher);
         mNewScale = scaleAndTranslation[0];
         PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
         final int childCount = mWorkspace.getChildCount();
         for (int i = 0; i < childCount; i++) {
             applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
-                    propertySetter);
+                    propertySetter, builder, config);
         }
 
-        propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_IN);
-        propertySetter.setFloat(mWorkspace, View.TRANSLATION_X,
-                scaleAndTranslation[1], Interpolators.ZOOM_IN);
-        propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
-                scaleAndTranslation[2], Interpolators.ZOOM_IN);
-
-        propertySetter.setViewAlpha(mLauncher.getHotseat(), state.getHoseatAlpha(mLauncher),
+        int elements = state.getVisibleElements(mLauncher);
+        Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
                 pageAlphaProvider.interpolator);
+        boolean playAtomicComponent = config.playAtomicComponent();
+        if (playAtomicComponent) {
+            Interpolator scaleInterpolator = builder.getInterpolator(ANIM_WORKSPACE_SCALE, ZOOM_OUT);
+            propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, scaleInterpolator);
+            float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
+            propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha,
+                    fadeInterpolator);
+            propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
+                    hotseatIconsAlpha, fadeInterpolator);
+        }
+
+        if (!config.playNonAtomicComponent()) {
+            // Only the alpha and scale, handled above, are included in the atomic animation.
+            return;
+        }
+
+        Interpolator translationInterpolator = !playAtomicComponent ? LINEAR : ZOOM_OUT;
+        propertySetter.setFloat(mWorkspace, View.TRANSLATION_X,
+                scaleAndTranslation[1], translationInterpolator);
+        propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
+                scaleAndTranslation[2], translationInterpolator);
+
+        propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(),
+                (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0, fadeInterpolator);
 
         // Set scrim
-        propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA,
-                state.hasScrim ? mWorkspaceScrimAlpha : 0, Interpolators.DEACCEL_1_5);
+        WorkspaceAndHotseatScrim scrim = mLauncher.getDragLayer().getScrim();
+        propertySetter.setFloat(scrim, SCRIM_PROGRESS, state.getWorkspaceScrimAlpha(mLauncher),
+                LINEAR);
+        propertySetter.setFloat(scrim, SYSUI_PROGRESS, state.hasSysUiScrim ? 1 : 0, LINEAR);
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
         applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
-                NO_ANIM_PROPERTY_SETTER);
+                NO_ANIM_PROPERTY_SETTER, new AnimatorSetBuilder(), new AnimationConfig());
     }
 
     private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
-            PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
+            PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter,
+            AnimatorSetBuilder builder, AnimationConfig config) {
         float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex);
-        int drawableAlpha = Math.round(pageAlpha * (state.hasScrim ? 255 : 0));
+        int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
 
-        propertySetter.setInt(cl.getScrimBackground(),
-                DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN);
-        propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
-                pageAlpha, pageAlphaProvider.interpolator);
-    }
-
-    public static class PropertySetter {
-
-        public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
-            view.setAlpha(alpha);
-            AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
+        if (config.playNonAtomicComponent()) {
+            propertySetter.setInt(cl.getScrimBackground(),
+                    DRAWABLE_ALPHA, drawableAlpha, ZOOM_OUT);
         }
-
-        public <T> void setFloat(T target, Property<T, Float> property, float value,
-                TimeInterpolator interpolator) {
-            property.set(target, value);
-        }
-
-        public <T> void setInt(T target, Property<T, Integer> property, int value,
-                TimeInterpolator interpolator) {
-            property.set(target, value);
-        }
-    }
-
-    public static class AnimatedPropertySetter extends PropertySetter {
-
-        private final long mDuration;
-        private final AnimatorSetBuilder mStateAnimator;
-
-        public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
-            mDuration = duration;
-            mStateAnimator = builder;
-        }
-
-        @Override
-        public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
-            if (view.getAlpha() == alpha) {
-                return;
-            }
-            ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
-            anim.addListener(new AlphaUpdateListener(
-                    view, isAccessibilityEnabled(view.getContext())));
-            anim.setDuration(mDuration).setInterpolator(interpolator);
-            mStateAnimator.play(anim);
-        }
-
-        @Override
-        public <T> void setFloat(T target, Property<T, Float> property, float value,
-                TimeInterpolator interpolator) {
-            if (property.get(target) == value) {
-                return;
-            }
-            Animator anim = ObjectAnimator.ofFloat(target, property, value);
-            anim.setDuration(mDuration).setInterpolator(interpolator);
-            mStateAnimator.play(anim);
-        }
-
-        @Override
-        public <T> void setInt(T target, Property<T, Integer> property, int value,
-                TimeInterpolator interpolator) {
-            if (property.get(target) == value) {
-                return;
-            }
-            Animator anim = ObjectAnimator.ofInt(target, property, value);
-            anim.setDuration(mDuration).setInterpolator(interpolator);
-            mStateAnimator.play(anim);
-        }
-
-        private TimeInterpolator getFadeInterpolator(float finalAlpha) {
-            return finalAlpha == 0 ? Interpolators.DEACCEL_2 : null;
+        if (config.playAtomicComponent()) {
+            Interpolator fadeInterpolator = builder.getInterpolator(ANIM_WORKSPACE_FADE,
+                    pageAlphaProvider.interpolator);
+            propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
+                    pageAlpha, fadeInterpolator);
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 3b6fea9..81a0e1d 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -25,7 +25,6 @@
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.LauncherAppWidgetInfo;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -36,9 +35,12 @@
 import com.android.launcher3.dragndrop.DragController.DragListener;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.folder.Folder;
+import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.util.ArrayList;
 
@@ -47,13 +49,14 @@
     private static final String TAG = "LauncherAccessibilityDelegate";
 
     public static final int REMOVE = R.id.action_remove;
-    public static final int INFO = R.id.action_info;
     public static final int UNINSTALL = R.id.action_uninstall;
+    public static final int RECONFIGURE = R.id.action_reconfigure;
     protected static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
     protected static final int MOVE = R.id.action_move;
     protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
     protected static final int RESIZE = R.id.action_resize;
     public static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
+    public static final int SHORTCUTS_AND_NOTIFICATIONS = R.id.action_shortcuts_and_notifications;
 
     public enum DragType {
         ICON,
@@ -77,10 +80,10 @@
 
         mActions.put(REMOVE, new AccessibilityAction(REMOVE,
                 launcher.getText(R.string.remove_drop_target_label)));
-        mActions.put(INFO, new AccessibilityAction(INFO,
-                launcher.getText(R.string.app_info_drop_target_label)));
         mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL,
                 launcher.getText(R.string.uninstall_drop_target_label)));
+        mActions.put(RECONFIGURE, new AccessibilityAction(RECONFIGURE,
+                launcher.getText(R.string.gadget_setup_text)));
         mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE,
                 launcher.getText(R.string.action_add_to_workspace)));
         mActions.put(MOVE, new AccessibilityAction(MOVE,
@@ -91,6 +94,12 @@
                         launcher.getText(R.string.action_resize)));
         mActions.put(DEEP_SHORTCUTS, new AccessibilityAction(DEEP_SHORTCUTS,
                 launcher.getText(R.string.action_deep_shortcut)));
+        mActions.put(SHORTCUTS_AND_NOTIFICATIONS, new AccessibilityAction(DEEP_SHORTCUTS,
+                launcher.getText(R.string.shortcuts_menu_with_notifications_description)));
+    }
+
+    public void addAccessibilityAction(int action, int actionLabel) {
+        mActions.put(action, new AccessibilityAction(action, mLauncher.getText(actionLabel)));
     }
 
     @Override
@@ -106,11 +115,12 @@
         // If the request came from keyboard, do not add custom shortcuts as that is already
         // exposed as a direct shortcut
         if (!fromKeyboard && DeepShortcutManager.supportsShortcuts(item)) {
-            info.addAction(mActions.get(DEEP_SHORTCUTS));
+            info.addAction(mActions.get(NotificationListener.getInstanceIfConnected() != null
+                    ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
         }
 
         for (ButtonDropTarget target : mLauncher.getDropTargetBar().getDropTargets()) {
-            if (target.supportsAccessibilityDrop(item)) {
+            if (target.supportsAccessibilityDrop(item, host)) {
                 info.addAction(mActions.get(target.getAccessibilityAction()));
             }
         }
@@ -222,7 +232,8 @@
             return PopupContainerWithArrow.showForIcon((BubbleTextView) host) != null;
         } else {
             for (ButtonDropTarget dropTarget : mLauncher.getDropTargetBar().getDropTargets()) {
-                if (action == dropTarget.getAccessibilityAction()) {
+                if (dropTarget.supportsAccessibilityDrop(item, host) &&
+                        action == dropTarget.getAccessibilityAction()) {
                     dropTarget.onAccessibilityDrop(host, item);
                     return true;
                 }
@@ -357,29 +368,14 @@
             mDragInfo.dragType = DragType.WIDGET;
         }
 
-        CellLayout.CellInfo cellInfo = new CellLayout.CellInfo(item, info);
-
         Rect pos = new Rect();
         mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
         mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY());
-
-        Folder folder = Folder.getOpen(mLauncher);
-        if (folder != null) {
-            if (!folder.getItemsInReadingOrder().contains(item)) {
-                folder.close(true);
-                folder = null;
-            }
-        }
-
         mLauncher.getDragController().addDragListener(this);
 
         DragOptions options = new DragOptions();
         options.isAccessibleDrag = true;
-        if (folder != null) {
-            folder.startDrag(cellInfo.cell, options);
-        } else {
-            mLauncher.getWorkspace().startDrag(cellInfo, options);
-        }
+        ItemLongClickListener.beginDrag(item, mLauncher, info, options);
     }
 
     @Override
diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
deleted file mode 100644
index f9eb2ed..0000000
--- a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2015 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.accessibility;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.config.FeatureFlags;
-
-public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate {
-
-    private static final int MOVE_BACKWARD = R.id.action_move_screen_backwards;
-    private static final int MOVE_FORWARD = R.id.action_move_screen_forwards;
-
-    private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
-    private final Workspace mWorkspace;
-
-    public OverviewScreenAccessibilityDelegate(Workspace workspace) {
-        mWorkspace = workspace;
-
-        Context context = mWorkspace.getContext();
-        boolean isRtl = Utilities.isRtl(context.getResources());
-        mActions.put(MOVE_BACKWARD, new AccessibilityAction(MOVE_BACKWARD,
-                context.getText(isRtl ? R.string.action_move_screen_right :
-                    R.string.action_move_screen_left)));
-        mActions.put(MOVE_FORWARD, new AccessibilityAction(MOVE_FORWARD,
-                context.getText(isRtl ? R.string.action_move_screen_left :
-                    R.string.action_move_screen_right)));
-    }
-
-    @Override
-    public boolean performAccessibilityAction(View host, int action, Bundle args) {
-        if (host != null) {
-            if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS ) {
-                int index = mWorkspace.indexOfChild(host);
-                mWorkspace.setCurrentPage(index);
-            } else if (action == MOVE_FORWARD) {
-                movePage(mWorkspace.indexOfChild(host) + 1, host);
-                return true;
-            } else if (action == MOVE_BACKWARD) {
-                movePage(mWorkspace.indexOfChild(host) - 1, host);
-                return true;
-            }
-        }
-
-        return super.performAccessibilityAction(host, action, args);
-    }
-
-    private void movePage(int finalIndex, View view) {
-        mWorkspace.onStartReordering();
-        mWorkspace.removeView(view);
-        mWorkspace.addView(view, finalIndex);
-        mWorkspace.onEndReordering();
-        mWorkspace.announceForAccessibility(mWorkspace.getContext().getText(R.string.screen_moved));
-
-        mWorkspace.updateAccessibilityFlags();
-        view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(host, info);
-
-        int index = mWorkspace.indexOfChild(host);
-        if (index < mWorkspace.getChildCount() - 1) {
-            info.addAction(mActions.get(MOVE_FORWARD));
-        }
-
-        int startIndex = FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0;
-        if (index > startIndex) {
-            info.addAction(mActions.get(MOVE_BACKWARD));
-        }
-    }
-}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a7eae39..fdf32af 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -15,12 +15,17 @@
  */
 package com.android.launcher3.allapps;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Process;
+import android.support.animation.DynamicAnimation;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
@@ -30,47 +35,47 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
-import android.widget.RelativeLayout;
 
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
-import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
-import com.android.launcher3.anim.SpringAnimationHandler;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BottomUserEducationView;
+import com.android.launcher3.views.RecyclerViewFastScroller;
+import com.android.launcher3.views.SpringRelativeLayout;
 
 /**
  * The all apps view container.
  */
-public class AllAppsContainerView extends RelativeLayout implements DragSource,
-        OnLongClickListener, Insettable, BubbleTextShadowHandler, OnDeviceProfileChangeListener {
+public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
+        Insettable, OnDeviceProfileChangeListener {
+
+    private static final float FLING_VELOCITY_MULTIPLIER = 135f;
+    // Starts the springs after at least 55% of the animation has passed.
+    private static final float FLING_ANIMATION_THRESHOLD = 0.55f;
 
     private final Launcher mLauncher;
     private final AdapterHolder[] mAH;
-    private final ClickShadowView mTouchFeedbackView;
     private final ItemInfoMatcher mPersonalMatcher = ItemInfoMatcher.ofUser(Process.myUserHandle());
     private final ItemInfoMatcher mWorkMatcher = ItemInfoMatcher.not(mPersonalMatcher);
     private final AllAppsStore mAllAppsStore = new AllAppsStore();
 
+    private final Paint mNavBarScrimPaint;
+    private int mNavBarScrimHeight = 0;
+
     private SearchUiManager mSearchUiManager;
     private View mSearchContainer;
     private AllAppsPagedView mViewPager;
@@ -81,6 +86,9 @@
     private boolean mUsingTabs;
     private boolean mSearchModeWhileUsingTabs = false;
 
+    private RecyclerViewFastScroller mTouchHandler;
+    private final Point mFastScrollerOffset = new Point();
+
     public AllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -96,30 +104,20 @@
         mLauncher.addOnDeviceProfileChangeListener(this);
 
         mSearchQueryBuilder = new SpannableStringBuilder();
-
         Selection.setSelection(mSearchQueryBuilder, 0);
 
-        mTouchFeedbackView = new ClickShadowView(context);
-        // Make the feedback view large enough to hold the blur bitmap.
-        int size = mLauncher.getDeviceProfile().allAppsIconSizePx
-                + mTouchFeedbackView.getExtraSize();
-        addView(mTouchFeedbackView, size, size);
-
         mAH = new AdapterHolder[2];
         mAH[AdapterHolder.MAIN] = new AdapterHolder(false /* isWork */);
         mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */);
 
+        mNavBarScrimPaint = new Paint();
+        mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
+
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
-    }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        applyTouchDelegate();
-    }
-
-    private void applyTouchDelegate() {
-        // TODO: Reimplement once fast scroller is fixed.
+        addSpringView(R.id.all_apps_header);
+        addSpringView(R.id.apps_list_view);
+        addSpringView(R.id.all_apps_tabs_view_pager);
     }
 
     public AllAppsStore getAppsStore() {
@@ -127,9 +125,10 @@
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        applyTouchDelegate();
+    protected void setDampedScrollShift(float shift) {
+        // Bound the shift amount to avoid content from drawing on top (Y-val) of the QSB.
+        float maxShift = getSearchView().getHeight() / 2f;
+        super.setDampedScrollShift(Utilities.boundToRange(shift, -maxShift, maxShift));
     }
 
     @Override
@@ -157,11 +156,6 @@
         }
     }
 
-    @Override
-    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
-        mTouchFeedbackView.setPressedIcon(icon, background);
-    }
-
     /**
      * Returns whether the view itself will handle the touch event or not.
      */
@@ -172,7 +166,51 @@
             return true;
         }
         AllAppsRecyclerView rv = getActiveRecyclerView();
-        return rv == null || rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
+        if (rv == null) {
+            return true;
+        }
+        if (rv.getScrollbar().getThumbOffsetY() >= 0 &&
+                mLauncher.getDragLayer().isEventOverView(rv.getScrollbar(), ev)) {
+            return false;
+        }
+        return rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            AllAppsRecyclerView rv = getActiveRecyclerView();
+            if (rv != null &&
+                    rv.getScrollbar().isHitInParent(ev.getX(), ev.getY(), mFastScrollerOffset)) {
+                mTouchHandler = rv.getScrollbar();
+            }
+        }
+        if (mTouchHandler != null) {
+            return mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mTouchHandler != null) {
+            mTouchHandler.handleTouchEvent(ev, mFastScrollerOffset);
+            return true;
+        }
+        return false;
+    }
+
+    public String getDescription() {
+        @StringRes int descriptionRes;
+        if (mUsingTabs) {
+            descriptionRes =
+                    mViewPager.getNextPage() == 0
+                            ? R.string.all_apps_button_personal_label
+                            : R.string.all_apps_button_work_label;
+        } else {
+            descriptionRes = R.string.all_apps_button_label;
+        }
+        return getContext().getString(descriptionRes);
     }
 
     public AllAppsRecyclerView getActiveRecyclerView() {
@@ -186,17 +224,17 @@
     /**
      * Resets the state of AllApps.
      */
-    public void reset() {
+    public void reset(boolean animate) {
         for (int i = 0; i < mAH.length; i++) {
             if (mAH[i].recyclerView != null) {
                 mAH[i].recyclerView.scrollToTop();
             }
         }
         if (isHeaderVisible()) {
-            mHeader.reset();
+            mHeader.reset(animate);
         }
         // Reset the search bar and base recycler view after transitioning home
-        mSearchUiManager.reset();
+        mSearchUiManager.resetSearch();
     }
 
     @Override
@@ -230,37 +268,6 @@
     }
 
     @Override
-    public boolean onLongClick(final View v) {
-        // When we have exited all apps or are in transition, disregard long clicks
-        if (!mLauncher.isInState(LauncherState.ALL_APPS) ||
-                mLauncher.getWorkspace().isSwitchingState()) return false;
-        // Return if global dragging is not enabled or we are already dragging
-        if (!mLauncher.isDraggingEnabled()) return false;
-        if (mLauncher.getDragController().isDragging()) return false;
-
-        // Start the drag
-        final DragController dragController = mLauncher.getDragController();
-        dragController.addDragListener(new DragController.DragListener() {
-            @Override
-            public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
-                v.setVisibility(INVISIBLE);
-            }
-
-            @Override
-            public void onDragEnd() {
-                v.setVisibility(VISIBLE);
-                dragController.removeDragListener(this);
-            }
-        });
-
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-        DragOptions options = new DragOptions();
-        options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
-        mLauncher.getWorkspace().beginDragShared(v, this, options);
-        return false;
-    }
-
-    @Override
     public void onDropCompleted(View target, DragObject d, boolean success) { }
 
     @Override
@@ -283,25 +290,32 @@
         ViewGroup.MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
         if (grid.isVerticalBarLayout()) {
             mlp.leftMargin = insets.left;
-            mlp.topMargin = insets.top;
             mlp.rightMargin = insets.right;
             setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
         } else {
-            mlp.leftMargin = mlp.rightMargin = mlp.topMargin = 0;
+            mlp.leftMargin = mlp.rightMargin = 0;
             setPadding(0, 0, 0, 0);
         }
         setLayoutParams(mlp);
 
-        View navBarBg = findViewById(R.id.nav_bar_bg);
-        ViewGroup.LayoutParams navBarBgLp = navBarBg.getLayoutParams();
-        navBarBgLp.height = insets.bottom;
-        navBarBg.setLayoutParams(navBarBgLp);
-
+        mNavBarScrimHeight = insets.bottom;
         InsettableFrameLayout.dispatchInsets(this, insets);
     }
 
-    public SpringAnimationHandler getSpringAnimationHandler() {
-        return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler;
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+
+        if (mNavBarScrimHeight > 0) {
+            canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
+                    mNavBarScrimPaint);
+        }
+    }
+
+    @Override
+    public int getCanvasClipTopForOverscroll() {
+        // Do not clip if the QSB is attached to the spring, otherwise the QSB will get clipped.
+        return mSpringViews.get(getSearchView().getId()) ? 0 : mHeader.getTop();
     }
 
     private void rebindAdapters(boolean showTabs) {
@@ -330,8 +344,6 @@
 
         mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
         mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
-
-        applyTouchDelegate();
     }
 
     private void replaceRVContainer(boolean showTabs) {
@@ -361,8 +373,7 @@
 
     public void onTabChanged(int pos) {
         mHeader.setMainActive(pos == 0);
-        reset();
-        applyTouchDelegate();
+        reset(true /* animate */);
         if (mAH[pos].recyclerView != null) {
             mAH[pos].recyclerView.bindFastScrollbar();
 
@@ -385,6 +396,19 @@
         return mHeader;
     }
 
+    public View getSearchView() {
+        return mSearchContainer;
+    }
+
+    public View getContentView() {
+        return mViewPager == null ? getActiveRecyclerView() : mViewPager;
+    }
+
+    public RecyclerViewFastScroller getScrollBar() {
+        AllAppsRecyclerView rv = getActiveRecyclerView();
+        return rv == null ? null : rv.getScrollbar();
+    }
+
     public void setupHeader() {
         mHeader.setVisibility(View.VISIBLE);
         mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null);
@@ -443,13 +467,47 @@
         }
     }
 
+    /**
+     * Adds an update listener to {@param animator} that adds springs to the animation.
+     */
+    public void addSpringFromFlingUpdateListener(ValueAnimator animator, float velocity) {
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            boolean shouldSpring = true;
+
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                if (shouldSpring
+                        && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) {
+                    int searchViewId = getSearchView().getId();
+                    addSpringView(searchViewId);
+
+                    finishWithShiftAndVelocity(1, velocity * FLING_VELOCITY_MULTIPLIER,
+                            new DynamicAnimation.OnAnimationEndListener() {
+                                @Override
+                                public void onAnimationEnd(DynamicAnimation animation,
+                                        boolean canceled, float value, float velocity) {
+                                    removeSpringView(searchViewId);
+                                }
+                            });
+
+                    shouldSpring = false;
+                }
+            }
+        });
+    }
+
+    @Override
+    public void getDrawingRect(Rect outRect) {
+        super.getDrawingRect(outRect);
+        outRect.offset(0, (int) getTranslationY());
+    }
+
     public class AdapterHolder {
         public static final int MAIN = 0;
         public static final int WORK = 1;
 
         public final AllAppsGridAdapter adapter;
         final LinearLayoutManager layoutManager;
-        final SpringAnimationHandler animationHandler;
         final AlphabeticalAppsList appsList;
         final Rect padding = new Rect();
         AllAppsRecyclerView recyclerView;
@@ -457,25 +515,21 @@
 
         AdapterHolder(boolean isWork) {
             appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
-            adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
-                    AllAppsContainerView.this, true);
+            adapter = new AllAppsGridAdapter(mLauncher, appsList);
             appsList.setAdapter(adapter);
-            animationHandler = adapter.getSpringAnimationHandler();
             layoutManager = adapter.getLayoutManager();
         }
 
         void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
             appsList.updateItemFilter(matcher);
             recyclerView = (AllAppsRecyclerView) rv;
+            recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
             recyclerView.setApps(appsList, mUsingTabs);
             recyclerView.setLayoutManager(layoutManager);
             recyclerView.setAdapter(adapter);
             recyclerView.setHasFixedSize(true);
             // No animations will occur when changes occur to the items in this RecyclerView.
             recyclerView.setItemAnimator(null);
-            if (FeatureFlags.LAUNCHER3_PHYSICS && animationHandler != null) {
-                recyclerView.setSpringAnimationHandler(animationHandler);
-            }
             FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
             recyclerView.addItemDecoration(focusedItemDecorator);
             adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index a61521c..27fc53a 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,8 +18,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.support.animation.DynamicAnimation;
-import android.support.animation.SpringAnimation;
 import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@@ -38,11 +36,10 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
-import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.PackageManagerHelper;
 
 import java.util.List;
@@ -71,7 +68,6 @@
     // Common view type masks
     public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
     public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
-    public static final int VIEW_TYPE_MASK_HAS_SPRINGS = VIEW_TYPE_MASK_ICON;
 
 
     public interface BindViewCallback {
@@ -182,8 +178,6 @@
     private final AlphabeticalAppsList mApps;
     private final GridLayoutManager mGridLayoutMgr;
     private final GridSpanSizer mGridSizer;
-    private final View.OnClickListener mIconClickListener;
-    private final View.OnLongClickListener mIconLongClickListener;
 
     private final int mAppsPerRow;
 
@@ -195,10 +189,7 @@
     // The intent to send off to the market app, updated each time the search query changes.
     private Intent mMarketSearchIntent;
 
-    private final SpringAnimationHandler<ViewHolder> mSpringAnimationHandler;
-
-    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
-            iconClickListener, View.OnLongClickListener iconLongClickListener, boolean springAnim) {
+    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps) {
         Resources res = launcher.getResources();
         mLauncher = launcher;
         mApps = apps;
@@ -207,23 +198,11 @@
         mGridLayoutMgr = new AppsGridLayoutManager(launcher);
         mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
         mLayoutInflater = LayoutInflater.from(launcher);
-        mIconClickListener = iconClickListener;
-        mIconLongClickListener = iconLongClickListener;
-        if (FeatureFlags.LAUNCHER3_PHYSICS && springAnim) {
-            mSpringAnimationHandler = new SpringAnimationHandler<>(
-                    SpringAnimationHandler.Y_DIRECTION, new AllAppsSpringAnimationFactory());
-        } else {
-            mSpringAnimationHandler = null;
-        }
 
         mAppsPerRow = mLauncher.getDeviceProfile().inv.numColumns;
         mGridLayoutMgr.setSpanCount(mAppsPerRow);
     }
 
-    public SpringAnimationHandler getSpringAnimationHandler() {
-        return mSpringAnimationHandler;
-    }
-
     public static boolean isDividerViewType(int viewType) {
         return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
     }
@@ -270,8 +249,8 @@
             case VIEW_TYPE_ICON:
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
                         R.layout.all_apps_icon, parent, false);
-                icon.setOnClickListener(mIconClickListener);
-                icon.setOnLongClickListener(mIconLongClickListener);
+                icon.setOnClickListener(ItemClickHandler.INSTANCE);
+                icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
                 icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
                 icon.setOnFocusChangeListener(mIconFocusListener);
 
@@ -344,22 +323,6 @@
     }
 
     @Override
-    public void onViewAttachedToWindow(ViewHolder holder) {
-        int type = holder.getItemViewType();
-        if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
-            mSpringAnimationHandler.add(holder.itemView, holder);
-        }
-    }
-
-    @Override
-    public void onViewDetachedFromWindow(ViewHolder holder) {
-        int type = holder.getItemViewType();
-        if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
-            mSpringAnimationHandler.remove(holder.itemView);
-        }
-    }
-
-    @Override
     public boolean onFailedToRecycleView(ViewHolder holder) {
         // Always recycle and we will reset the view when it is bound
         return true;
@@ -376,104 +339,4 @@
         return item.viewType;
     }
 
-    /**
-     * Helper class to set the SpringAnimation values for an item in the adapter.
-     */
-    private class AllAppsSpringAnimationFactory
-            implements SpringAnimationHandler.AnimationFactory<ViewHolder> {
-        private static final float DEFAULT_MAX_VALUE_PX = 100;
-        private static final float DEFAULT_MIN_VALUE_PX = -DEFAULT_MAX_VALUE_PX;
-
-        // Damping ratio range is [0, 1]
-        private static final float SPRING_DAMPING_RATIO = 0.55f;
-
-        // Stiffness is a non-negative number.
-        private static final float MIN_SPRING_STIFFNESS = 580f;
-        private static final float MAX_SPRING_STIFFNESS = 900f;
-
-        // The amount by which each adjacent rows' stiffness will differ.
-        private static final float ROW_STIFFNESS_COEFFICIENT = 50f;
-
-        // The percentage by which we multiply each row to create the row factor.
-        private static final float ROW_PERCENTAGE = 0.3f;
-
-        @Override
-        public SpringAnimation initialize(ViewHolder vh) {
-            return SpringAnimationHandler.forView(vh.itemView, DynamicAnimation.TRANSLATION_Y, 0);
-        }
-
-        /**
-         * @param spring A new or recycled SpringAnimation.
-         * @param vh The ViewHolder that {@param spring} is related to.
-         */
-        @Override
-        public void update(SpringAnimation spring, ViewHolder vh) {
-            int appPosition = vh.getAdapterPosition();
-            int col = appPosition % mAppsPerRow;
-            int row = appPosition / mAppsPerRow;
-
-            int numTotalRows = mApps.getNumAppRows() - 1; // zero-based count
-            if (row > (numTotalRows / 2)) {
-                // Mirror the rows so that the top row acts the same as the bottom row.
-                row = Math.abs(numTotalRows - row);
-            }
-
-            calculateSpringValues(spring, row, col);
-        }
-
-        @Override
-        public void setDefaultValues(SpringAnimation spring) {
-            calculateSpringValues(spring, 0, mAppsPerRow / 2);
-        }
-
-        /**
-         * We manipulate the stiffness, min, and max values based on the items distance to the
-         * first row and the items distance to the center column to create the ^-shaped motion
-         * effect.
-         */
-        private void calculateSpringValues(SpringAnimation spring, int row, int col) {
-            float rowFactor = (1 + row) * ROW_PERCENTAGE;
-            float colFactor = getColumnFactor(col, mAppsPerRow);
-
-            float minValue = DEFAULT_MIN_VALUE_PX * (rowFactor + colFactor);
-            float maxValue = DEFAULT_MAX_VALUE_PX * (rowFactor + colFactor);
-
-            float stiffness = Utilities.boundToRange(
-                    MAX_SPRING_STIFFNESS - (row * ROW_STIFFNESS_COEFFICIENT),
-                    MIN_SPRING_STIFFNESS,
-                    MAX_SPRING_STIFFNESS);
-
-            spring.setMinValue(minValue)
-                    .setMaxValue(maxValue)
-                    .getSpring()
-                    .setStiffness(stiffness)
-                    .setDampingRatio(SPRING_DAMPING_RATIO);
-        }
-
-        /**
-         * Increase the column factor as the distance increases between the column and the center
-         * column(s).
-         */
-        private float getColumnFactor(int col, int numCols) {
-            float centerColumn = numCols / 2;
-            int distanceToCenter = (int) Math.abs(col - centerColumn);
-
-            boolean evenNumberOfColumns = numCols % 2 == 0;
-            if (evenNumberOfColumns && col < centerColumn) {
-                distanceToCenter -= 1;
-            }
-
-            float factor = 0;
-            while (distanceToCenter > 0) {
-                if (distanceToCenter == 1) {
-                    factor += 0.2f;
-                } else {
-                    factor += 0.1f;
-                }
-                --distanceToCenter;
-            }
-
-            return factor;
-        }
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
index 86186fd..69068c6 100644
--- a/src/com/android/launcher3/allapps/AllAppsPagedView.java
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -17,13 +17,17 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 
 import com.android.launcher3.PagedView;
-import com.android.launcher3.R;
 
 public class AllAppsPagedView extends PagedView<PersonalWorkSlidingTabStrip> {
 
-    public AllAppsPagedView(Context context) {
+  final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;
+  final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;
+  final static float TOUCH_SLOP_DAMPING_FACTOR = 4;
+
+  public AllAppsPagedView(Context context) {
         this(context, null);
     }
 
@@ -37,8 +41,8 @@
 
     @Override
     protected String getCurrentPageDescription() {
-        return getResources().getString(
-                getNextPage() == 0 ? R.string.all_apps_personal_tab : R.string.all_apps_work_tab);
+        // Not necessary, tab-bar already has two tabs with their own descriptions.
+        return "";
     }
 
     @Override
@@ -46,4 +50,35 @@
         super.onScrollChanged(l, t, oldl, oldt);
         mPageIndicator.setScroll(l, mMaxScrollX);
     }
+
+    @Override
+    protected void determineScrollingStart(MotionEvent ev) {
+        float absDeltaX = Math.abs(ev.getX() - getDownMotionX());
+        float absDeltaY = Math.abs(ev.getY() - getDownMotionY());
+
+        if (Float.compare(absDeltaX, 0f) == 0) return;
+
+        float slope = absDeltaY / absDeltaX;
+        float theta = (float) Math.atan(slope);
+
+        if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {
+            cancelCurrentPageLongPress();
+        }
+
+        if (theta > MAX_SWIPE_ANGLE) {
+            return;
+        } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {
+            theta -= START_DAMPING_TOUCH_SLOP_ANGLE;
+            float extraRatio = (float)
+                    Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));
+            super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);
+        } else {
+            super.determineScrollingStart(ev);
+        }
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 53d19eb..a6c1346 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -17,14 +17,12 @@
 
 import static android.view.View.MeasureSpec.UNSPECIFIED;
 
-import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
-import android.util.Property;
 import android.util.SparseIntArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -35,12 +33,8 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.DrawableFactory;
 import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
-import com.android.launcher3.touch.OverScroll;
-import com.android.launcher3.touch.SwipeDetector;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -64,23 +58,6 @@
     private AllAppsBackgroundDrawable mEmptySearchBackground;
     private int mEmptySearchBackgroundTopOffset;
 
-    private SpringAnimationHandler mSpringAnimationHandler;
-    private OverScrollHelper mOverScrollHelper;
-    private SwipeDetector mPullDetector;
-    private float mContentTranslationY = 0;
-    public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y =
-            new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") {
-                @Override
-                public Float get(AllAppsRecyclerView allAppsRecyclerView) {
-                    return allAppsRecyclerView.getContentTranslationY();
-                }
-
-                @Override
-                public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) {
-                    allAppsRecyclerView.setContentTranslationY(y);
-                }
-            };
-
     public AllAppsRecyclerView(Context context) {
         this(context, null);
     }
@@ -97,33 +74,11 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr);
         Resources res = getResources();
-        addOnItemTouchListener(this);
         mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
                 R.dimen.all_apps_empty_search_bg_top_offset);
-
-        mOverScrollHelper = new OverScrollHelper();
-        mPullDetector = new SwipeDetector(getContext(), mOverScrollHelper, SwipeDetector.VERTICAL);
-        mPullDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
-
         mNumAppsPerRow = LauncherAppState.getIDP(context).numColumns;
     }
 
-    public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
-        if (FeatureFlags.LAUNCHER3_PHYSICS) {
-            mSpringAnimationHandler = springAnimationHandler;
-            addOnScrollListener(new SpringMotionOnScrollListener());
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent e) {
-        mPullDetector.onTouchEvent(e);
-        if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) {
-            mSpringAnimationHandler.addMovement(e);
-        }
-        return super.onTouchEvent(e);
-    }
-
     /**
      * Sets the list of apps in this view, used to determine the fastscroll position.
      */
@@ -171,26 +126,6 @@
     }
 
     @Override
-    protected void dispatchDraw(Canvas canvas) {
-        canvas.translate(0, mContentTranslationY);
-        super.dispatchDraw(canvas);
-        canvas.translate(0, -mContentTranslationY);
-    }
-
-    public float getContentTranslationY() {
-        return mContentTranslationY;
-    }
-
-    /**
-     * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing
-     * on top of other Views.
-     */
-    public void setContentTranslationY(float y) {
-        mContentTranslationY = y;
-        invalidate();
-    }
-
-    @Override
     protected boolean verifyDrawable(Drawable who) {
         return who == mEmptySearchBackground || super.verifyDrawable(who);
     }
@@ -232,8 +167,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent e) {
-        mPullDetector.onTouchEvent(e);
-        boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll();
+        boolean result = super.onInterceptTouchEvent(e);
         if (!result && e.getAction() == MotionEvent.ACTION_DOWN
                 && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
             mEmptySearchBackground.setHotspot(e.getX(), e.getY());
@@ -481,114 +415,8 @@
                 y + mEmptySearchBackground.getIntrinsicHeight());
     }
 
-    private class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
-
-        @Override
-        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-            if (mOverScrollHelper.isInOverScroll()) {
-                // OverScroll will handle animating the springs.
-                return;
-            }
-
-            // We only start the spring animation when we hit the top/bottom, to ensure
-            // that all of the animations start at the same time.
-            if (dy < 0 && !canScrollVertically(-1)) {
-                mSpringAnimationHandler.animateToFinalPosition(0, 1);
-            } else if (dy > 0 && !canScrollVertically(1)) {
-                mSpringAnimationHandler.animateToFinalPosition(0, -1);
-            }
-        }
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
     }
-
-    private class OverScrollHelper implements SwipeDetector.Listener {
-
-        private static final float MAX_RELEASE_VELOCITY = 5000; // px / s
-        private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f;
-
-        private boolean mIsInOverScroll;
-
-        // We use this value to calculate the actual amount the user has overscrolled.
-        private float mFirstDisplacement = 0;
-
-        private boolean mAlreadyScrollingUp;
-        private int mFirstScrollYOnScrollUp;
-
-        @Override
-        public void onDragStart(boolean start) {
-        }
-
-        @Override
-        public boolean onDrag(float displacement, float velocity) {
-            boolean isScrollingUp = displacement > 0;
-            if (isScrollingUp) {
-                if (!mAlreadyScrollingUp) {
-                    mFirstScrollYOnScrollUp = getCurrentScrollY();
-                    mAlreadyScrollingUp = true;
-                }
-            } else {
-                mAlreadyScrollingUp = false;
-            }
-
-            // Only enter overscroll if the user is interacting with the RecyclerView directly
-            // and if one of the following criteria are met:
-            // - User scrolls down when they're already at the bottom.
-            // - User starts scrolling up, hits the top, and continues scrolling up.
-            boolean wasInOverScroll = mIsInOverScroll;
-            mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
-                    ((!canScrollVertically(1) && displacement < 0) ||
-                    (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
-
-            if (wasInOverScroll && !mIsInOverScroll) {
-                // Exit overscroll. This can happen when the user is in overscroll and then
-                // scrolls the opposite way.
-                reset(false /* shouldSpring */);
-            } else if (mIsInOverScroll) {
-                if (Float.compare(mFirstDisplacement, 0) == 0) {
-                    // Because users can scroll before entering overscroll, we need to
-                    // subtract the amount where the user was not in overscroll.
-                    mFirstDisplacement = displacement;
-                }
-                float overscrollY = displacement - mFirstDisplacement;
-                setContentTranslationY(getDampedOverScroll(overscrollY));
-            }
-
-            return mIsInOverScroll;
-        }
-
-        @Override
-        public void onDragEnd(float velocity, boolean fling) {
-           reset(mIsInOverScroll  /* shouldSpring */);
-        }
-
-        private void reset(boolean shouldSpring) {
-            float y = getContentTranslationY();
-            if (Float.compare(y, 0) != 0) {
-                if (mSpringAnimationHandler != null && shouldSpring) {
-                    // We calculate our own velocity to give the springs the desired effect.
-                    float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
-                    // We want to negate the velocity because we are moving to 0 from -1 due to the
-                    // downward motion. (y-axis -1 is above 0).
-                    mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
-                }
-
-                ObjectAnimator.ofFloat(AllAppsRecyclerView.this,
-                        AllAppsRecyclerView.CONTENT_TRANS_Y, 0)
-                        .setDuration(100)
-                        .start();
-            }
-            mIsInOverScroll = false;
-            mFirstDisplacement = 0;
-            mFirstScrollYOnScrollUp = 0;
-            mAlreadyScrollingUp = false;
-        }
-
-        public boolean isInOverScroll() {
-            return mIsInOverScroll;
-        }
-
-        private float getDampedOverScroll(float y) {
-            return OverScroll.dampedScroll(y, getHeight());
-        }
-    }
-
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c859347..24a8d51 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,7 +1,16 @@
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.LauncherState.VERTICAL_SWIPE_INDICATOR;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE;
+import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS;
 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.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
 
 import android.animation.Animator;
@@ -13,20 +22,16 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
 import com.android.launcher3.LauncherStateManager.AnimationConfig;
 import com.android.launcher3.LauncherStateManager.StateHandler;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.AllAppsScrim;
+import com.android.launcher3.views.ScrimView;
 
 /**
  * Handles AllApps view transition.
@@ -38,8 +43,7 @@
  * If release velocity < THRES1, snap according to either top or bottom depending on whether it's
  * closer to top or closer to the page indicator.
  */
-public class AllAppsTransitionController
-        implements OnScrollRangeChangeListener, StateHandler, OnDeviceProfileChangeListener {
+public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
 
     public static final Property<AllAppsTransitionController, Float> ALL_APPS_PROGRESS =
             new Property<AllAppsTransitionController, Float>(Float.class, "allAppsProgress") {
@@ -55,11 +59,8 @@
         }
     };
 
-    public static final float PARALLAX_COEFFICIENT = .125f;
-
     private AllAppsContainerView mAppsView;
-    private Workspace mWorkspace;
-    private Hotseat mHotseat;
+    private ScrimView mScrimView;
 
     private final Launcher mLauncher;
     private final boolean mIsDarkTheme;
@@ -74,13 +75,11 @@
     private float mShiftRange;      // changes depending on the orientation
     private float mProgress;        // [0, 1], mShiftRange * mProgress = shiftCurrent
 
-    private static final float DEFAULT_SHIFT_RANGE = 10;
-
-    private AllAppsScrim mAllAppsScrim;
+    private float mScrollRangeDelta = 0;
 
     public AllAppsTransitionController(Launcher l) {
         mLauncher = l;
-        mShiftRange = DEFAULT_SHIFT_RANGE;
+        mShiftRange = mLauncher.getDeviceProfile().heightPx;
         mProgress = 1f;
 
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
@@ -94,19 +93,18 @@
 
     private void onProgressAnimationStart() {
         // Initialize values that should not change until #onDragEnd
-        mHotseat.setVisibility(View.VISIBLE);
         mAppsView.setVisibility(View.VISIBLE);
     }
 
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
         mIsVerticalLayout = dp.isVerticalBarLayout();
+        setScrollRangeDelta(mScrollRangeDelta);
 
         if (mIsVerticalLayout) {
             mAppsView.setAlpha(1);
             mLauncher.getHotseat().setTranslationY(0);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
     }
 
@@ -121,31 +119,25 @@
      */
     public void setProgress(float progress) {
         mProgress = progress;
+        mScrimView.setProgress(progress);
         float shiftCurrent = progress * mShiftRange;
 
-        float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
-        float alpha = 1 - workspaceHotseatAlpha;
-
         mAppsView.setTranslationY(shiftCurrent);
-        if (mAllAppsScrim == null) {
-            mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim);
-        }
         float hotseatTranslation = -mShiftRange + shiftCurrent;
-        mAllAppsScrim.setProgress(hotseatTranslation, alpha);
 
         if (!mIsVerticalLayout) {
-            mAppsView.setAlpha(alpha);
             mLauncher.getHotseat().setTranslationY(hotseatTranslation);
             mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
+        }
 
-            // Use a light system UI (dark icons) if all apps is behind at least half of the
-            // status bar.
-            boolean forceChange = shiftCurrent <= mShiftRange / 4;
-            if (forceChange) {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
-            } else {
-                mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
-            }
+        // Use a light system UI (dark icons) if all apps is behind at least half of the
+        // status bar.
+        boolean forceChange = shiftCurrent - mScrimView.getDragHandleSize()
+                <= mLauncher.getDeviceProfile().getInsets().top / 2;
+        if (forceChange) {
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme);
+        } else {
+            mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0);
         }
     }
 
@@ -160,6 +152,7 @@
     @Override
     public void setState(LauncherState state) {
         setProgress(state.getVerticalProgress(mLauncher));
+        setAlphas(state, null, new AnimatorSetBuilder());
         onProgressAnimationEnd();
     }
 
@@ -172,19 +165,49 @@
             AnimatorSetBuilder builder, AnimationConfig config) {
         float targetProgress = toState.getVerticalProgress(mLauncher);
         if (Float.compare(mProgress, targetProgress) == 0) {
+            setAlphas(toState, config, builder);
             // Fail fast
             onProgressAnimationEnd();
             return;
         }
 
-        Interpolator interpolator = config.userControlled ? LINEAR : FAST_OUT_SLOW_IN;
+        if (!config.playNonAtomicComponent()) {
+            // There is no atomic component for the all apps transition, so just return early.
+            return;
+        }
+
+        Interpolator interpolator = config.userControlled ? LINEAR : toState == OVERVIEW
+                ? builder.getInterpolator(ANIM_OVERVIEW_SCALE, FAST_OUT_SLOW_IN)
+                : FAST_OUT_SLOW_IN;
         ObjectAnimator anim =
                 ObjectAnimator.ofFloat(this, ALL_APPS_PROGRESS, mProgress, targetProgress);
         anim.setDuration(config.duration);
-        anim.setInterpolator(interpolator);
+        anim.setInterpolator(builder.getInterpolator(ANIM_VERTICAL_PROGRESS, interpolator));
         anim.addListener(getProgressAnimatorListener());
 
         builder.play(anim);
+
+        setAlphas(toState, config, builder);
+    }
+
+    private void setAlphas(LauncherState toState, AnimationConfig config,
+            AnimatorSetBuilder builder) {
+        PropertySetter setter = config == null ? NO_ANIM_PROPERTY_SETTER
+                : config.getPropertySetter(builder);
+        int visibleElements = toState.getVisibleElements(mLauncher);
+        boolean hasHeader = (visibleElements & ALL_APPS_HEADER) != 0;
+        boolean hasHeaderExtra = (visibleElements & ALL_APPS_HEADER_EXTRA) != 0;
+        boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
+
+        Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
+        setter.setViewAlpha(mAppsView.getSearchView(), hasHeader ? 1 : 0, allAppsFade);
+        setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, allAppsFade);
+        setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, allAppsFade);
+        mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasContent, setter,
+                allAppsFade);
+
+        setter.setInt(mScrimView, ScrimView.DRAG_HANDLE_ALPHA,
+                (visibleElements & VERTICAL_SWIPE_INDICATOR) != 0 ? 255 : 0, LINEAR);
     }
 
     public AnimatorListenerAdapter getProgressAnimatorListener() {
@@ -201,18 +224,21 @@
         };
     }
 
-    public void setupViews(AllAppsContainerView appsView, Hotseat hotseat, Workspace workspace) {
+    public void setupViews(AllAppsContainerView appsView) {
         mAppsView = appsView;
-        mHotseat = hotseat;
-        mWorkspace = workspace;
-        mHotseat.bringToFront();
-        mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
+        mScrimView = mLauncher.findViewById(R.id.scrim_view);
     }
 
-    @Override
-    public void onScrollRangeChanged(int scrollRange) {
-        mShiftRange = scrollRange;
-        setProgress(mProgress);
+    /**
+     * Updates the total scroll range but does not update the UI.
+     */
+    public void setScrollRangeDelta(float delta) {
+        mScrollRangeDelta = delta;
+        mShiftRange = mLauncher.getDeviceProfile().heightPx - mScrollRangeDelta;
+
+        if (mScrimView != null) {
+            mScrimView.reInitUi();
+        }
     }
 
     /**
@@ -222,15 +248,12 @@
     private void onProgressAnimationEnd() {
         if (Float.compare(mProgress, 1f) == 0) {
             mAppsView.setVisibility(View.INVISIBLE);
-            mHotseat.setVisibility(View.VISIBLE);
-            mAppsView.reset();
+            mAppsView.reset(false /* animate */);
         } else if (Float.compare(mProgress, 0f) == 0) {
-            mHotseat.setVisibility(View.INVISIBLE);
             mAppsView.setVisibility(View.VISIBLE);
             mAppsView.onScrollUpEnd();
         } else {
             mAppsView.setVisibility(View.VISIBLE);
-            mHotseat.setVisibility(View.VISIBLE);
         }
     }
 }
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index fddafb2..76b2565 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -17,45 +17,51 @@
 package com.android.launcher3.allapps;
 
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.HOTSEAT;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.PREDICTION;
 
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
 import android.app.ActivityManager;
-import android.content.Context;
+import android.os.Handler;
 import android.view.MotionEvent;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.states.InternalStateHandler;
 
 /**
- * Floating view responsible for showing discovery bounce animation
+ * Abstract base class of floating view responsible for showing discovery bounce animation
  */
 public class DiscoveryBounce extends AbstractFloatingView {
 
-    public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
+    private static final long DELAY_MS = 450;
+
+    public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
+    public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
 
     private final Launcher mLauncher;
     private final Animator mDiscoBounceAnimation;
 
-    public DiscoveryBounce(Launcher launcher) {
+    public DiscoveryBounce(Launcher launcher, float delta) {
         super(launcher, null);
         mLauncher = launcher;
-
-        mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
-                R.animator.discovery_bounce);
         AllAppsTransitionController controller = mLauncher.getAllAppsController();
-        mDiscoBounceAnimation.setTarget(controller);
-        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
 
+        mDiscoBounceAnimation =
+                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
+        mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(controller, delta));
         mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 handleClose(false);
             }
         });
+        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
     }
 
     @Override
@@ -73,6 +79,14 @@
     }
 
     @Override
+    public boolean onBackPressed() {
+        super.onBackPressed();
+        // Go back to the previous state (from a user's perspective this floating view isn't
+        // something to go back from).
+        return false;
+    }
+
+    @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         handleClose(false);
         return false;
@@ -83,6 +97,9 @@
         if (mIsOpen) {
             mIsOpen = false;
             mLauncher.getDragLayer().removeView(this);
+            // Reset the all-apps progress to what ever it was previously.
+            mLauncher.getAllAppsController().setProgress(mLauncher.getStateManager()
+                    .getState().getVerticalProgress(mLauncher));
         }
     }
 
@@ -93,20 +110,91 @@
 
     @Override
     protected boolean isOfType(int type) {
-        return (type & TYPE_ON_BOARD_POPUP) != 0;
+        return (type & TYPE_DISCOVERY_BOUNCE) != 0;
     }
 
-    public static void showIfNeeded(Launcher launcher) {
+    private void show(int containerType) {
+        mIsOpen = true;
+        mLauncher.getDragLayer().addView(this);
+        mLauncher.getUserEventDispatcher().logActionBounceTip(containerType);
+    }
+
+    public static void showForHomeIfNeeded(Launcher launcher) {
+        showForHomeIfNeeded(launcher, true);
+    }
+
+    private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
         if (!launcher.isInState(NORMAL)
-                || launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
+                || (launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
+                && !shouldShowForWorkProfile(launcher))
                 || AbstractFloatingView.getTopOpenView(launcher) != null
                 || UserManagerCompat.getInstance(launcher).isDemoUser()
                 || ActivityManager.isRunningInTestHarness()) {
             return;
         }
 
-        DiscoveryBounce view = new DiscoveryBounce(launcher);
-        view.mIsOpen = true;
-        launcher.getDragLayer().addView(view);
+        if (withDelay) {
+            new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
+            return;
+        }
+
+        new DiscoveryBounce(launcher, 0).show(HOTSEAT);
+    }
+
+    public static void showForOverviewIfNeeded(Launcher launcher) {
+        showForOverviewIfNeeded(launcher, true);
+    }
+
+    private static void showForOverviewIfNeeded(Launcher launcher, boolean withDelay) {
+        if (!launcher.isInState(OVERVIEW)
+                || !launcher.hasBeenResumed()
+                || launcher.isForceInvisible()
+                || launcher.getDeviceProfile().isVerticalBarLayout()
+                || (launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
+                && !shouldShowForWorkProfile(launcher))
+                || UserManagerCompat.getInstance(launcher).isDemoUser()
+                || ActivityManager.isRunningInTestHarness()) {
+            return;
+        }
+
+        if (withDelay) {
+            new Handler().postDelayed(() -> showForOverviewIfNeeded(launcher, false), DELAY_MS);
+            return;
+        } else if (InternalStateHandler.hasPending()
+                || AbstractFloatingView.getTopOpenView(launcher) != null) {
+            // TODO: Move these checks to the top and call this method after invalidate handler.
+            return;
+        }
+
+        new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
+                .show(PREDICTION);
+    }
+
+    /**
+     * A wrapper around {@link AllAppsTransitionController} allowing a fixed shift in the value.
+     */
+    public static class VerticalProgressWrapper {
+
+        private final float mDelta;
+        private final AllAppsTransitionController mController;
+
+        private VerticalProgressWrapper(AllAppsTransitionController controller, float delta) {
+            mController = controller;
+            mDelta = delta;
+        }
+
+        public float getProgress() {
+            return mController.getProgress() + mDelta;
+        }
+
+        public void setProgress(float progress) {
+            mController.setProgress(progress - mDelta);
+        }
+    }
+
+    private static boolean shouldShowForWorkProfile(Launcher launcher) {
+        return !launcher.getSharedPrefs().getBoolean(
+                PersonalWorkSlidingTabStrip.KEY_SHOWED_PEEK_WORK_TAB, false)
+                && UserManagerCompat.getInstance(launcher).hasWorkProfile();
     }
 }
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index d8a9f63..eaa7774 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -26,10 +26,11 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.animation.Interpolator;
 import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
 
 import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertySetter;
 
 public class FloatingHeaderView extends LinearLayout implements
         ValueAnimator.AnimatorUpdateListener {
@@ -58,7 +59,7 @@
         }
     };
 
-    private ViewGroup mTabLayout;
+    protected ViewGroup mTabLayout;
     private AllAppsRecyclerView mMainRV;
     private AllAppsRecyclerView mWorkRV;
     private AllAppsRecyclerView mCurrentRV;
@@ -66,9 +67,13 @@
     private boolean mHeaderCollapsed;
     private int mSnappedScrolledY;
     private int mTranslationY;
+
+    private boolean mAllowTouchForwarding;
     private boolean mForwardToRecyclerView;
 
+    protected boolean mTabsHidden;
     protected int mMaxTranslation;
+    private boolean mMainRVActive = true;
 
     public FloatingHeaderView(@NonNull Context context) {
         this(context, null);
@@ -85,12 +90,13 @@
     }
 
     public void setup(AllAppsContainerView.AdapterHolder[] mAH, boolean tabsHidden) {
+        mTabsHidden = tabsHidden;
         mTabLayout.setVisibility(tabsHidden ? View.GONE : View.VISIBLE);
         mMainRV = setupRV(mMainRV, mAH[AllAppsContainerView.AdapterHolder.MAIN].recyclerView);
         mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
         mParent = (ViewGroup) mMainRV.getParent();
-        setMainActive(true);
-        reset();
+        setMainActive(mMainRVActive || mWorkRV == null);
+        reset(false);
     }
 
     private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
@@ -102,10 +108,17 @@
 
     public void setMainActive(boolean active) {
         mCurrentRV = active ? mMainRV : mWorkRV;
+        mMainRVActive = active;
     }
 
     public int getMaxTranslation() {
-        return mMaxTranslation;
+        if (mMaxTranslation == 0 && mTabsHidden) {
+            return getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_bottom_padding);
+        } else if (mMaxTranslation > 0 && mTabsHidden) {
+            return mMaxTranslation + getPaddingTop();
+        } else {
+            return mMaxTranslation;
+        }
     }
 
     private boolean canSnapAt(int currentScrollY) {
@@ -131,7 +144,7 @@
                 mSnappedScrolledY = currentScrollY - mMaxTranslation;
             } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
                 mHeaderCollapsed = true;
-                mSnappedScrolledY = currentScrollY;
+                mSnappedScrolledY = -mMaxTranslation;
             }
         }
     }
@@ -151,12 +164,19 @@
         }
     }
 
-    public void reset() {
-        int translateTo = 0;
-        mAnimator.setIntValues(mTranslationY, translateTo);
-        mAnimator.addUpdateListener(this);
-        mAnimator.setDuration(150);
-        mAnimator.start();
+    public void reset(boolean animate) {
+        if (mAnimator.isStarted()) {
+            mAnimator.cancel();
+        }
+        if (animate) {
+            mAnimator.setIntValues(mTranslationY, 0);
+            mAnimator.addUpdateListener(this);
+            mAnimator.setDuration(150);
+            mAnimator.start();
+        } else {
+            mTranslationY = 0;
+            apply();
+        }
         mHeaderCollapsed = false;
         mSnappedScrolledY = -mMaxTranslation;
         mCurrentRV.scrollToTop();
@@ -174,6 +194,10 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (!mAllowTouchForwarding) {
+            mForwardToRecyclerView = false;
+            return super.onInterceptTouchEvent(ev);
+        }
         calcOffset(mTempOffset);
         ev.offsetLocation(mTempOffset.x, mTempOffset.y);
         mForwardToRecyclerView = mCurrentRV.onInterceptTouchEvent(ev);
@@ -201,6 +225,25 @@
         p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
         p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
     }
+
+    public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter,
+            Interpolator fadeInterpolator) {
+        setter.setViewAlpha(this, hasContent ? 1 : 0, fadeInterpolator);
+        allowTouchForwarding(hasContent);
+    }
+
+    protected void allowTouchForwarding(boolean allow) {
+        mAllowTouchForwarding = allow;
+    }
+
+    public boolean hasVisibleContent() {
+        return false;
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
 }
 
 
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index b42d4cd..31c5914 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -28,6 +28,7 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.util.Themes;
 
@@ -38,7 +39,7 @@
     private static final int POSITION_PERSONAL = 0;
     private static final int POSITION_WORK = 1;
 
-    private static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
+    public static final String KEY_SHOWED_PEEK_WORK_TAB = "showed_peek_work_tab";
 
     private final Paint mSelectedIndicatorPaint;
     private final Paint mDividerPaint;
@@ -47,12 +48,12 @@
     private int mSelectedIndicatorHeight;
     private int mIndicatorLeft = -1;
     private int mIndicatorRight = -1;
-    private int mIndicatorPosition = 0;
-    private float mIndicatorOffset;
+    private float mScrollOffset;
     private int mSelectedPosition = 0;
 
     private AllAppsContainerView mContainerView;
     private int mLastActivePage = 0;
+    private boolean mIsRtl;
 
     public PersonalWorkSlidingTabStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
@@ -72,11 +73,11 @@
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
 
         mSharedPreferences = Launcher.getLauncher(getContext()).getSharedPrefs();
+        mIsRtl = Utilities.isRtl(getResources());
     }
 
-    private void updateIndicatorPosition(int position, float positionOffset) {
-        mIndicatorPosition = position;
-        mIndicatorOffset = positionOffset;
+    private void updateIndicatorPosition(float scrollOffset) {
+        mScrollOffset = scrollOffset;
         updateIndicatorPosition();
     }
 
@@ -92,32 +93,23 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         updateTabTextColor(mSelectedPosition);
-        updateIndicatorPosition(mIndicatorPosition, mIndicatorOffset);
+        updateIndicatorPosition(mScrollOffset);
     }
 
     private void updateIndicatorPosition() {
-        final View tab = getChildAt(mIndicatorPosition);
-        int left, right;
-
-        if (tab != null && tab.getWidth() > 0) {
-            left = tab.getLeft();
-            right = tab.getRight();
-
-            if (mIndicatorOffset > 0f && mIndicatorPosition < getChildCount() - 1) {
-                // Draw the selection partway between the tabs
-                View nextTitle = getChildAt(mIndicatorPosition + 1);
-                left = (int) (mIndicatorOffset * nextTitle.getLeft() +
-                        (1.0f - mIndicatorOffset) * left);
-                right = (int) (mIndicatorOffset * nextTitle.getRight() +
-                        (1.0f - mIndicatorOffset) * right);
-            }
-        } else {
-            left = right = -1;
+        int left = -1, right = -1;
+        final View leftTab = getLeftTab();
+        if (leftTab != null) {
+            left = (int) (leftTab.getLeft() + leftTab.getWidth() * mScrollOffset);
+            right = left + leftTab.getWidth();
         }
-
         setIndicatorPosition(left, right);
     }
 
+    private View getLeftTab() {
+        return mIsRtl ? getChildAt(1) : getChildAt(0);
+    }
+
     private void setIndicatorPosition(int left, int right) {
         if (left != mIndicatorLeft || right != mIndicatorRight) {
             mIndicatorLeft = left;
@@ -140,7 +132,7 @@
         if (mSharedPreferences.getBoolean(KEY_SHOWED_PEEK_WORK_TAB, false)) {
             return;
         }
-        if (mIndicatorPosition != POSITION_PERSONAL) {
+        if (mLastActivePage != POSITION_PERSONAL) {
             return;
         }
         highlightWorkTab();
@@ -157,11 +149,8 @@
 
     @Override
     public void setScroll(int currentScroll, int totalScroll) {
-        if (currentScroll == totalScroll) {
-            updateIndicatorPosition(1, 0);
-        } else if (totalScroll > 0) {
-            updateIndicatorPosition(0, ((float) currentScroll) / totalScroll);
-        }
+        float scrollOffset = ((float) currentScroll) / totalScroll;
+        updateIndicatorPosition(scrollOffset);
     }
 
     @Override
@@ -181,8 +170,7 @@
     public void setMarkersCount(int numMarkers) { }
 
     @Override
-    public void setPageDescription(CharSequence description) {
-        // We don't want custom page description as the tab-bar already has two tabs with their
-        // own descriptions.
+    public boolean hasOverlappingRendering() {
+        return false;
     }
 }
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index bb17ed5..68193f5 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.allapps;
 
-import android.support.animation.SpringAnimation;
-import android.support.annotation.NonNull;
 import android.view.KeyEvent;
 
 /**
@@ -30,28 +28,13 @@
     void initialize(AllAppsContainerView containerView);
 
     /**
-     * A {@link SpringAnimation} that will be used when the user flings.
-     */
-    @NonNull SpringAnimation getSpringForFling();
-
-    /**
      * Notifies the search manager to close any active search session.
      */
-    void reset();
+    void resetSearch();
 
     /**
      * Called before dispatching a key event, in case the search manager wants to initialize
      * some UI beforehand.
      */
     void preDispatchKeyEvent(KeyEvent keyEvent);
-
-    void addOnScrollRangeChangeListener(OnScrollRangeChangeListener listener);
-
-    /**
-     * Callback for listening to changes in the vertical scroll range when opening all-apps.
-     */
-    interface OnScrollRangeChangeListener {
-
-        void onScrollRangeChanged(int scrollRange);
-    }
 }
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index e83904f..dcc4554 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -21,6 +21,8 @@
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
 import android.view.inputmethod.EditorInfo;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
@@ -37,7 +39,8 @@
  * An interface to a search box that AllApps can command.
  */
 public class AllAppsSearchBarController
-        implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener {
+        implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
+        OnFocusChangeListener {
 
     protected Launcher mLauncher;
     protected Callbacks mCb;
@@ -62,6 +65,7 @@
         mInput.addTextChangedListener(this);
         mInput.setOnEditorActionListener(this);
         mInput.setOnBackKeyListener(this);
+        mInput.setOnFocusChangeListener(this);
         mSearchAlgorithm = searchAlgorithm;
     }
 
@@ -123,6 +127,13 @@
         return false;
     }
 
+    @Override
+    public void onFocusChange(View view, boolean hasFocus) {
+        if (!hasFocus) {
+            mInput.hideKeyboard();
+        }
+    }
+
     /**
      * Resets the search bar state.
      */
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index a56c8b8..ab6635e 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -15,12 +15,14 @@
  */
 package com.android.launcher3.allapps.search;
 
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.getSize;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static com.android.launcher3.graphics.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
+
 import android.content.Context;
 import android.graphics.Rect;
-import android.support.animation.FloatValueHolder;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -29,10 +31,11 @@
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.View;
-import android.widget.FrameLayout;
+import android.view.ViewGroup.MarginLayoutParams;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsContainerView;
@@ -47,22 +50,21 @@
 /**
  * Layout to contain the All-apps search UI.
  */
-public class AppsSearchContainerLayout extends FrameLayout
+public class AppsSearchContainerLayout extends ExtendedEditText
         implements SearchUiManager, AllAppsSearchBarController.Callbacks,
-        AllAppsStore.OnUpdateListener {
+        AllAppsStore.OnUpdateListener, Insettable {
+
 
     private final Launcher mLauncher;
-    private final int mMinHeight;
-    private final int mSearchBoxHeight;
     private final AllAppsSearchBarController mSearchBarController;
     private final SpannableStringBuilder mSearchQueryBuilder;
 
-    private ExtendedEditText mSearchInput;
     private AlphabeticalAppsList mApps;
-    private View mDivider;
-    private HeaderElevationController mElevationController;
     private AllAppsContainerView mAppsView;
-    private SpringAnimation mSpring;
+
+    // This value was used to position the QSB. We store it here for translationY animations.
+    private final float mFixedTranslationY;
+    private final float mMarginTopAdjusting;
 
     public AppsSearchContainerLayout(Context context) {
         this(context, null);
@@ -76,39 +78,22 @@
         super(context, attrs, defStyleAttr);
 
         mLauncher = Launcher.getLauncher(context);
-        mMinHeight = getResources().getDimensionPixelSize(R.dimen.all_apps_search_bar_height);
-        mSearchBoxHeight = getResources()
-                .getDimensionPixelSize(R.dimen.all_apps_search_bar_field_height);
         mSearchBarController = new AllAppsSearchBarController();
 
         mSearchQueryBuilder = new SpannableStringBuilder();
         Selection.setSelection(mSearchQueryBuilder, 0);
 
-        // Note: This spring does nothing.
-        mSpring = new SpringAnimation(new FloatValueHolder()).setSpring(new SpringForce(0));
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mSearchInput = findViewById(R.id.search_box_input);
-        mDivider = findViewById(R.id.search_divider);
-        mElevationController = new HeaderElevationController(mDivider);
+        mFixedTranslationY = getTranslationY();
+        mMarginTopAdjusting = mFixedTranslationY - getPaddingTop();
 
         // Update the hint to contain the icon.
         // Prefix the original hint with two spaces. The first space gets replaced by the icon
         // using span. The second space is used for a singe space character between the hint
         // and the icon.
-        SpannableString spanned = new SpannableString("  " + mSearchInput.getHint());
+        SpannableString spanned = new SpannableString("  " + getHint());
         spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search),
                 0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
-        mSearchInput.setHint(spanned);
-
-        DeviceProfile dp = mLauncher.getDeviceProfile();
-        if (!dp.isVerticalBarLayout()) {
-            LayoutParams lp = (LayoutParams) mDivider.getLayoutParams();
-            lp.leftMargin = lp.rightMargin = dp.edgeMarginPx;
-        }
+        setHint(spanned);
     }
 
     @Override
@@ -125,26 +110,39 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Update the width to match the grid padding
         DeviceProfile dp = mLauncher.getDeviceProfile();
-        if (!dp.isVerticalBarLayout()) {
-            getLayoutParams().height = dp.getInsets().top + mMinHeight;
-        }
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int myRequestedWidth = getSize(widthMeasureSpec);
+        int rowWidth = myRequestedWidth - mAppsView.getActiveRecyclerView().getPaddingLeft()
+                - mAppsView.getActiveRecyclerView().getPaddingRight();
+
+        int cellWidth = DeviceProfile.calculateCellWidth(rowWidth, dp.inv.numHotseatIcons);
+        int iconVisibleSize = Math.round(ICON_VISIBLE_AREA_FACTOR * dp.iconSizePx);
+        int iconPadding = cellWidth - iconVisibleSize;
+
+        int myWidth = rowWidth - iconPadding + getPaddingLeft() + getPaddingRight();
+        super.onMeasure(makeMeasureSpec(myWidth, EXACTLY), heightMeasureSpec);
     }
 
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        // Shift the widget horizontally so that its centered in the parent (b/63428078)
+        View parent = (View) getParent();
+        int availableWidth = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight();
+        int myWidth = right - left;
+        int expectedLeft = parent.getPaddingLeft() + (availableWidth - myWidth) / 2;
+        int shift = expectedLeft - left;
+        setTranslationX(shift);
+    }
 
     @Override
     public void initialize(AllAppsContainerView appsView) {
         mApps = appsView.getApps();
         mAppsView = appsView;
-        appsView.addElevationController(mElevationController);
         mSearchBarController.initialize(
-                new DefaultAppSearchAlgorithm(mApps.getApps()), mSearchInput, mLauncher, this);
-    }
-
-    @Override
-    public @NonNull SpringAnimation getSpringForFling() {
-        return mSpring;
+                new DefaultAppSearchAlgorithm(mApps.getApps()), this, mLauncher, this);
     }
 
     @Override
@@ -153,8 +151,7 @@
     }
 
     @Override
-    public void reset() {
-        mElevationController.reset();
+    public void resetSearch() {
         mSearchBarController.reset();
     }
 
@@ -200,27 +197,21 @@
     }
 
     private void notifyResultChanged() {
-        mElevationController.reset();
         mAppsView.onSearchResultsChanged();
     }
 
     @Override
-    public void addOnScrollRangeChangeListener(final OnScrollRangeChangeListener listener) {
-        mLauncher.getHotseat().addOnLayoutChangeListener(new OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                DeviceProfile dp = mLauncher.getDeviceProfile();
-                if (!dp.isVerticalBarLayout()) {
-                    Rect insets = dp.getInsets();
-                    int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom;
-                    int searchTopMargin = insets.top + (mMinHeight - mSearchBoxHeight)
-                            + ((MarginLayoutParams) getLayoutParams()).bottomMargin;
-                    listener.onScrollRangeChanged(hotseatBottom - searchTopMargin);
-                } else {
-                    listener.onScrollRangeChanged(bottom);
-                }
-            }
-        });
+    public void setInsets(Rect insets) {
+        MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
+        mlp.topMargin = Math.round(Math.max(-mFixedTranslationY, insets.top - mMarginTopAdjusting));
+        requestLayout();
+
+        DeviceProfile dp = mLauncher.getDeviceProfile();
+        if (dp.isVerticalBarLayout()) {
+            mLauncher.getAllAppsController().setScrollRangeDelta(0);
+        } else {
+            mLauncher.getAllAppsController().setScrollRangeDelta(
+                    insets.bottom + mlp.topMargin + mFixedTranslationY);
+        }
     }
 }
diff --git a/src/com/android/launcher3/allapps/search/HeaderElevationController.java b/src/com/android/launcher3/allapps/search/HeaderElevationController.java
deleted file mode 100644
index 7cd32b2..0000000
--- a/src/com/android/launcher3/allapps/search/HeaderElevationController.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.launcher3.allapps.search;
-
-import android.content.res.Resources;
-import android.graphics.Outline;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-
-import com.android.launcher3.BaseRecyclerView;
-import com.android.launcher3.R;
-
-/**
- * Helper class for controlling the header elevation in response to RecyclerView scroll.
- */
-public class HeaderElevationController extends RecyclerView.OnScrollListener {
-
-    private final View mHeader;
-    private final View mHeaderChild;
-    private final float mMaxElevation;
-    private final float mScrollToElevation;
-
-    private int mCurrentY = 0;
-
-    public HeaderElevationController(View header) {
-        mHeader = header;
-        final Resources res = mHeader.getContext().getResources();
-        mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
-        mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
-
-        // We need to provide a custom outline so the shadow only appears on the bottom edge.
-        // The top, left and right edges are all extended out to match parent's edge, so that
-        // the shadow is clipped by the parent.
-        final ViewOutlineProvider vop = new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                // Set the left and top to be at the parents edge. Since the coordinates are
-                // relative to this view,
-                //    (x = -view.getLeft()) for this view => (x = 0) for parent
-                final int left = -view.getLeft();
-                final int top = -view.getTop();
-
-                // Since the view is centered align, the spacing on left and right are same.
-                // Add same spacing on the right to reach parent's edge.
-                final int right = view.getWidth() - left;
-                final int bottom = view.getHeight();
-                final int offset = (int) mMaxElevation;
-                outline.setRect(left - offset, top - offset, right + offset, bottom);
-            }
-        };
-        mHeader.setOutlineProvider(vop);
-        mHeaderChild = ((ViewGroup) mHeader).getChildAt(0);
-    }
-
-    public void reset() {
-        mCurrentY = 0;
-        onScroll(mCurrentY);
-    }
-
-    @Override
-    public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-        mCurrentY = ((BaseRecyclerView) recyclerView).getCurrentScrollY();
-        onScroll(mCurrentY);
-    }
-
-    private void onScroll(int scrollY) {
-        float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
-        float newElevation = mMaxElevation * elevationPct;
-        if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
-            mHeader.setElevation(newElevation);
-
-            // To simulate a scrolling effect for the header, we translate the header down, and
-            // its content up by the same amount, so that it gets clipped by the parent, making it
-            // look like the content was scrolled out of the view.
-            int shift = Math.min(mHeader.getHeight(), scrollY);
-            mHeader.setTranslationY(-shift);
-            mHeaderChild.setTranslationY(shift);
-        }
-    }
-
-}
diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java
new file mode 100644
index 0000000..a3d02d9
--- /dev/null
+++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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.anim;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.view.View;
+
+/**
+ * A convenience class to update a view's visibility state after an alpha animation.
+ */
+public class AlphaUpdateListener extends AnimationSuccessListener
+        implements AnimatorUpdateListener {
+    private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
+
+    private View mView;
+
+    public AlphaUpdateListener(View v) {
+        mView = v;
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator arg0) {
+        updateVisibility(mView);
+    }
+
+    @Override
+    public void onAnimationSuccess(Animator animator) {
+        updateVisibility(mView);
+    }
+
+    @Override
+    public void onAnimationStart(Animator arg0) {
+        // We want the views to be visible for animation, so fade-in/out is visible
+        mView.setVisibility(View.VISIBLE);
+    }
+
+    public static void updateVisibility(View view) {
+        if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != View.INVISIBLE) {
+            view.setVisibility(View.INVISIBLE);
+        } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
+                && view.getVisibility() != View.VISIBLE) {
+            view.setVisibility(View.VISIBLE);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 68e9847..164728a 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -15,9 +15,13 @@
  */
 package com.android.launcher3.anim;
 
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 
 import java.util.ArrayList;
@@ -33,61 +37,80 @@
  */
 public abstract class AnimatorPlaybackController implements ValueAnimator.AnimatorUpdateListener {
 
+    public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration) {
+        return wrap(anim, duration, null);
+    }
+
     /**
      * Creates an animation controller for the provided animation.
      * The actual duration does not matter as the animation is manually controlled. It just
      * needs to be larger than the total number of pixels so that we don't have jittering due
      * to float (animation-fraction * total duration) to int conversion.
      */
-    public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration) {
+    public static AnimatorPlaybackController wrap(AnimatorSet anim, long duration,
+            Runnable onCancelRunnable) {
 
         /**
          * TODO: use {@link AnimatorSet#setCurrentPlayTime(long)} once b/68382377 is fixed.
          */
-        return new AnimatorPlaybackControllerVL(anim, duration);
+        return new AnimatorPlaybackControllerVL(anim, duration, onCancelRunnable);
     }
 
     private final ValueAnimator mAnimationPlayer;
     private final long mDuration;
 
     protected final AnimatorSet mAnim;
-    private AnimatorSet mOriginalTarget;
 
     protected float mCurrentFraction;
     private Runnable mEndAction;
 
-    protected AnimatorPlaybackController(AnimatorSet anim, long duration) {
+    protected boolean mTargetCancelled = false;
+    protected Runnable mOnCancelRunnable;
+
+    protected AnimatorPlaybackController(AnimatorSet anim, long duration,
+            Runnable onCancelRunnable) {
         mAnim = anim;
-        mOriginalTarget = mAnim;
         mDuration = duration;
+        mOnCancelRunnable = onCancelRunnable;
 
         mAnimationPlayer = ValueAnimator.ofFloat(0, 1);
-        mAnimationPlayer.setInterpolator(Interpolators.LINEAR);
+        mAnimationPlayer.setInterpolator(LINEAR);
         mAnimationPlayer.addListener(new OnAnimationEndDispatcher());
         mAnimationPlayer.addUpdateListener(this);
+
+        mAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mTargetCancelled = true;
+                if (mOnCancelRunnable != null) {
+                    mOnCancelRunnable.run();
+                    mOnCancelRunnable = null;
+                }
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mTargetCancelled = false;
+                mOnCancelRunnable = null;
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mTargetCancelled = false;
+            }
+        });
     }
 
     public AnimatorSet getTarget() {
         return mAnim;
     }
 
-    public void setOriginalTarget(AnimatorSet anim) {
-        mOriginalTarget = anim;
-    }
-
-    public AnimatorSet getOriginalTarget() {
-        return mOriginalTarget;
-    }
-
     public long getDuration() {
         return mDuration;
     }
 
-    public AnimatorPlaybackController cloneFor(AnimatorSet anim) {
-        AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(anim, mDuration);
-        controller.setOriginalTarget(mOriginalTarget);
-        controller.setPlayFraction(mCurrentFraction);
-        return controller;
+    public TimeInterpolator getInterpolator() {
+        return mAnim.getInterpolator() != null ? mAnim.getInterpolator() : LINEAR;
     }
 
     /**
@@ -169,12 +192,50 @@
         }
     }
 
+    public void dispatchOnCancel() {
+        dispatchOnCancelRecursively(mAnim);
+    }
+
+    private void dispatchOnCancelRecursively(Animator animator) {
+        for (AnimatorListener l : nonNullList(animator.getListeners())) {
+            l.onAnimationCancel(animator);
+        }
+
+        if (animator instanceof AnimatorSet) {
+            for (Animator anim : nonNullList(((AnimatorSet) animator).getChildAnimations())) {
+                dispatchOnCancelRecursively(anim);
+            }
+        }
+    }
+
+    public void dispatchSetInterpolator(TimeInterpolator interpolator) {
+        dispatchSetInterpolatorRecursively(mAnim, interpolator);
+    }
+
+    private void dispatchSetInterpolatorRecursively(Animator anim, TimeInterpolator interpolator) {
+        anim.setInterpolator(interpolator);
+        if (anim instanceof AnimatorSet) {
+            for (Animator child : nonNullList(((AnimatorSet) anim).getChildAnimations())) {
+                dispatchSetInterpolatorRecursively(child, interpolator);
+            }
+        }
+    }
+
+    public void setOnCancelRunnable(Runnable runnable) {
+        mOnCancelRunnable = runnable;
+    }
+
+    public Runnable getOnCancelRunnable() {
+        return mOnCancelRunnable;
+    }
+
     public static class AnimatorPlaybackControllerVL extends AnimatorPlaybackController {
 
         private final ValueAnimator[] mChildAnimations;
 
-        private AnimatorPlaybackControllerVL(AnimatorSet anim, long duration) {
-            super(anim, duration);
+        private AnimatorPlaybackControllerVL(AnimatorSet anim, long duration,
+                Runnable onCancelRunnable) {
+            super(anim, duration, onCancelRunnable);
 
             // Build animation list
             ArrayList<ValueAnimator> childAnims = new ArrayList<>();
@@ -184,10 +245,14 @@
 
         private void getAnimationsRecur(AnimatorSet anim, ArrayList<ValueAnimator> out) {
             long forceDuration = anim.getDuration();
+            TimeInterpolator forceInterpolator = anim.getInterpolator();
             for (Animator child : anim.getChildAnimations()) {
                 if (forceDuration > 0) {
                     child.setDuration(forceDuration);
                 }
+                if (forceInterpolator != null) {
+                    child.setInterpolator(forceInterpolator);
+                }
                 if (child instanceof ValueAnimator) {
                     out.add((ValueAnimator) child);
                 } else if (child instanceof AnimatorSet) {
@@ -201,12 +266,16 @@
         @Override
         public void setPlayFraction(float fraction) {
             mCurrentFraction = fraction;
+            // Let the animator report the progress but don't apply the progress to child
+            // animations if it has been cancelled.
+            if (mTargetCancelled) {
+                return;
+            }
             long playPos = clampDuration(fraction);
             for (ValueAnimator anim : mChildAnimations) {
                 anim.setCurrentPlayTime(Math.min(playPos, anim.getDuration()));
             }
         }
-
     }
 
     private class OnAnimationEndDispatcher extends AnimationSuccessListener {
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 7cd9651..307f258 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -17,18 +17,30 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
+import android.util.SparseArray;
+import android.view.animation.Interpolator;
 
 import com.android.launcher3.LauncherAnimUtils;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Utility class for building animator set
  */
 public class AnimatorSetBuilder {
 
+    public static final int ANIM_VERTICAL_PROGRESS = 0;
+    public static final int ANIM_WORKSPACE_SCALE = 1;
+    public static final int ANIM_WORKSPACE_FADE = 2;
+    public static final int ANIM_OVERVIEW_SCALE = 3;
+    public static final int ANIM_OVERVIEW_FADE = 4;
+    public static final int ANIM_ALL_APPS_FADE = 5;
+
     protected final ArrayList<Animator> mAnims = new ArrayList<>();
-    private long mStartDelay = 0;
+
+    private final SparseArray<Interpolator> mInterpolators = new SparseArray<>();
+    private List<Runnable> mOnFinishRunnables = new ArrayList<>();
 
     /**
      * Associates a tag with all the animations added after this call.
@@ -39,14 +51,32 @@
         mAnims.add(anim);
     }
 
-    public void setStartDelay(long startDelay) {
-        mStartDelay = startDelay;
+    public void addOnFinishRunnable(Runnable onFinishRunnable) {
+        mOnFinishRunnables.add(onFinishRunnable);
     }
 
     public AnimatorSet build() {
         AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
         anim.playTogether(mAnims);
-        anim.setStartDelay(mStartDelay);
+        if (!mOnFinishRunnables.isEmpty()) {
+            anim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationSuccess(Animator animation) {
+                    for (Runnable onFinishRunnable : mOnFinishRunnables) {
+                        onFinishRunnable.run();
+                    }
+                    mOnFinishRunnables.clear();
+                }
+            });
+        }
         return anim;
     }
+
+    public Interpolator getInterpolator(int animId, Interpolator fallback) {
+        return mInterpolators.get(animId, fallback);
+    }
+
+    public void setInterpolator(int animId, Interpolator interpolator) {
+        mInterpolators.put(animId, interpolator);
+    }
 }
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 0dcebe3..675e26d 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -16,6 +16,10 @@
 
 package com.android.launcher3.anim;
 
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+
+import android.graphics.Path;
+import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -23,6 +27,8 @@
 import android.view.animation.OvershootInterpolator;
 import android.view.animation.PathInterpolator;
 
+import com.android.launcher3.Utilities;
+
 
 /**
  * Common interpolators used in Launcher
@@ -37,32 +43,53 @@
 
     public static final Interpolator DEACCEL = new DecelerateInterpolator();
     public static final Interpolator DEACCEL_1_5 = new DecelerateInterpolator(1.5f);
+    public static final Interpolator DEACCEL_1_7 = new DecelerateInterpolator(1.7f);
     public static final Interpolator DEACCEL_2 = new DecelerateInterpolator(2);
     public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f);
     public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f);
 
+    public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator();
+
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
 
     public static final Interpolator AGGRESSIVE_EASE = new PathInterpolator(0.2f, 0f, 0f, 1f);
-    public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.8f,0, 0.4f, 1);
+    public static final Interpolator AGGRESSIVE_EASE_IN_OUT = new PathInterpolator(0.6f,0, 0.4f, 1);
 
-    public static final Interpolator APP_CLOSE_ALPHA = new PathInterpolator(0.9f, 0, 1f, 1f);
+    public static final Interpolator EXAGGERATED_EASE;
 
-    public static final Interpolator OVERSHOOT_0 = new OvershootInterpolator(0);
+    private static final int MIN_SETTLE_DURATION = 200;
+    private static final float OVERSHOOT_FACTOR = 0.9f;
+
+    static {
+        Path exaggeratedEase = new Path();
+        exaggeratedEase.moveTo(0, 0);
+        exaggeratedEase.cubicTo(0.05f, 0f, 0.133333f, 0.08f, 0.166666f, 0.4f);
+        exaggeratedEase.cubicTo(0.225f, 0.94f, 0.5f, 1f, 1f, 1f);
+        EXAGGERATED_EASE = new PathInterpolator(exaggeratedEase);
+    }
+
+    public static final Interpolator OVERSHOOT_1_2 = new OvershootInterpolator(1.2f);
 
     public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
 
     /**
-     * Inversion of zInterpolate, compounded with an ease-out.
+     * Inversion of ZOOM_OUT, compounded with an ease-out.
      */
     public static final Interpolator ZOOM_IN = new Interpolator() {
+        @Override
+        public float getInterpolation(float v) {
+            return DEACCEL_3.getInterpolation(1 - ZOOM_OUT.getInterpolation(1 - v));
+        }
+    };
+
+    public static final Interpolator ZOOM_OUT = new Interpolator() {
 
         private static final float FOCAL_LENGTH = 0.35f;
 
         @Override
         public float getInterpolation(float v) {
-            return DEACCEL_3.getInterpolation(1 - zInterpolate(1 - v));
+            return zInterpolate(v);
         }
 
         /**
@@ -98,4 +125,113 @@
     public static Interpolator scrollInterpolatorForVelocity(float velocity) {
         return Math.abs(velocity) > FAST_FLING_PX_MS ? SCROLL : SCROLL_CUBIC;
     }
-}
\ No newline at end of file
+
+    /**
+     * Create an OvershootInterpolator with tension directly related to the velocity (in px/ms).
+     * @param velocity The start velocity of the animation we want to overshoot.
+     */
+    public static Interpolator overshootInterpolatorForVelocity(float velocity) {
+        return new OvershootInterpolator(Math.min(Math.abs(velocity), 3f));
+    }
+
+    /**
+     * Runs the given interpolator such that the entire progress is set between the given bounds.
+     * That is, we set the interpolation to 0 until lowerBound and reach 1 by upperBound.
+     */
+    public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
+            float upperBound) {
+        if (upperBound <= lowerBound) {
+            throw new IllegalArgumentException("lowerBound must be less than upperBound");
+        }
+        return t -> {
+            if (t < lowerBound) {
+                return 0;
+            }
+            if (t > upperBound) {
+                return 1;
+            }
+            return interpolator.getInterpolation((t - lowerBound) / (upperBound - lowerBound));
+        };
+    }
+
+    /**
+     * Runs the given interpolator such that the interpolated value is mapped to the given range.
+     * This is useful, for example, if we only use this interpolator for part of the animation,
+     * such as to take over a user-controlled animation when they let go.
+     */
+    public static Interpolator mapToProgress(Interpolator interpolator, float lowerBound,
+            float upperBound) {
+        return t -> Utilities.mapRange(interpolator.getInterpolation(t), lowerBound, upperBound);
+    }
+
+    /**
+     * Computes parameters necessary for an overshoot effect.
+     */
+    public static class OvershootParams {
+        public Interpolator interpolator;
+        public float start;
+        public float end;
+        public long duration;
+
+        /**
+         * Given the input params, sets OvershootParams variables to be used by the caller.
+         * @param startProgress The progress from 0 to 1 that the overshoot starts from.
+         * @param overshootPastProgress The progress from 0 to 1 where we overshoot past (should
+         *        either be equal to startProgress or endProgress, depending on if we want to
+         *        overshoot immediately or only once we reach the end).
+         * @param endProgress The final progress from 0 to 1 that we will settle to.
+         * @param velocityPxPerMs The initial velocity that causes this overshoot.
+         * @param totalDistancePx The distance against which progress is calculated.
+         */
+        public OvershootParams(float startProgress, float overshootPastProgress,
+                float endProgress, float velocityPxPerMs, int totalDistancePx) {
+            velocityPxPerMs = Math.abs(velocityPxPerMs);
+            start = startProgress;
+            int startPx = (int) (start * totalDistancePx);
+            // Overshoot by about half a frame.
+            float overshootBy = OVERSHOOT_FACTOR * velocityPxPerMs *
+                    SINGLE_FRAME_MS / totalDistancePx / 2;
+            overshootBy = Utilities.boundToRange(overshootBy, 0.02f, 0.15f);
+            end = overshootPastProgress + overshootBy;
+            int endPx = (int) (end  * totalDistancePx);
+            int overshootDistance = endPx - startPx;
+            // Calculate deceleration necessary to reach overshoot distance.
+            // Formula: velocityFinal^2 = velocityInitial^2 + 2 * acceleration * distance
+            //          0 = v^2 + 2ad (velocityFinal == 0)
+            //          a = v^2 / -2d
+            float decelerationPxPerMs = velocityPxPerMs * velocityPxPerMs / (2 * overshootDistance);
+            // Calculate time necessary to reach peak of overshoot.
+            // Formula: acceleration = velocity / time
+            //          time = velocity / acceleration
+            duration = (long) (velocityPxPerMs / decelerationPxPerMs);
+
+            // Now that we're at the top of the overshoot, need to settle back to endProgress.
+            float settleDistance = end - endProgress;
+            int settleDistancePx = (int) (settleDistance * totalDistancePx);
+            // Calculate time necessary for the settle.
+            // Formula: distance = velocityInitial * time + 1/2 * acceleration * time^2
+            //          d = 1/2at^2 (velocityInitial = 0, since we just stopped at the top)
+            //          t = sqrt(2d/a)
+            // Above formula assumes constant acceleration. Since we use ACCEL_DEACCEL, we actually
+            // have acceleration to halfway then deceleration the rest. So the formula becomes:
+            //          t = sqrt(d/a) * 2 (half the distance for accel, half for deaccel)
+            long settleDuration = (long) Math.sqrt(settleDistancePx / decelerationPxPerMs) * 4;
+
+            settleDuration = Math.max(MIN_SETTLE_DURATION, settleDuration);
+            // How much of the animation to devote to playing the overshoot (the rest is for settle).
+            float overshootFraction = (float) duration / (duration + settleDuration);
+            duration += settleDuration;
+            // Finally, create the interpolator, composed of two interpolators: an overshoot, which
+            // reaches end > 1, and then a settle to endProgress.
+            Interpolator overshoot = Interpolators.clampToProgress(DEACCEL, 0, overshootFraction);
+            // The settle starts at 1, where 1 is the top of the overshoot, and maps to a fraction
+            // such that final progress is endProgress. For example, if we overshot to 1.1 but want
+            // to end at 1, we need to map to 1/1.1.
+            Interpolator settle = Interpolators.clampToProgress(Interpolators.mapToProgress(
+                    ACCEL_DEACCEL, 1, (endProgress - start) / (end - start)), overshootFraction, 1);
+            interpolator = t -> t <= overshootFraction
+                    ? overshoot.getInterpolation(t)
+                    : settle.getInterpolation(t);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
new file mode 100644
index 0000000..757edff
--- /dev/null
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 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.anim;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Utility class for setting a property with or without animation
+ */
+public class PropertySetter {
+
+    public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
+
+    public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+        if (view != null) {
+            view.setAlpha(alpha);
+            AlphaUpdateListener.updateVisibility(view);
+        }
+    }
+
+    public <T> void setFloat(T target, Property<T, Float> property, float value,
+            TimeInterpolator interpolator) {
+        property.set(target, value);
+    }
+
+    public <T> void setInt(T target, Property<T, Integer> property, int value,
+            TimeInterpolator interpolator) {
+        property.set(target, value);
+    }
+
+    public static class AnimatedPropertySetter extends PropertySetter {
+
+        private final long mDuration;
+        private final AnimatorSetBuilder mStateAnimator;
+
+        public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
+            mDuration = duration;
+            mStateAnimator = builder;
+        }
+
+        @Override
+        public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+            if (view == null || view.getAlpha() == alpha) {
+                return;
+            }
+            ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
+            anim.addListener(new AlphaUpdateListener(view));
+            anim.setDuration(mDuration).setInterpolator(interpolator);
+            mStateAnimator.play(anim);
+        }
+
+        @Override
+        public <T> void setFloat(T target, Property<T, Float> property, float value,
+                TimeInterpolator interpolator) {
+            if (property.get(target) == value) {
+                return;
+            }
+            Animator anim = ObjectAnimator.ofFloat(target, property, value);
+            anim.setDuration(mDuration).setInterpolator(interpolator);
+            mStateAnimator.play(anim);
+        }
+
+        @Override
+        public <T> void setInt(T target, Property<T, Integer> property, int value,
+                TimeInterpolator interpolator) {
+            if (property.get(target) == value) {
+                return;
+            }
+            Animator anim = ObjectAnimator.ofInt(target, property, value);
+            anim.setDuration(mDuration).setInterpolator(interpolator);
+            mStateAnimator.play(anim);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/anim/SpringAnimationHandler.java b/src/com/android/launcher3/anim/SpringAnimationHandler.java
deleted file mode 100644
index 29a2430..0000000
--- a/src/com/android/launcher3/anim/SpringAnimationHandler.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.anim;
-
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.IntDef;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-
-import com.android.launcher3.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Handler class that manages springs for a set of views that should all move based on the same
- * {@link MotionEvent}s.
- *
- * Supports setting either X or Y velocity on the list of springs added to this handler.
- */
-public class SpringAnimationHandler<T> {
-
-    private static final String TAG = "SpringAnimationHandler";
-    private static final boolean DEBUG = false;
-
-    private static final float VELOCITY_DAMPING_FACTOR = 0.175f;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Y_DIRECTION, X_DIRECTION})
-    public @interface Direction {}
-    public static final int Y_DIRECTION = 0;
-    public static final int X_DIRECTION = 1;
-    private int mVelocityDirection;
-
-    private VelocityTracker mVelocityTracker;
-    private float mCurrentVelocity = 0;
-    private boolean mShouldComputeVelocity = false;
-
-    private AnimationFactory<T> mAnimationFactory;
-
-    private ArrayList<SpringAnimation> mAnimations = new ArrayList<>();
-
-    /**
-     * @param direction Either {@link #X_DIRECTION} or {@link #Y_DIRECTION}.
-     *                  Determines which direction we use to calculate and set the velocity.
-     * @param factory   The AnimationFactory is responsible for initializing and updating the
-     *                  SpringAnimations added to this class.
-     */
-    public SpringAnimationHandler(@Direction int direction, AnimationFactory<T> factory) {
-        mVelocityDirection = direction;
-        mAnimationFactory = factory;
-    }
-
-    /**
-     * Adds a spring to the list of springs handled by this class.
-     * @param spring The new spring to be added.
-     * @param setDefaultValues If True, sets the spring to the default
-     *                         {@link AnimationFactory} values.
-     */
-    public void add(SpringAnimation spring, boolean setDefaultValues) {
-        if (setDefaultValues) {
-            mAnimationFactory.setDefaultValues(spring);
-        }
-        spring.setStartVelocity(mCurrentVelocity);
-        mAnimations.add(spring);
-    }
-
-    public AnimationFactory<T> getFactory() {
-        return mAnimationFactory;
-    }
-
-    /**
-     * Adds a new or recycled animation to the list of springs handled by this class.
-     *
-     * @param view The view the spring is attached to.
-     * @param object Used to initialize and update the spring.
-     */
-    public void add(View view, T object) {
-        SpringAnimation spring = (SpringAnimation) view.getTag(R.id.spring_animation_tag);
-        if (spring == null) {
-            spring = mAnimationFactory.initialize(object);
-            view.setTag(R.id.spring_animation_tag, spring);
-        }
-        mAnimationFactory.update(spring, object);
-        add(spring, false /* setDefaultValues */);
-    }
-
-    /**
-     * Stops and removes the spring attached to {@param view}.
-     */
-    public void remove(View view) {
-        remove((SpringAnimation) view.getTag(R.id.spring_animation_tag));
-    }
-
-    public void remove(SpringAnimation animation) {
-        if (animation.canSkipToEnd()) {
-            animation.skipToEnd();
-        }
-        mAnimations.remove(animation);
-    }
-
-    public void addMovement(MotionEvent event) {
-        int action = event.getActionMasked();
-        if (DEBUG) Log.d(TAG, "addMovement#action=" + action);
-        switch (action) {
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_DOWN:
-                reset();
-                break;
-        }
-
-        getVelocityTracker().addMovement(event);
-        mShouldComputeVelocity = true;
-    }
-
-    public void animateToFinalPosition(float position, int startValue) {
-        animateToFinalPosition(position, startValue, mShouldComputeVelocity);
-    }
-
-    /**
-     * @param position The final animation position.
-     * @param startValue < 0 if scrolling from start to end; > 0 if scrolling from end to start
-     *                   The magnitude of the number changes how the spring will move.
-     * @param setVelocity If true, we set the velocity to {@link #mCurrentVelocity} before
-     *                    starting the animation.
-     */
-    private void animateToFinalPosition(float position, int startValue, boolean setVelocity) {
-        if (DEBUG) {
-            Log.d(TAG, "animateToFinalPosition#position=" + position + ", startValue=" + startValue);
-        }
-
-        if (mShouldComputeVelocity) {
-            mCurrentVelocity = computeVelocity();
-        }
-
-        int size = mAnimations.size();
-        for (int i = 0; i < size; ++i) {
-            mAnimations.get(i).setStartValue(startValue);
-            if (setVelocity) {
-                mAnimations.get(i).setStartVelocity(mCurrentVelocity);
-            }
-            mAnimations.get(i).animateToFinalPosition(position);
-        }
-
-        reset();
-    }
-
-    /**
-     * Similar to {@link #animateToFinalPosition(float, int)}, but used in cases where we want to
-     * manually set the velocity.
-     */
-    public void animateToPositionWithVelocity(float position, int startValue, float velocity) {
-        if (DEBUG) {
-            Log.d(TAG, "animateToPosition#pos=" + position + ", start=" + startValue
-                    + ", velocity=" + velocity);
-        }
-
-        mCurrentVelocity = velocity;
-        mShouldComputeVelocity = false;
-        animateToFinalPosition(position, startValue, true);
-    }
-
-
-    public boolean isRunning() {
-        // All the animations run at the same time so we can just check the first one.
-        return !mAnimations.isEmpty() && mAnimations.get(0).isRunning();
-    }
-
-    public void skipToEnd() {
-        if (DEBUG) Log.d(TAG, "setStartVelocity#skipToEnd");
-        if (DEBUG) Log.v(TAG, "setStartVelocity#skipToEnd", new Exception());
-
-        int size = mAnimations.size();
-        for (int i = 0; i < size; ++i) {
-            if (mAnimations.get(i).canSkipToEnd()) {
-                mAnimations.get(i).skipToEnd();
-            }
-        }
-    }
-
-    public void reset() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-        mCurrentVelocity = 0;
-        mShouldComputeVelocity = false;
-    }
-
-
-    private float computeVelocity() {
-        getVelocityTracker().computeCurrentVelocity(1000 /* millis */);
-
-        float velocity = isVerticalDirection()
-                ? getVelocityTracker().getYVelocity()
-                : getVelocityTracker().getXVelocity();
-        velocity *= VELOCITY_DAMPING_FACTOR;
-
-        if (DEBUG) Log.d(TAG, "computeVelocity=" + velocity);
-        return velocity;
-    }
-
-    private boolean isVerticalDirection() {
-        return mVelocityDirection == Y_DIRECTION;
-    }
-
-    private VelocityTracker getVelocityTracker() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        return mVelocityTracker;
-    }
-
-    /**
-     * This interface is used to initialize and update the SpringAnimations added to the
-     * {@link SpringAnimationHandler}.
-     *
-     * @param <T> The object that each SpringAnimation is attached to.
-     */
-    public interface AnimationFactory<T> {
-
-        /**
-         * Initializes a new Spring for {@param object}.
-         */
-        SpringAnimation initialize(T object);
-
-        /**
-         * Updates the value of {@param spring} based on {@param object}.
-         */
-        void update(SpringAnimation spring, T object);
-
-        /**
-         * Sets the factory default values for the given {@param spring}.
-         */
-        void setDefaultValues(SpringAnimation spring);
-    }
-
-    /**
-     * Helper method to create a new SpringAnimation for {@param view}.
-     */
-    public static SpringAnimation forView(View view, FloatPropertyCompat property, float finalPos) {
-        SpringAnimation spring = new SpringAnimation(view, property, finalPos);
-        spring.setSpring(new SpringForce(finalPos));
-        return spring;
-    }
-
-}
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index 72d49f0..9487427 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -80,7 +80,7 @@
             Log.e(TAG, "Invalid null argument(s) passed in call to draw.");
             return;
         }
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.save();
         // We draw the badge relative to its center.
         float badgeCenterX = iconBounds.right - mDotCenterOffset / 2;
         float badgeCenterY = iconBounds.top + mDotCenterOffset / 2;
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 0c78381..29fc2bc 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -16,11 +16,14 @@
 
 package com.android.launcher3.compat;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.launcher3.Utilities;
+
 public class AccessibilityManagerCompat {
 
     public static boolean isAccessibilityEnabled(Context context) {
@@ -44,4 +47,19 @@
     private static AccessibilityManager getManager(Context context) {
         return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
     }
+
+    public static void sendEventToTest(Context context, String eventTag) {
+        if (!Utilities.IS_RUNNING_IN_TEST_HARNESS) return;
+
+        final AccessibilityManager accessibilityManager = getManager(context);
+        if (accessibilityManager.isEnabled() &&
+                accessibilityManager.getEnabledAccessibilityServiceList(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK).size() == 0) {
+
+            final AccessibilityEvent e = AccessibilityEvent.obtain(
+                    AccessibilityEvent.TYPE_ANNOUNCEMENT);
+            e.setClassName(eventTag);
+            accessibilityManager.sendAccessibilityEvent(e);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 112cca5..3270ba2 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -45,7 +45,7 @@
     /**
      * @return a map of active installs to their progress
      */
-    public abstract HashMap<String, Integer> updateAndGetActiveSessionCache();
+    public abstract HashMap<String, PackageInstaller.SessionInfo> updateAndGetActiveSessionCache();
 
     public abstract void onStop();
 
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 1ffd3da..dd17916 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -59,13 +59,13 @@
     }
 
     @Override
-    public HashMap<String, Integer> updateAndGetActiveSessionCache() {
-        HashMap<String, Integer> activePackages = new HashMap<>();
+    public HashMap<String, SessionInfo> updateAndGetActiveSessionCache() {
+        HashMap<String, SessionInfo> activePackages = new HashMap<>();
         UserHandle user = Process.myUserHandle();
         for (SessionInfo info : getAllVerifiedSessions()) {
             addSessionInfoToCache(info, user);
             if (info.getAppPackageName() != null) {
-                activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
+                activePackages.put(info.getAppPackageName(), info);
                 mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
             }
         }
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 62055dc..ad51477 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -58,11 +58,12 @@
     public abstract long getSerialNumberForUser(UserHandle user);
     public abstract UserHandle getUserForSerialNumber(long serialNumber);
     public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user);
-    public abstract long getUserCreationTime(UserHandle user);
     public abstract boolean isQuietModeEnabled(UserHandle user);
     public abstract boolean isUserUnlocked(UserHandle user);
 
     public abstract boolean isDemoUser();
     public abstract boolean requestQuietModeEnabled(boolean enableQuietMode, UserHandle user);
     public abstract boolean isAnyProfileQuietModeEnabled();
+
+    public abstract boolean hasWorkProfile();
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index e57786d..eec3438 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -23,7 +23,6 @@
 import android.os.UserManager;
 import android.util.ArrayMap;
 import com.android.launcher3.util.LongArrayMap;
-import com.android.launcher3.util.ManagedProfileHeuristic;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -121,21 +120,21 @@
     }
 
     @Override
+    public boolean hasWorkProfile() {
+        synchronized (this) {
+            if (mUsers != null) {
+                return mUsers.size() > 1;
+            }
+        }
+        return getUserProfiles().size() > 1;
+    }
+
+    @Override
     public CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user) {
         if (user == null) {
             return label;
         }
         return mPm.getUserBadgedLabel(label, user);
     }
-
-    @Override
-    public long getUserCreationTime(UserHandle user) {
-        SharedPreferences prefs = ManagedProfileHeuristic.prefs(mContext);
-        String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user);
-        if (!prefs.contains(key)) {
-            prefs.edit().putLong(key, System.currentTimeMillis()).apply();
-        }
-        return prefs.getLong(key, 0);
-    }
 }
 
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVM.java b/src/com/android/launcher3/compat/UserManagerCompatVM.java
index 75c1877..cf74b37 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVM.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVM.java
@@ -27,9 +27,4 @@
     UserManagerCompatVM(Context context) {
         super(context);
     }
-
-    @Override
-    public long getUserCreationTime(UserHandle user) {
-        return mUserManager.getUserCreationTime(user);
-    }
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVP.java b/src/com/android/launcher3/compat/UserManagerCompatVP.java
index 2e8a8eb..fa3902b 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVP.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVP.java
@@ -15,41 +15,20 @@
  */
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
+@TargetApi(Build.VERSION_CODES.P)
 public class UserManagerCompatVP extends UserManagerCompatVNMr1 {
-    private static final String TAG = "UserManagerCompatVP";
-
-    private Method mRequestQuietModeEnabled;
 
     UserManagerCompatVP(Context context) {
         super(context);
-        // TODO: Replace it with proper API call once SDK is ready.
-        try {
-            mRequestQuietModeEnabled = UserManager.class.getDeclaredMethod(
-                    "requestQuietModeEnabled", boolean.class, UserHandle.class);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "requestQuietModeEnabled is not available", e);
-        }
     }
 
     @Override
     public boolean requestQuietModeEnabled(boolean enableQuietMode, UserHandle user) {
-        if (mRequestQuietModeEnabled == null) {
-            return false;
-        }
-        try {
-            return (boolean)
-                    mRequestQuietModeEnabled.invoke(mUserManager, enableQuietMode, user);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            Log.e(TAG, "Failed to invoke mRequestQuietModeEnabled", e);
-        }
-        return false;
+        return mUserManager.requestQuietModeEnabled(enableQuietMode, user);
     }
 }
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index e494bea..f4c6380 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -35,8 +35,6 @@
     public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
     // When enabled the promise icon is visible in all apps while installation an app.
     public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
-    // When enabled allows use of physics based motions in the Launcher.
-    public static final boolean LAUNCHER3_PHYSICS = true;
     // When enabled allows use of spring motions on the icons.
     public static final boolean LAUNCHER3_SPRING_ICONS = true;
 
@@ -54,5 +52,7 @@
     // When enabled shows a work profile tab in all apps
     public static final boolean ALL_APPS_TABS_ENABLED = true;
 
-    public static final boolean ENABLE_TWO_SWIPE_TARGETS = true;
+    // When true, overview shows screenshots in the orientation they were taken rather than
+    // trying to make them fit the orientation the device is in.
+    public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
 }
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index db199c1..278eefd 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -16,6 +16,11 @@
 
 package com.android.launcher3.dragndrop;
 
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+
 import android.annotation.TargetApi;
 import android.app.ActivityOptions;
 import android.appwidget.AppWidgetManager;
@@ -23,7 +28,6 @@
 import android.content.ClipDescription;
 import android.content.Intent;
 import android.content.pm.LauncherApps.PinItemRequest;
-import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -43,23 +47,18 @@
 import com.android.launcher3.LauncherAppWidgetHost;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherAppsCompatVO;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.WidgetHostViewLoader;
 import com.android.launcher3.widget.WidgetImageView;
 
-import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-
 @TargetApi(Build.VERSION_CODES.O)
 public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
 
@@ -84,6 +83,7 @@
     private Bundle mWidgetOptions;
 
     private boolean mFinishOnPause = false;
+    private InstantAppResolver mInstantAppResolver;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -97,6 +97,7 @@
 
         mApp = LauncherAppState.getInstance(this);
         mIdp = mApp.getInvariantDeviceProfile();
+        mInstantAppResolver = InstantAppResolver.newInstance(this);
 
         // Use the application context to get the device profile, as in multiwindow-mode, the
         // confirmation activity might be rotated.
@@ -154,15 +155,7 @@
                         .setPackage(getPackageName())
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
 
-        if (!getResources().getBoolean(R.bool.allow_rotation) &&
-                !Utilities.isAllowRotationPrefEnabled(this) &&
-                (getResources().getConfiguration().orientation ==
-                        Configuration.ORIENTATION_LANDSCAPE && !isInMultiWindowMode())) {
-            // If we are starting the drag in landscape even though home is locked in portrait,
-            // restart the home activity to temporarily allow rotation.
-            homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        }
-
+        listener.initWhenReady();
         startActivity(homeIntent,
                 ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out).toBundle());
         mFinishOnPause = true;
@@ -308,7 +301,7 @@
     private void logCommand(int command) {
         getUserEventDispatcher().dispatchUserEvent(newLauncherEvent(
                 newCommandAction(command),
-                newItemTarget(mWidgetCell.getWidgetView()),
+                newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver),
                 newContainerTarget(ContainerType.PINITEM)), null);
     }
 }
diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
index 9638a75..e204c63 100644
--- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java
@@ -17,6 +17,8 @@
 package com.android.launcher3.dragndrop;
 
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
+import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
 
 import android.content.ClipDescription;
 import android.content.Intent;
@@ -79,6 +81,7 @@
         AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
         launcher.getStateManager().goToState(NORMAL, alreadyOnHome /* animated */);
         launcher.getDragLayer().setOnDragListener(this);
+        launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
 
         mLauncher = launcher;
         mDragController = launcher.getDragController();
@@ -103,6 +106,10 @@
     }
 
     protected boolean onDragStart(DragEvent event) {
+        return onDragStart(event, this);
+    }
+
+    protected boolean onDragStart(DragEvent event, DragOptions.PreDragCondition preDragCondition) {
         ClipDescription desc =  event.getClipDescription();
         if (desc == null || !desc.hasMimeType(getMimeType())) {
             Log.e(TAG, "Someone started a dragAndDrop before us.");
@@ -112,7 +119,7 @@
         Point downPos = new Point((int) event.getX(), (int) event.getY());
         DragOptions options = new DragOptions();
         options.systemDndStartPoint = downPos;
-        options.preDragCondition = this;
+        options.preDragCondition = preDragCondition;
 
         // We use drag event position as the screenPos for the preview image. Since mPreviewRect
         // already includes the view position relative to the drag event on the source window,
@@ -120,7 +127,7 @@
         // across windows, using drag position here give a good estimate for relative position
         // to source window.
         createDragHelper().startDrag(new Rect(mPreviewRect),
-                mPreviewBitmapWidth, mPreviewViewWidth, downPos,  this, options);
+                mPreviewBitmapWidth, mPreviewViewWidth, downPos, this, options);
         mDragStartTime = SystemClock.uptimeMillis();
         return true;
     }
@@ -156,7 +163,8 @@
         postCleanup();
     }
 
-    private void postCleanup() {
+    protected void postCleanup() {
+        clearReference();
         if (mLauncher != null) {
             // Remove any drag params from the launcher intent since the drag operation is complete.
             Intent newIntent = new Intent(mLauncher.getIntent());
@@ -164,16 +172,12 @@
             mLauncher.setIntent(newIntent);
         }
 
-        new Handler(Looper.getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                removeListener();
-            }
-        });
+        new Handler(Looper.getMainLooper()).post(this::removeListener);
     }
 
     public void removeListener() {
         if (mLauncher != null) {
+            mLauncher.getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
             mLauncher.getDragLayer().setOnDragListener(null);
         }
     }
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 818cea7..47bbbcb 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.dragndrop;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherState.NORMAL;
 
@@ -31,6 +32,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
@@ -138,13 +140,14 @@
      */
     public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
             DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
-            float initialDragViewScale, DragOptions options) {
+            float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
         }
 
         // Hide soft keyboard, if visible
         UiThreadHelper.hideKeyboardAsync(mLauncher, mWindowToken);
+        AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
 
         mOptions = options;
         if (mOptions.systemDndStartPoint != null) {
@@ -169,7 +172,7 @@
         final float scaleDps = mIsInPreDrag
                 ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
         final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
-                registrationY, initialDragViewScale, scaleDps);
+                registrationY, initialDragViewScale, dragViewScaleOnDrop, scaleDps);
         dragView.setItemInfo(dragInfo);
         mDragObject.dragComplete = false;
         if (mOptions.isAccessibleDrag) {
@@ -583,6 +586,12 @@
         }
 
         mDragObject.dragComplete = true;
+        if (mIsInPreDrag) {
+            if (dropTarget != null) {
+                dropTarget.onDragExit(mDragObject);
+            }
+            return;
+        }
 
         // Drop onto the target.
         boolean accepted = false;
@@ -591,17 +600,15 @@
             if (dropTarget.acceptDrop(mDragObject)) {
                 if (flingAnimation != null) {
                     flingAnimation.run();
-                } else if (!mIsInPreDrag) {
+                } else {
                     dropTarget.onDrop(mDragObject, mOptions);
                 }
                 accepted = true;
             }
         }
         final View dropTargetAsView = dropTarget instanceof View ? (View) dropTarget : null;
-        if (!mIsInPreDrag) {
-            mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
-            dispatchDropComplete(dropTargetAsView, accepted);
-        }
+        mLauncher.getUserEventDispatcher().logDragNDrop(mDragObject, dropTargetAsView);
+        dispatchDropComplete(dropTargetAsView, accepted);
     }
 
     private DropTarget findDropTarget(int x, int y, int[] dropCoordinates) {
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 1cf407e..6d2d3cb 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2008 The Android Open Source Project
  *
@@ -27,50 +28,50 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DropTargetBar;
-import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
-import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.ViewScrim;
+import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.Thunk;
-import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
 
 /**
  * A ViewGroup that coordinates dragging across its descendants
  */
-public class DragLayer extends InsettableFrameLayout {
+public class DragLayer extends BaseDragLayer<Launcher> {
+
+    public static final int ALPHA_INDEX_OVERLAY = 0;
+    public static final int ALPHA_INDEX_LAUNCHER_LOAD = 1;
+    public static final int ALPHA_INDEX_TRANSITIONS = 2;
+    public static final int ALPHA_INDEX_SWIPE_UP = 3;
+    private static final int ALPHA_CHANNEL_COUNT = 4;
 
     public static final int ANIMATION_END_DISAPPEAR = 0;
     public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
 
-    private final int[] mTmpXY = new int[2];
-
     @Thunk DragController mDragController;
 
-    private Launcher mLauncher;
-
     // Variables relating to animation of views after drop
     private ValueAnimator mDropAnim = null;
     private final TimeInterpolator mCubicEaseOutInterpolator = Interpolators.DEACCEL_1_5;
@@ -79,19 +80,14 @@
     @Thunk View mAnchorView = null;
 
     private boolean mHoverPointClosesFolder = false;
-    private final Rect mHitRect = new Rect();
-
-    private TouchCompleteListener mTouchCompleteListener;
 
     private int mTopViewIndex;
     private int mChildCountOnLastUpdate = -1;
 
     // Related to adjacent page hints
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
-    private final PageCutOutScrimDrawable mPageCutOutScrim;
+    private final WorkspaceAndHotseatScrim mScrim;
 
-    protected TouchController[] mControllers;
-    private TouchController mActiveController;
     /**
      * Used to create a new DragLayer from XML.
      *
@@ -99,21 +95,24 @@
      * @param attrs The attributes set containing the Workspace's customization values.
      */
     public DragLayer(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        super(context, attrs, ALPHA_CHANNEL_COUNT);
 
         // Disable multitouch across the workspace/all apps/customize tray
         setMotionEventSplittingEnabled(false);
         setChildrenDrawingOrderEnabled(true);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mPageCutOutScrim = new PageCutOutScrimDrawable(this);
-        mPageCutOutScrim.setCallback(this);
+        mScrim = new WorkspaceAndHotseatScrim(this);
     }
 
-    public void setup(Launcher launcher, DragController dragController) {
-        mLauncher = launcher;
+    public void setup(DragController dragController, Workspace workspace) {
         mDragController = dragController;
-        mControllers = UiFactory.createTouchControllers(mLauncher);
+        mScrim.setWorkspace(workspace);
+        recreateControllers();
+    }
+
+    public void recreateControllers() {
+        mControllers = UiFactory.createTouchControllers(mActivity);
     }
 
     public ViewGroupFocusHelper getFocusIndicatorHelper() {
@@ -126,83 +125,47 @@
     }
 
     @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mPageCutOutScrim;
-    }
-
-    public boolean isEventOverHotseat(MotionEvent ev) {
-        return isEventOverView(mLauncher.getHotseat(), ev);
-    }
-
-    private boolean isEventOverFolder(Folder folder, MotionEvent ev) {
-        return isEventOverView(folder, ev);
-    }
-
-    private boolean isEventOverDropTargetBar(MotionEvent ev) {
-        return isEventOverView(mLauncher.getDropTargetBar(), ev);
-    }
-
-    public boolean isEventOverView(View view, MotionEvent ev) {
-        getDescendantRectRelativeToSelf(view, mHitRect);
-        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        ViewScrim scrim = ViewScrim.get(child);
+        if (scrim != null) {
+            scrim.draw(canvas, getWidth(), getHeight());
+        }
+        return super.drawChild(canvas, child, drawingTime);
     }
 
     @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        int action = ev.getAction();
-
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            if (mTouchCompleteListener != null) {
-                mTouchCompleteListener.onTouchComplete();
-            }
-            mTouchCompleteListener = null;
-        } else if (action == MotionEvent.ACTION_DOWN) {
-            mLauncher.finishAutoCancelActionMode();
+    protected boolean findActiveController(MotionEvent ev) {
+        if (mActivity.getStateManager().getState().disableInteraction) {
+            // You Shall Not Pass!!!
+            mActiveController = null;
+            return true;
         }
-        return findActiveController(ev);
+        return super.findActiveController(ev);
     }
 
-    private boolean findActiveController(MotionEvent ev) {
-        mActiveController = null;
-
-        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
-            mActiveController = topView;
-            return true;
-        }
-
-        if (mDragController.onControllerInterceptTouchEvent(ev)) {
-            mActiveController = mDragController;
-            return true;
-        }
-
-        for (TouchController controller : mControllers) {
-            if (controller.onControllerInterceptTouchEvent(ev)) {
-                mActiveController = controller;
-                return true;
-            }
-        }
-        return false;
+    private boolean isEventOverAccessibleDropTargetBar(MotionEvent ev) {
+        return isInAccessibleDrag() && isEventOverView(mActivity.getDropTargetBar(), ev);
     }
 
     @Override
     public boolean onInterceptHoverEvent(MotionEvent ev) {
-        if (mLauncher == null || mLauncher.getWorkspace() == null) {
+        if (mActivity == null || mActivity.getWorkspace() == null) {
             return false;
         }
-        Folder currentFolder = Folder.getOpen(mLauncher);
-        if (currentFolder == null) {
+        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+        if (!(topView instanceof Folder)) {
             return false;
         } else {
-                AccessibilityManager accessibilityManager = (AccessibilityManager)
-                        getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
+            AccessibilityManager accessibilityManager = (AccessibilityManager)
+                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
             if (accessibilityManager.isTouchExplorationEnabled()) {
+                Folder currentFolder = (Folder) topView;
                 final int action = ev.getAction();
                 boolean isOverFolderOrSearchBar;
                 switch (action) {
                     case MotionEvent.ACTION_HOVER_ENTER:
-                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
-                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+                        isOverFolderOrSearchBar = isEventOverView(topView, ev) ||
+                                isEventOverAccessibleDropTargetBar(ev);
                         if (!isOverFolderOrSearchBar) {
                             sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
                             mHoverPointClosesFolder = true;
@@ -211,8 +174,8 @@
                         mHoverPointClosesFolder = false;
                         break;
                     case MotionEvent.ACTION_HOVER_MOVE:
-                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
-                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+                        isOverFolderOrSearchBar = isEventOverView(topView, ev) ||
+                                isEventOverAccessibleDropTargetBar(ev);
                         if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
                             sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
                             mHoverPointClosesFolder = true;
@@ -233,43 +196,6 @@
                 this, AccessibilityEvent.TYPE_VIEW_FOCUSED, getContext().getString(stringId));
     }
 
-    private boolean isInAccessibleDrag() {
-        return mLauncher.getAccessibilityDelegate().isInAccessibleDrag();
-    }
-
-    @Override
-    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
-        // Shortcuts can appear above folder
-        View topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null) {
-            if (child == topView) {
-                return super.onRequestSendAccessibilityEvent(child, event);
-            }
-            if (isInAccessibleDrag() && child instanceof DropTargetBar) {
-                return super.onRequestSendAccessibilityEvent(child, event);
-            }
-            // Skip propagating onRequestSendAccessibilityEvent for all other children
-            // which are not topView
-            return false;
-        }
-        return super.onRequestSendAccessibilityEvent(child, event);
-    }
-
-    @Override
-    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
-        View topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null) {
-            // Only add the top view as a child for accessibility when it is open
-            childrenForAccessibility.add(topView);
-
-            if (isInAccessibleDrag()) {
-                childrenForAccessibility.add(mLauncher.getDropTargetBar());
-            }
-        } else {
-            super.addChildrenForAccessibility(childrenForAccessibility);
-        }
-    }
-
     @Override
     public boolean onHoverEvent(MotionEvent ev) {
         // If we've received this, we've already done the necessary handling
@@ -277,97 +203,37 @@
         return false;
     }
 
+
+    private boolean isInAccessibleDrag() {
+        return mActivity.getAccessibilityDelegate().isInAccessibleDrag();
+    }
+
     @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        int action = ev.getAction();
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            if (mTouchCompleteListener != null) {
-                mTouchCompleteListener.onTouchComplete();
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (isInAccessibleDrag() && child instanceof DropTargetBar) {
+            return true;
+        }
+        return super.onRequestSendAccessibilityEvent(child, event);
+    }
+
+    @Override
+    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
+        View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+                AbstractFloatingView.TYPE_ACCESSIBLE);
+        if (topView != null) {
+            addAccessibleChildToList(topView, childrenForAccessibility);
+            if (isInAccessibleDrag()) {
+                addAccessibleChildToList(mActivity.getDropTargetBar(), childrenForAccessibility);
             }
-            mTouchCompleteListener = null;
-        }
-
-        if (mActiveController != null) {
-            return mActiveController.onControllerTouchEvent(ev);
         } else {
-            // In case no child view handled the touch event, we may not get onIntercept anymore
-            return findActiveController(ev);
+            super.addChildrenForAccessibility(childrenForAccessibility);
         }
     }
 
-    /**
-     * Determine the rect of the descendant in this DragLayer's coordinates
-     *
-     * @param descendant The descendant whose coordinates we want to find.
-     * @param r The rect into which to place the results.
-     * @return The factor by which this descendant is scaled relative to this DragLayer.
-     */
-    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
-        mTmpXY[0] = 0;
-        mTmpXY[1] = 0;
-        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
-
-        r.set(mTmpXY[0], mTmpXY[1],
-                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
-                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
-        return scale;
-    }
-
-    public float getLocationInDragLayer(View child, int[] loc) {
-        loc[0] = 0;
-        loc[1] = 0;
-        return getDescendantCoordRelativeToSelf(child, loc);
-    }
-
-    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
-        return getDescendantCoordRelativeToSelf(descendant, coord, false);
-    }
-
-    /**
-     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
-     * coordinates.
-     *
-     * @param descendant The descendant to which the passed coordinate is relative.
-     * @param coord The coordinate that we want mapped.
-     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
-     *          sometimes this is relevant as in a child's coordinates within the root descendant.
-     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
-     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
-     *         assumption fails, we will need to return a pair of scale factors.
-     */
-    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
-            boolean includeRootScroll) {
-        return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
-                coord, includeRootScroll);
-    }
-
-    /**
-     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
-     */
-    public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
-        Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
-    }
-
-    public void getViewRectRelativeToSelf(View v, Rect r) {
-        int[] loc = new int[2];
-        getLocationInWindow(loc);
-        int x = loc[0];
-        int y = loc[1];
-
-        v.getLocationInWindow(loc);
-        int vX = loc[0];
-        int vY = loc[1];
-
-        int left = vX - x;
-        int top = vY - y;
-        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
-    }
-
     @Override
     public boolean dispatchUnhandledMove(View focused, int direction) {
-        // Consume the unhandled move if a container is open, to avoid switching pages underneath.
-        boolean isContainerOpen = AbstractFloatingView.getTopOpenView(mLauncher) != null;
-        return isContainerOpen || mDragController.dispatchUnhandledMove(focused, direction);
+        return super.dispatchUnhandledMove(focused, direction)
+                || mDragController.dispatchUnhandledMove(focused, direction);
     }
 
     @Override
@@ -380,91 +246,6 @@
         }
     }
 
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-    }
-
-    // Override to allow type-checking of LayoutParams.
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
-    }
-
-    public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
-        public int x, y;
-        public boolean customPosition = false;
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams lp) {
-            super(lp);
-        }
-
-        public void setWidth(int width) {
-            this.width = width;
-        }
-
-        public int getWidth() {
-            return width;
-        }
-
-        public void setHeight(int height) {
-            this.height = height;
-        }
-
-        public int getHeight() {
-            return height;
-        }
-
-        public void setX(int x) {
-            this.x = x;
-        }
-
-        public int getX() {
-            return x;
-        }
-
-        public void setY(int y) {
-            this.y = y;
-        }
-
-        public int getY() {
-            return y;
-        }
-    }
-
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
-            if (flp instanceof LayoutParams) {
-                final LayoutParams lp = (LayoutParams) flp;
-                if (lp.customPosition) {
-                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
-                }
-            }
-        }
-    }
-
     public void animateViewIntoPosition(DragView dragView, final int[] pos, float alpha,
             float scaleX, float scaleY, int animationEndStyle, Runnable onFinishRunnable,
             int duration) {
@@ -536,11 +317,7 @@
         final int fromX = r.left;
         final int fromY = r.top;
         child.setVisibility(INVISIBLE);
-        Runnable onCompleteRunnable = new Runnable() {
-            public void run() {
-                child.setVisibility(VISIBLE);
-            }
-        };
+        Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE);
         animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
                 onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
     }
@@ -683,6 +460,7 @@
                 case ANIMATION_END_REMAIN_VISIBLE:
                     break;
                 }
+                mDropAnim = null;
             }
         });
         mDropAnim.start();
@@ -692,6 +470,7 @@
         if (mDropAnim != null) {
             mDropAnim.cancel();
         }
+        mDropAnim = null;
         if (mDropView != null) {
             mDragController.onDeferredEndDrag(mDropView);
         }
@@ -707,12 +486,14 @@
     public void onViewAdded(View child) {
         super.onViewAdded(child);
         updateChildIndices();
+        UiFactory.onLauncherStateOrFocusChanged(mActivity);
     }
 
     @Override
     public void onViewRemoved(View child) {
         super.onViewRemoved(child);
         updateChildIndices();
+        UiFactory.onLauncherStateOrFocusChanged(mActivity);
     }
 
     @Override
@@ -758,49 +539,27 @@
         }
     }
 
-    public void invalidateScrim() {
-        if (mPageCutOutScrim.getAlpha() > 0) {
-            invalidate();
-        }
-    }
-
-    public Drawable getScrim() {
-        return mPageCutOutScrim;
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
         // Draw the background below children.
-        mPageCutOutScrim.draw(canvas);
+        mScrim.draw(canvas);
         mFocusIndicatorHelper.draw(canvas);
         super.dispatchDraw(canvas);
     }
 
     @Override
-    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        View topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null) {
-            return topView.requestFocus(direction, previouslyFocusedRect);
-        } else {
-            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
-        }
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mScrim.setSize(w, h);
     }
 
     @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        View topView = AbstractFloatingView.getTopOpenView(mLauncher);
-        if (topView != null) {
-            topView.addFocusables(views, direction);
-        } else {
-            super.addFocusables(views, direction, focusableMode);
-        }
+    public void setInsets(Rect insets) {
+        super.setInsets(insets);
+        mScrim.onInsetsChanged(insets);
     }
 
-    public void setTouchCompleteListener(TouchCompleteListener listener) {
-        mTouchCompleteListener = listener;
-    }
-
-    public interface TouchCompleteListener {
-        void onTouchComplete();
+    public WorkspaceAndHotseatScrim getScrim() {
+        return mScrim;
     }
 }
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index a59b899..551567a 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -46,6 +46,7 @@
 
 import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.ItemInfo;
+import com.android.launcher3.ItemInfoWithIcon;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherAppState;
@@ -69,6 +70,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+
 public class DragView extends View {
     private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
     private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
@@ -86,6 +89,7 @@
     private final int mRegistrationX;
     private final int mRegistrationY;
     private final float mInitialScale;
+    private final float mScaleOnDrop;
     private final int[] mTempLoc = new int[2];
 
     private Point mDragVisualizeOffset = null;
@@ -128,7 +132,7 @@
      * @param registrationY The y coordinate of the registration point.
      */
     public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
-                    final float initialScale, final float finalScaleDps) {
+                    final float initialScale, final float scaleOnDrop, final float finalScaleDps) {
         super(launcher);
         mLauncher = launcher;
         mDragLayer = launcher.getDragLayer();
@@ -177,6 +181,7 @@
         mRegistrationY = registrationY;
 
         mInitialScale = initialScale;
+        mScaleOnDrop = scaleOnDrop;
 
         // Force a measure, because Workspace uses getMeasuredHeight() before the layout pass
         int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
@@ -285,7 +290,7 @@
 
             if (mScaledMaskPath != null) {
                 mBgSpringDrawable.setColorFilter(mBaseFilter);
-                mBgSpringDrawable.setColorFilter(mBaseFilter);
+                mFgSpringDrawable.setColorFilter(mBaseFilter);
                 mBadge.setColorFilter(mBaseFilter);
             }
         } else {
@@ -364,7 +369,10 @@
     private Drawable getBadge(ItemInfo info, LauncherAppState appState, Object obj) {
         int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
         if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-            if (info.id == ItemInfo.NO_ID || !(obj instanceof ShortcutInfoCompat)) {
+            boolean iconBadged = (info instanceof ItemInfoWithIcon)
+                    && (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0;
+            if ((info.id == ItemInfo.NO_ID && !iconBadged)
+                    || !(obj instanceof ShortcutInfoCompat)) {
                 // The item is not yet added on home screen.
                 return new FixedSizeEmptyDrawable(iconSize);
             }
@@ -448,7 +456,7 @@
             canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
             if (crossFade) {
                 mPaint.setAlpha((int) (255 * mCrossFadeProgress));
-                final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+                final int saveCount = canvas.save();
                 float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth();
                 float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight();
                 canvas.scale(sX, sY);
@@ -590,7 +598,7 @@
     public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
         mTempLoc[0] = toTouchX - mRegistrationX;
         mTempLoc[1] = toTouchY - mRegistrationY;
-        mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mInitialScale, mInitialScale,
+        mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop, mScaleOnDrop,
                 DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
     }
 
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 1c6f77c..5576d91 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -36,7 +36,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.PreviewBackground;
-import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.Preconditions;
 
 /**
@@ -113,7 +113,7 @@
         final float previewShiftX = shiftFactor * previewWidth;
         final float previewShiftY = shiftFactor * previewHeight;
 
-        Bitmap previewBitmap = UiFactory.createFromRenderer(previewWidth, previewHeight, false,
+        Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(previewWidth, previewHeight,
                 (canvas) -> {
                     int count = canvas.save();
                     canvas.translate(previewShiftX, previewShiftY);
diff --git a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java b/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java
deleted file mode 100644
index 367124b..0000000
--- a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.dragndrop;
-
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
-
-import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-
-/**
- * Scrim drawable which draws a hole for the current drop target page.
- */
-public class PageCutOutScrimDrawable extends Drawable {
-
-    private final Rect mHighlightRect = new Rect();
-    private final DragLayer mDragLayer;
-    private final Launcher mLauncher;
-    private final WallpaperColorInfo mWallpaperColorInfo;
-
-    private int mAlpha = 0;
-
-    public PageCutOutScrimDrawable(DragLayer dragLayer) {
-        mDragLayer = dragLayer;
-        mLauncher = Launcher.getLauncher(mDragLayer.getContext());
-        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        // Draw the background below children.
-        if (mAlpha > 0) {
-            // Update the scroll position first to ensure scrim cutout is in the right place.
-            mLauncher.getWorkspace().computeScrollWithoutInvalidation();
-            CellLayout currCellLayout = mLauncher.getWorkspace().getCurrentDragOverlappingLayout();
-            canvas.save();
-            if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
-                // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
-                mDragLayer.getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
-                canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
-            }
-            // for super light wallpaper it needs to be darken for contrast to workspace
-            // for dark wallpapers the text is white so darkening works as well
-            int color = ColorUtils.compositeColors(0x66000000, mWallpaperColorInfo.getMainColor());
-            canvas.drawColor(ColorUtils.setAlphaComponent(color, mAlpha));
-            canvas.restore();
-        }
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        if (mAlpha != alpha) {
-            mAlpha = alpha;
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public int getAlpha() {
-        return mAlpha;
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) { }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-}
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index 924bb4c..07eb0d6 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -22,14 +22,17 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.view.DragEvent;
 import android.view.View;
 import android.widget.RemoteViews;
 
 import com.android.launcher3.DragSource;
 import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -44,11 +47,13 @@
 public class PinItemDragListener extends BaseItemDragListener {
 
     private final PinItemRequest mRequest;
+    private final CancellationSignal mCancelSignal;
 
     public PinItemDragListener(PinItemRequest request, Rect previewRect,
             int previewBitmapWidth, int previewViewWidth) {
         super(previewRect, previewBitmapWidth, previewViewWidth);
         mRequest = request;
+        mCancelSignal = new CancellationSignal();
     }
 
     @Override
@@ -60,6 +65,15 @@
     }
 
     @Override
+    public boolean init(Launcher launcher, boolean alreadyOnHome) {
+        super.init(launcher, alreadyOnHome);
+        if (!alreadyOnHome) {
+            UiFactory.useFadeOutAnimationForLauncherStart(launcher, mCancelSignal);
+        }
+        return false;
+    }
+
+    @Override
     protected PendingItemDragHelper createDragHelper() {
         final PendingAddItemInfo item;
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -95,6 +109,12 @@
         targetParent.containerType = LauncherLogProto.ContainerType.PINITEM;
     }
 
+    @Override
+    protected void postCleanup() {
+        super.postCleanup();
+        mCancelSignal.cancel();
+    }
+
     public static RemoteViews getPreview(PinItemRequest request) {
         Bundle extras = request.getExtras();
         if (extras != null &&
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 8abafb0..6a3ebcf 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
 
 import android.animation.Animator;
@@ -26,12 +25,14 @@
 import android.animation.AnimatorSet;
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.text.InputType;
 import android.text.Selection;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.ActionMode;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
@@ -40,6 +41,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
@@ -86,7 +88,7 @@
 /**
  * Represents a set of icons chosen by the user or generated by the system.
  */
-public class Folder extends AbstractFloatingView implements DragSource, View.OnClickListener,
+public class Folder extends AbstractFloatingView implements DragSource,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
         View.OnFocusChangeListener, DragListener, ExtendedEditText.OnBackKeyListener {
     private static final String TAG = "Launcher.Folder";
@@ -190,14 +192,9 @@
     public Folder(Context context, AttributeSet attrs) {
         super(context, attrs);
         setAlwaysDrawnWithCacheEnabled(false);
-        Resources res = getResources();
 
-        if (sDefaultFolderName == null) {
-            sDefaultFolderName = res.getString(R.string.folder_name);
-        }
-        if (sHintText == null) {
-            sHintText = res.getString(R.string.folder_hint_text);
-        }
+        setLocaleDependentFields(getResources(), false /* force */);
+
         mLauncher = Launcher.getLauncher(context);
         // We need this view to be focusable in touch mode so that when text editing of the folder
         // name is complete, we have something to focus on, thus hiding the cursor and giving
@@ -208,11 +205,11 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mContent = (FolderPagedView) findViewById(R.id.folder_content);
+        mContent = findViewById(R.id.folder_content);
         mContent.setFolder(this);
 
-        mPageIndicator = (PageIndicatorDots) findViewById(R.id.folder_page_indicator);
-        mFolderName = (ExtendedEditText) findViewById(R.id.folder_name);
+        mPageIndicator = findViewById(R.id.folder_page_indicator);
+        mFolderName = findViewById(R.id.folder_name);
         mFolderName.setOnBackKeyListener(this);
         mFolderName.setOnFocusChangeListener(this);
 
@@ -253,13 +250,6 @@
         mFooterHeight = mFooter.getMeasuredHeight();
     }
 
-    public void onClick(View v) {
-        Object tag = v.getTag();
-        if (tag instanceof ShortcutInfo) {
-            mLauncher.onClick(v);
-        }
-    }
-
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return true;
@@ -489,6 +479,8 @@
             openFolder.close(true);
         }
 
+        mIsOpen = true;
+
         DragLayer dragLayer = mLauncher.getDragLayer();
         // Just verify that the folder hasn't already been added to the DragLayer.
         // There was a one-off crash where the folder had a parent already.
@@ -502,8 +494,6 @@
             }
         }
 
-        mIsOpen = true;
-
         mContent.completePendingPageChanges();
         if (!mDragInProgress) {
             // Open on the first page.
@@ -515,32 +505,21 @@
         // dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
         mDeleteFolderOnDropCompleted = false;
 
-        final Runnable onCompleteRunnable;
         centerAboutIcon();
 
         AnimatorSet anim = new FolderAnimationManager(this, true /* isOpening */).getAnimator();
-        onCompleteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
-            }
-        };
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 mFolderIcon.setBackgroundVisible(false);
                 mFolderIcon.drawLeaveBehindIfExists();
-
-                sendCustomAccessibilityEvent(
-                        Folder.this,
-                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                        mContent.getAccessibilityDescription());
             }
             @Override
             public void onAnimationEnd(Animator animation) {
                 mState = STATE_OPEN;
+                announceAccessibilityChanges();
 
-                onCompleteRunnable.run();
+                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("folder opened");
                 mContent.setFocusOnFirstChild();
             }
         });
@@ -588,11 +567,6 @@
         }
 
         mContent.verifyVisibleHighResIcons(mContent.getNextPage());
-
-        // Notify the accessibility manager that this folder "window" has appeared and occluded
-        // the workspace items
-        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        dragLayer.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
     }
 
     public void beginExternalDrag() {
@@ -622,18 +596,17 @@
             mFolderIcon.clearLeaveBehindIfExists();
         }
 
-        if (!(getParent() instanceof DragLayer)) return;
-        DragLayer parent = (DragLayer) getParent();
-
         if (animate) {
             animateClosed();
         } else {
             closeComplete(false);
+            post(this::announceAccessibilityChanges);
         }
 
         // Notify the accessibility manager that this folder "window" has disappeared and no
         // longer occludes the workspace items
-        parent.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        mLauncher.getDragLayer().sendAccessibilityEvent(
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
     private void animateClosed() {
@@ -642,18 +615,18 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 closeComplete(true);
-            }
-            @Override
-            public void onAnimationStart(Animator animation) {
-                sendCustomAccessibilityEvent(
-                        Folder.this,
-                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                        getContext().getString(R.string.folder_closed));
+                announceAccessibilityChanges();
             }
         });
         startAnimation(a);
     }
 
+    @Override
+    protected Pair<View, String> getAccessibilityTarget() {
+        return Pair.create(mContent, mIsOpen ? mContent.getAccessibilityDescription()
+                : getContext().getString(R.string.folder_closed));
+    }
+
     private void closeComplete(boolean wasAnimated) {
         // TODO: Clear all active animations.
         DragLayer parent = (DragLayer) getParent();
@@ -930,7 +903,7 @@
         int centeredTop = centerY - height / 2;
 
         // We need to bound the folder to the currently visible workspace area
-        if (mLauncher.isInState(OVERVIEW)) {
+        if (mLauncher.getStateManager().getState().overviewUi) {
             mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mLauncher.getOverviewPanel(),
                     sTempRect);
         } else {
@@ -1460,12 +1433,13 @@
     }
 
     @Override
-    public void onBackPressed() {
+    public boolean onBackPressed() {
         if (isEditingName()) {
             mFolderName.dispatchBackKey();
         } else {
             super.onBackPressed();
         }
+        return true;
     }
 
     @Override
@@ -1495,4 +1469,13 @@
         }
         return false;
     }
+
+    public static void setLocaleDependentFields(Resources res, boolean force) {
+        if (sDefaultFolderName == null || force) {
+            sDefaultFolderName = res.getString(R.string.folder_name);
+        }
+        if (sHintText == null || force) {
+            sHintText = res.getString(R.string.folder_hint_text);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index ec448e9..9ae3775 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.folder;
 
+import static com.android.launcher3.BubbleTextView.TEXT_ALPHA_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
 
@@ -172,9 +173,8 @@
         AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
 
         // Initialize the Folder items' text.
-        PropertyResetListener colorResetListener = new PropertyResetListener<>(
-                BubbleTextView.TEXT_ALPHA_PROPERTY,
-                Color.alpha(Themes.getAttrColor(mContext, android.R.attr.textColorSecondary)));
+        PropertyResetListener colorResetListener =
+                new PropertyResetListener<>(TEXT_ALPHA_PROPERTY, 1f);
         for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
             if (mIsOpening) {
                 icon.setTextVisibility(false);
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 2de09b8..95a6bbd 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -63,6 +63,7 @@
 import com.android.launcher3.dragndrop.BaseItemDragListener;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
@@ -76,7 +77,6 @@
     @Thunk Launcher mLauncher;
     @Thunk Folder mFolder;
     private FolderInfo mInfo;
-    @Thunk static boolean sStaticValuesDirty = true;
 
     private CheckLongPressHelper mLongPressHelper;
     private StylusEventHelper mStylusEventHelper;
@@ -159,14 +159,14 @@
                 .inflate(resId, group, false);
 
         icon.setClipToPadding(false);
-        icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
+        icon.mFolderName = icon.findViewById(R.id.folder_icon_name);
         icon.mFolderName.setText(folderInfo.title);
         icon.mFolderName.setCompoundDrawablePadding(0);
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
         lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
 
         icon.setTag(folderInfo);
-        icon.setOnClickListener(launcher);
+        icon.setOnClickListener(ItemClickHandler.INSTANCE);
         icon.mInfo = folderInfo;
         icon.mLauncher = launcher;
         icon.mBadgeRenderer = launcher.getDeviceProfile().mBadgeRenderer;
@@ -184,12 +184,6 @@
         return icon;
     }
 
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        sStaticValuesDirty = true;
-        return super.onSaveInstanceState();
-    }
-
     public Folder getFolder() {
         return mFolder;
     }
@@ -467,11 +461,10 @@
         final int saveCount;
 
         if (canvas.isHardwareAccelerated()) {
-            saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
-                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+            saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null);
         } else {
-            saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipPath(mBackground.getClipPath(), Region.Op.INTERSECT);
+            saveCount = canvas.save();
+            canvas.clipPath(mBackground.getClipPath());
         }
 
         mPreviewItemManager.draw(canvas);
@@ -568,7 +561,7 @@
     @Override
     public void onAdd(ShortcutInfo item, int rank) {
         boolean wasBadged = mBadgeInfo.hasBadge();
-        mBadgeInfo.addBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+        mBadgeInfo.addBadgeInfo(mLauncher.getBadgeInfoForItem(item));
         boolean isBadged = mBadgeInfo.hasBadge();
         updateBadgeScale(wasBadged, isBadged);
         invalidate();
@@ -578,7 +571,7 @@
     @Override
     public void onRemove(ShortcutInfo item) {
         boolean wasBadged = mBadgeInfo.hasBadge();
-        mBadgeInfo.subtractBadgeInfo(mLauncher.getPopupDataProvider().getBadgeInfoForItem(item));
+        mBadgeInfo.subtractBadgeInfo(mLauncher.getBadgeInfoForItem(item));
         boolean isBadged = mBadgeInfo.hasBadge();
         updateBadgeScale(wasBadged, isBadged);
         invalidate();
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index a468cb5..9be71f9 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
@@ -45,6 +44,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -87,7 +87,6 @@
     private int mGridCountY;
 
     private Folder mFolder;
-    private PagedFolderKeyEventListener mKeyListener;
 
     public FolderPagedView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -107,7 +106,6 @@
 
     public void setFolder(Folder folder) {
         mFolder = folder;
-        mKeyListener = new PagedFolderKeyEventListener(folder);
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
         initParentViews(folder);
     }
@@ -237,10 +235,9 @@
                 R.layout.folder_application, null, false);
         textView.applyFromShortcutInfo(item);
         textView.setHapticFeedbackEnabled(false);
-        textView.setOnClickListener(mFolder);
+        textView.setOnClickListener(ItemClickHandler.INSTANCE);
         textView.setOnLongClickListener(mFolder);
         textView.setOnFocusChangeListener(mFocusIndicatorHelper);
-        textView.setOnKeyListener(mKeyListener);
 
         textView.setLayoutParams(new CellLayout.LayoutParams(
                 item.cellX, item.cellY, item.spanX, item.spanY));
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index 285aef8..069ec4b 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -129,18 +129,15 @@
             };
 
     public void setup(Launcher launcher, View invalidateDelegate,
-                      int availableSpace, int topPadding) {
+                      int availableSpaceX, int topPadding) {
         mInvalidateDelegate = invalidateDelegate;
         mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
 
         DeviceProfile grid = launcher.getDeviceProfile();
-        final int previewSize = grid.folderIconSizePx;
-        final int previewPadding = grid.folderIconPreviewPadding;
+        previewSize = grid.folderIconSizePx;
 
-        this.previewSize = (previewSize - 2 * previewPadding);
-
-        basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
-        basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
+        basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
+        basePreviewOffsetY = topPadding + grid.folderIconOffsetYPx;
 
         // Stroke width is 1dp
         mStrokeWidth = launcher.getResources().getDisplayMetrics().density;
@@ -227,11 +224,10 @@
         final int saveCount;
         if (canvas.isHardwareAccelerated()) {
             saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY,
-                    offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius,
-                    null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG);
+                    offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius, null);
 
         } else {
-            saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
+            saveCount = canvas.save();
             canvas.clipPath(getClipPath(), Region.Op.DIFFERENCE);
         }
 
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 06d3eb1..1f69f6e 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -168,7 +168,7 @@
     }
 
     private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) {
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        canvas.save();
         canvas.translate(params.transX, params.transY);
         canvas.scale(params.scale, params.scale);
         Drawable d = params.drawable;
diff --git a/src/com/android/launcher3/graphics/BitmapRenderer.java b/src/com/android/launcher3/graphics/BitmapRenderer.java
index 4652ded..2a7f20e 100644
--- a/src/com/android/launcher3/graphics/BitmapRenderer.java
+++ b/src/com/android/launcher3/graphics/BitmapRenderer.java
@@ -15,9 +15,38 @@
  */
 package com.android.launcher3.graphics;
 
+import android.annotation.TargetApi;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Picture;
+import android.os.Build;
 
+import com.android.launcher3.Utilities;
+
+/**
+ * Interface representing a bitmap draw operation.
+ */
 public interface BitmapRenderer {
 
-     void render(Canvas out);
+    boolean USE_HARDWARE_BITMAP = Utilities.ATLEAST_P;
+
+    static Bitmap createSoftwareBitmap(int width, int height, BitmapRenderer renderer) {
+        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        renderer.draw(new Canvas(result));
+        return result;
+    }
+
+    @TargetApi(Build.VERSION_CODES.P)
+    static Bitmap createHardwareBitmap(int width, int height, BitmapRenderer renderer) {
+        if (!USE_HARDWARE_BITMAP) {
+            return createSoftwareBitmap(width, height, renderer);
+        }
+
+        Picture picture = new Picture();
+        renderer.draw(picture.beginRecording(width, height));
+        picture.endRecording();
+        return Bitmap.createBitmap(picture);
+    }
+
+    void draw(Canvas out);
 }
diff --git a/src/com/android/launcher3/graphics/ColorScrim.java b/src/com/android/launcher3/graphics/ColorScrim.java
new file mode 100644
index 0000000..96d93d8
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ColorScrim.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.support.v4.graphics.ColorUtils;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+
+/**
+ * Simple scrim which draws a color
+ */
+public class ColorScrim extends ViewScrim {
+
+    private final int mColor;
+    private final Interpolator mInterpolator;
+    private int mCurrentColor;
+
+    public ColorScrim(View view, int color, Interpolator interpolator) {
+        super(view);
+        mColor = color;
+        mInterpolator = interpolator;
+    }
+
+    @Override
+    protected void onProgressChanged() {
+        mCurrentColor = ColorUtils.setAlphaComponent(mColor,
+                Math.round(mInterpolator.getInterpolation(mProgress) * Color.alpha(mColor)));
+    }
+
+    @Override
+    public void draw(Canvas canvas, int width, int height) {
+        if (mProgress > 0) {
+            canvas.drawColor(mCurrentColor);
+        }
+    }
+
+    public static ColorScrim createExtractedColorScrim(View view) {
+        WallpaperColorInfo colors = WallpaperColorInfo.getInstance(view.getContext());
+        int alpha = view.getResources().getInteger(R.integer.extracted_color_gradient_alpha);
+        ColorScrim scrim = new ColorScrim(view, ColorUtils.setAlphaComponent(
+                colors.getSecondaryColor(), alpha), Interpolators.LINEAR);
+        scrim.attach();
+        return scrim;
+    }
+}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 6a328e9..5094280 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -24,19 +24,17 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.UiThreadHelper;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
 import java.nio.ByteBuffer;
 
@@ -78,7 +76,7 @@
     /**
      * Draws the {@link #mView} into the given {@param destCanvas}.
      */
-    private void drawDragView(Canvas destCanvas, float scale) {
+    protected void drawDragView(Canvas destCanvas, float scale) {
         destCanvas.save();
         destCanvas.scale(scale, scale);
 
@@ -103,7 +101,7 @@
             }
             destCanvas.translate(-mView.getScrollX() + blurSizeOutline / 2,
                     -mView.getScrollY() + blurSizeOutline / 2);
-            destCanvas.clipRect(clipRect, Op.REPLACE);
+            destCanvas.clipRect(clipRect);
             mView.draw(destCanvas);
 
             // Restore text visibility of FolderIcon if necessary
@@ -119,28 +117,26 @@
      * Responsibility for the bitmap is transferred to the caller.
      */
     public Bitmap createDragBitmap() {
-        float scale = 1f;
         int width = mView.getWidth();
         int height = mView.getHeight();
 
-        boolean forceSoftwareRenderer = false;
         if (mView instanceof BubbleTextView) {
             Drawable d = ((BubbleTextView) mView).getIcon();
             Rect bounds = getDrawableBounds(d);
             width = bounds.width();
             height = bounds.height();
         } else if (mView instanceof LauncherAppWidgetHostView) {
-            scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
+            float scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
             width = (int) (mView.getWidth() * scale);
             height = (int) (mView.getHeight() * scale);
 
             // Use software renderer for widgets as we know that they already work
-            forceSoftwareRenderer = true;
+            return BitmapRenderer.createSoftwareBitmap(width + blurSizeOutline,
+                    height + blurSizeOutline, (c) -> drawDragView(c, scale));
         }
 
-        final float scaleFinal = scale;
-        return UiFactory.createFromRenderer(width + blurSizeOutline, height + blurSizeOutline,
-                forceSoftwareRenderer, (c) -> drawDragView(c, scaleFinal));
+        return BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
+                height + blurSizeOutline, (c) -> drawDragView(c, 1));
     }
 
     public final void generateDragOutline(Bitmap preview) {
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 32d9e41..bbc013d 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.graphics;
 
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -35,11 +36,12 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
+import com.android.launcher3.util.ResourceBasedOverride;
 
 /**
  * Factory for creating new drawables.
  */
-public class DrawableFactory {
+public class DrawableFactory implements ResourceBasedOverride {
 
     private static final String TAG = "DrawableFactory";
 
@@ -51,7 +53,7 @@
     public static DrawableFactory get(Context context) {
         synchronized (LOCK) {
             if (sInstance == null) {
-                sInstance = Utilities.getOverrideObject(DrawableFactory.class,
+                sInstance = Overrides.getObject(DrawableFactory.class,
                         context.getApplicationContext(), R.string.drawable_factory_class);
             }
             return sInstance;
@@ -65,6 +67,12 @@
      * Returns a FastBitmapDrawable with the icon.
      */
     public FastBitmapDrawable newIcon(ItemInfoWithIcon info) {
+        FastBitmapDrawable drawable = new FastBitmapDrawable(info);
+        drawable.setIsDisabled(info.isDisabled());
+        return drawable;
+    }
+
+    public FastBitmapDrawable newIcon(BitmapInfo info, ActivityInfo target) {
         return new FastBitmapDrawable(info);
     }
 
@@ -78,7 +86,6 @@
         return new PreloadIconDrawable(info, mPreloadProgressPath, context);
     }
 
-
     protected Path getPreloadProgressPath(Context context) {
         if (Utilities.ATLEAST_OREO) {
             try {
diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
index 262a95e..0f0e424 100644
--- a/src/com/android/launcher3/graphics/FixedScaleDrawable.java
+++ b/src/com/android/launcher3/graphics/FixedScaleDrawable.java
@@ -29,7 +29,7 @@
 
     @Override
     public void draw(Canvas canvas) {
-        int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        int saveCount = canvas.save();
         canvas.scale(mScaleX, mScaleY,
                 getBounds().exactCenterX(), getBounds().exactCenterY());
         super.draw(canvas);
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
deleted file mode 100644
index 6253e18..0000000
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.graphics;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.RadialGradient;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.util.DisplayMetrics;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.util.Themes;
-
-/**
- * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
- * final state with progress 1.0;
- */
-public class GradientView extends View implements WallpaperColorInfo.OnChangeListener {
-
-    private static final int DEFAULT_COLOR = Color.WHITE;
-    private static final int ALPHA_MASK_HEIGHT_DP = 500;
-    private static final int ALPHA_MASK_WIDTH_DP = 2;
-    private static final boolean DEBUG = false;
-
-    private final Bitmap mAlphaGradientMask;
-
-    private boolean mShowScrim = true;
-    private int mColor1 = DEFAULT_COLOR;
-    private int mColor2 = DEFAULT_COLOR;
-    private int mWidth;
-    private int mHeight;
-    private final RectF mAlphaMaskRect = new RectF();
-    private final RectF mFinalMaskRect = new RectF();
-    private final Paint mPaintWithScrim = new Paint();
-    private final Paint mPaintNoScrim = new Paint();
-    private float mProgress;
-    private final int mMaskHeight, mMaskWidth;
-    private final int mAlphaColors;
-    private final Paint mDebugPaint = DEBUG ? new Paint() : null;
-    private final Interpolator mAccelerator = Interpolators.ACCEL;
-    private final float mAlphaStart;
-    private final WallpaperColorInfo mWallpaperColorInfo;
-    private final int mScrimColor;
-
-    public GradientView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
-        this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
-        Launcher launcher = Launcher.getLauncher(context);
-        this.mAlphaStart = 0;
-        this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
-        mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha);
-        updateColors();
-        mAlphaGradientMask = createDitheredAlphaMask();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperColorInfo.addOnChangeListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mWallpaperColorInfo.removeOnChangeListener(this);
-    }
-
-    @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo info) {
-        updateColors();
-        invalidate();
-    }
-
-    private void updateColors() {
-        this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(),
-                mAlphaColors);
-        this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(),
-                mAlphaColors);
-        if (mWidth + mHeight > 0) {
-            createRadialShader();
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        this.mWidth = getMeasuredWidth();
-        this.mHeight = getMeasuredHeight();
-        if (mWidth + mHeight > 0) {
-            createRadialShader();
-        }
-    }
-
-    // only being called when colors change
-    private void createRadialShader() {
-        final float gradientCenterY = 1.05f;
-        float radius = Math.max(mHeight, mWidth) * gradientCenterY;
-        float posScreenBottom = (radius - mHeight) / radius; // center lives below screen
-
-        RadialGradient shaderNoScrim = new RadialGradient(
-                mWidth * 0.5f,
-                mHeight * gradientCenterY,
-                radius,
-                new int[] {mColor1, mColor1, mColor2},
-                new float[] {0f, posScreenBottom, 1f},
-                Shader.TileMode.CLAMP);
-        mPaintNoScrim.setShader(shaderNoScrim);
-
-        int color1 = ColorUtils.compositeColors(mScrimColor,mColor1);
-        int color2 = ColorUtils.compositeColors(mScrimColor,mColor2);
-        RadialGradient shaderWithScrim = new RadialGradient(
-                mWidth * 0.5f,
-                mHeight * gradientCenterY,
-                radius,
-                new int[] { color1, color1, color2 },
-                new float[] {0f, posScreenBottom, 1f},
-                Shader.TileMode.CLAMP);
-        mPaintWithScrim.setShader(shaderWithScrim);
-    }
-
-    public void setProgress(float progress) {
-        setProgress(progress, true);
-    }
-
-    public void setProgress(float progress, boolean showScrim) {
-        this.mProgress = progress;
-        this.mShowScrim = showScrim;
-        invalidate();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        Paint paint = mShowScrim ? mPaintWithScrim : mPaintNoScrim;
-
-        float head = 0.29f;
-        float linearProgress = head + (mProgress * (1f - head));
-        float startMaskY = (1f - linearProgress) * mHeight - mMaskHeight * linearProgress;
-        float interpolatedAlpha = (255 - mAlphaStart) * mAccelerator.getInterpolation(mProgress);
-        paint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
-        float div = (float) Math.floor(startMaskY + mMaskHeight);
-        mAlphaMaskRect.set(0, startMaskY, mWidth, div);
-        mFinalMaskRect.set(0, div, mWidth, mHeight);
-        canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, paint);
-        canvas.drawRect(mFinalMaskRect, paint);
-
-        if (DEBUG) {
-            mDebugPaint.setColor(0xFF00FF00);
-            canvas.drawLine(0, startMaskY, mWidth, startMaskY, mDebugPaint);
-            canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint);
-        }
-    }
-
-    public Bitmap createDitheredAlphaMask() {
-        Bitmap dst = Bitmap.createBitmap(mMaskWidth, mMaskHeight, Bitmap.Config.ALPHA_8);
-        Canvas c = new Canvas(dst);
-        Paint paint = new Paint(Paint.DITHER_FLAG);
-        LinearGradient lg = new LinearGradient(0, 0, 0, mMaskHeight,
-                new int[]{
-                        0x00FFFFFF,
-                        ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
-                        0xFFFFFFFF},
-                new float[]{0f, 0.8f, 1f},
-                Shader.TileMode.CLAMP);
-        paint.setShader(lg);
-        c.drawRect(0, 0, mMaskWidth, mMaskHeight, paint);
-        return dst;
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java b/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
deleted file mode 100644
index ebfe1e7..0000000
--- a/src/com/android/launcher3/graphics/HolographicOutlineHelper.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.graphics;
-
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_ADAPTIVE_ICON;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BlurMaskFilter;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.SparseArray;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.ItemInfoWithIcon;
-import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.UiFactory;
-
-/**
- * Utility class to generate shadow and outline effect, which are used for click feedback
- * and drag-n-drop respectively.
- */
-public class HolographicOutlineHelper {
-
-    /**
-     * Bitmap used as shadow for Adaptive icons
-     */
-    public static final Bitmap ADAPTIVE_ICON_SHADOW_BITMAP =
-            Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
-
-    private static HolographicOutlineHelper sInstance;
-
-    private final Canvas mCanvas = new Canvas();
-    private final Paint mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-    private final Paint mErasePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-
-    private final float mShadowBitmapShift;
-    private final BlurMaskFilter mShadowBlurMaskFilter;
-
-    // We have 4 different icon sizes: homescreen, hotseat, folder & all-apps
-    private final SparseArray<Bitmap> mBitmapCache = new SparseArray<>(4);
-
-    private HolographicOutlineHelper(Context context) {
-        mShadowBitmapShift = context.getResources().getDimension(R.dimen.blur_size_click_shadow);
-        mShadowBlurMaskFilter = new BlurMaskFilter(mShadowBitmapShift, BlurMaskFilter.Blur.NORMAL);
-        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
-    }
-
-    public static HolographicOutlineHelper getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new HolographicOutlineHelper(context.getApplicationContext());
-        }
-        return sInstance;
-    }
-
-    public Bitmap createMediumDropShadow(BubbleTextView view) {
-        if (view.getTag() instanceof ItemInfoWithIcon &&
-                ((((ItemInfoWithIcon) view.getTag()).runtimeStatusFlags & FLAG_ADAPTIVE_ICON)
-                        != 0)) {
-            return ADAPTIVE_ICON_SHADOW_BITMAP;
-        }
-        Drawable drawable = view.getIcon();
-        if (drawable == null) {
-            return null;
-        }
-
-        float scaleX = view.getScaleX();
-        float scaleY = view.getScaleY();
-        Rect rect = drawable.getBounds();
-
-        int bitmapWidth = (int) (rect.width() * scaleX);
-        int bitmapHeight = (int) (rect.height() * scaleY);
-        if (bitmapHeight <= 0 || bitmapWidth <= 0) {
-            return null;
-        }
-
-        int key = (bitmapWidth << 16) | bitmapHeight;
-        Bitmap cache = mBitmapCache.get(key);
-        if (cache == null) {
-            cache = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ALPHA_8);
-            mCanvas.setBitmap(cache);
-            mBitmapCache.put(key, cache);
-        } else {
-            mCanvas.setBitmap(cache);
-            mCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
-        }
-
-        int saveCount = mCanvas.save();
-        mCanvas.scale(scaleX, scaleY);
-        mCanvas.translate(-rect.left, -rect.top);
-        if (!UiFactory.USE_HARDWARE_BITMAP) {
-            // TODO: Outline generation requires alpha extraction, which is costly for
-            // hardware bitmaps. Instead use canvas layer operations once its available.
-            drawable.draw(mCanvas);
-        }
-        mCanvas.restoreToCount(saveCount);
-        mCanvas.setBitmap(null);
-
-        mBlurPaint.setMaskFilter(mShadowBlurMaskFilter);
-
-        int extraSize = (int) (2 * mShadowBitmapShift);
-
-        int resultWidth = bitmapWidth + extraSize;
-        int resultHeight = bitmapHeight + extraSize;
-        key = (resultWidth << 16) | resultHeight;
-        Bitmap result = mBitmapCache.get(key);
-        if (result == null) {
-            result = Bitmap.createBitmap(resultWidth, resultHeight, Bitmap.Config.ALPHA_8);
-            mCanvas.setBitmap(result);
-        } else {
-            // Use put instead of delete, to avoid unnecessary shrinking of cache array
-            mBitmapCache.put(key, null);
-            mCanvas.setBitmap(result);
-            mCanvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR);
-        }
-        mCanvas.drawBitmap(cache, mShadowBitmapShift, mShadowBitmapShift, mBlurPaint);
-        mCanvas.setBitmap(null);
-        return result;
-    }
-
-    public void recycleShadowBitmap(Bitmap bitmap) {
-        if (bitmap != null && bitmap != ADAPTIVE_ICON_SHADOW_BITMAP) {
-            mBitmapCache.put((bitmap.getWidth() << 16) | bitmap.getHeight(), bitmap);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index bd20c87..a2a0801 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -24,6 +24,7 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -61,14 +62,15 @@
     private static final float PIXEL_DIFF_PERCENTAGE_THRESHOLD = 0.005f;
     private static final float SCALE_NOT_INITIALIZED = 0;
 
+    // Ratio of the diameter of an normalized circular icon to the actual icon size.
+    public static final float ICON_VISIBLE_AREA_FACTOR = 0.92f;
+
     private final int mMaxSize;
     private final Bitmap mBitmap;
-    private final Bitmap mBitmapARGB;
     private final Canvas mCanvas;
     private final Paint mPaintMaskShape;
     private final Paint mPaintMaskShapeOutline;
     private final byte[] mPixels;
-    private final int[] mPixelsARGB;
 
     private final Rect mAdaptiveIconBounds;
     private float mAdaptiveIconScale;
@@ -77,11 +79,9 @@
     private final float[] mLeftBorder;
     private final float[] mRightBorder;
     private final Rect mBounds;
+    private final Path mShapePath;
     private final Matrix mMatrix;
 
-    private final Paint mPaintIcon;
-    private final Canvas mCanvasARGB;
-
     /** package private **/
     IconNormalizer(Context context) {
         // Use twice the icon size as maximum size to avoid scaling down twice.
@@ -89,19 +89,11 @@
         mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
         mCanvas = new Canvas(mBitmap);
         mPixels = new byte[mMaxSize * mMaxSize];
-        mPixelsARGB = new int[mMaxSize * mMaxSize];
         mLeftBorder = new float[mMaxSize];
         mRightBorder = new float[mMaxSize];
         mBounds = new Rect();
         mAdaptiveIconBounds = new Rect();
 
-        // Needed for isShape() method
-        mBitmapARGB = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ARGB_8888);
-        mCanvasARGB = new Canvas(mBitmapARGB);
-
-        mPaintIcon = new Paint();
-        mPaintIcon.setColor(Color.WHITE);
-
         mPaintMaskShape = new Paint();
         mPaintMaskShape.setColor(Color.RED);
         mPaintMaskShape.setStyle(Paint.Style.FILL);
@@ -111,8 +103,9 @@
         mPaintMaskShapeOutline.setStrokeWidth(2 * context.getResources().getDisplayMetrics().density);
         mPaintMaskShapeOutline.setStyle(Paint.Style.STROKE);
         mPaintMaskShapeOutline.setColor(Color.BLACK);
-        mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+        mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
 
+        mShapePath = new Path();
         mMatrix = new Matrix();
         mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
     }
@@ -136,41 +129,49 @@
         // Condition 2:
         // Actual icon (white) and the fitted shape (e.g., circle)(red) XOR operation
         // should generate transparent image, if the actual icon is equivalent to the shape.
-        mBitmapARGB.eraseColor(Color.TRANSPARENT);
-        mCanvasARGB.drawBitmap(mBitmap, 0, 0, mPaintIcon);
 
         // Fit the shape within the icon's bounding box
         mMatrix.reset();
         mMatrix.setScale(mBounds.width(), mBounds.height());
         mMatrix.postTranslate(mBounds.left, mBounds.top);
-        maskPath.transform(mMatrix);
+        maskPath.transform(mMatrix, mShapePath);
 
         // XOR operation
-        mCanvasARGB.drawPath(maskPath, mPaintMaskShape);
+        mCanvas.drawPath(mShapePath, mPaintMaskShape);
 
         // DST_OUT operation around the mask path outline
-        mCanvasARGB.drawPath(maskPath, mPaintMaskShapeOutline);
+        mCanvas.drawPath(mShapePath, mPaintMaskShapeOutline);
 
         // Check if the result is almost transparent
-        return isTransparentBitmap(mBitmapARGB);
+        return isTransparentBitmap();
     }
 
     /**
      * Used to determine if certain the bitmap is transparent.
      */
-    private boolean isTransparentBitmap(Bitmap bitmap) {
-        int w = mBounds.width();
-        int h = mBounds.height();
-        bitmap.getPixels(mPixelsARGB, 0 /* the first index to write into the array */,
-                w /* stride */,
-                mBounds.left, mBounds.top,
-                w, h);
+    private boolean isTransparentBitmap() {
+        ByteBuffer buffer = ByteBuffer.wrap(mPixels);
+        buffer.rewind();
+        mBitmap.copyPixelsToBuffer(buffer);
+
+        int y = mBounds.top;
+        // buffer position
+        int index = y * mMaxSize;
+        // buffer shift after every row, width of buffer = mMaxSize
+        int rowSizeDiff = mMaxSize - mBounds.right;
+
         int sum = 0;
-        for (int i = w * h - 1; i >= 0; i--) {
-            if(Color.alpha(mPixelsARGB[i]) > MIN_VISIBLE_ALPHA) {
+        for (; y < mBounds.bottom; y++) {
+            index += mBounds.left;
+            for (int x = mBounds.left; x < mBounds.right; x++) {
+                if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
                     sum++;
+                }
+                index++;
             }
+            index += rowSizeDiff;
         }
+
         float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
         return percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
     }
@@ -301,7 +302,7 @@
         mBounds.bottom = bottomY;
 
         if (outBounds != null) {
-            outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top),
+            outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height,
                     1 - ((float) mBounds.right) / width,
                     1 - ((float) mBounds.bottom) / height);
         }
@@ -373,4 +374,12 @@
             last = i;
         }
     }
+
+    /**
+     * @return The diameter of the normalized circle that fits inside of the square (size x size).
+     */
+    public static int getNormalizedCircleSize(int size) {
+        float area = size * size * MAX_CIRCLE_AREA_FACTOR;
+        return (int) Math.round(Math.sqrt((4 * area) / Math.PI));
+    }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 34fc921..333fe59 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -29,11 +29,13 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.PaintFlagsDrawFilter;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
 import android.os.Build;
@@ -52,7 +54,6 @@
 import com.android.launcher3.model.PackageItemInfo;
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
-import com.android.launcher3.uioverrides.UiFactory;
 import com.android.launcher3.util.Provider;
 import com.android.launcher3.util.Themes;
 
@@ -61,6 +62,8 @@
  */
 public class LauncherIcons implements AutoCloseable {
 
+    private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+
     public static final Object sPoolSync = new Object();
     private static LauncherIcons sPool;
 
@@ -85,6 +88,9 @@
      */
     public void recycle() {
         synchronized (sPoolSync) {
+            // Clear any temporary state variables
+            mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+
             next = sPool;
             sPool = this;
         }
@@ -106,6 +112,9 @@
     private IconNormalizer mNormalizer;
     private ShadowGenerator mShadowGenerator;
 
+    private Drawable mWrapperIcon;
+    private int mWrapperBackgroundColor = DEFAULT_WRAPPER_BACKGROUND;
+
     // sometimes we store linked lists of these things
     private LauncherIcons next;
 
@@ -173,7 +182,24 @@
      * The bitmap is also visually normalized with other icons.
      */
     public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk) {
-        float[] scale = new float[1];
+        return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false, null);
+    }
+
+    public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
+            boolean isInstantApp) {
+        return createBadgedIconBitmap(icon, user, iconAppTargetSdk, isInstantApp, null);
+    }
+
+    /**
+     * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
+     * view or workspace. The icon is badged for {@param user}.
+     * The bitmap is also visually normalized with other icons.
+     */
+    public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
+            boolean isInstantApp, float [] scale) {
+        if (scale == null) {
+            scale = new float[1];
+        }
         icon = normalizeAndWrapToAdaptiveIcon(icon, iconAppTargetSdk, null, scale);
         Bitmap bitmap = createIconBitmap(icon, scale[0]);
         if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
@@ -191,6 +217,9 @@
             } else {
                 result = createIconBitmap(badged, 1f);
             }
+        } else if (isInstantApp) {
+            badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
+            result = bitmap;
         } else {
             result = bitmap;
         }
@@ -209,13 +238,24 @@
                 Math.min(scale[0], ShadowGenerator.getScaleForBounds(iconBounds)));
     }
 
+    /**
+     * Sets the background color used for wrapped adaptive icon
+     */
+    public void setWrapperBackgroundColor(int color) {
+        mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
+    }
+
     private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, int iconAppTargetSdk,
             RectF outIconBounds, float[] outScale) {
         float scale = 1f;
-        if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
+        if ((Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) ||
+                Utilities.ATLEAST_P) {
             boolean[] outShape = new boolean[1];
-            AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
-                    mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+            if (mWrapperIcon == null) {
+                mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
+                        .mutate();
+            }
+            AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
             dr.setBounds(0, 0, 1, 1);
             scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
             if (Utilities.ATLEAST_OREO && !outShape[0] && !(icon instanceof AdaptiveIconDrawable)) {
@@ -224,6 +264,8 @@
                 fsd.setScale(scale);
                 icon = dr;
                 scale = getNormalizer().getScale(icon, outIconBounds, null, null);
+
+                ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
             }
         } else {
             scale = getNormalizer().getScale(icon, outIconBounds, null, null);
@@ -296,13 +338,13 @@
 
         mOldBounds.set(icon.getBounds());
         if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) {
-            int offset = Math.max((int)(BLUR_FACTOR * textureWidth), Math.min(left, top));
+            int offset = Math.max((int) Math.ceil(BLUR_FACTOR * textureWidth), Math.max(left, top));
             int size = Math.max(width, height);
-            icon.setBounds(offset, offset, size, size);
+            icon.setBounds(offset, offset, size - offset, size - offset);
         } else {
             icon.setBounds(left, top, left+width, top+height);
         }
-        mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+        mCanvas.save();
         mCanvas.scale(scale, scale, textureWidth / 2, textureHeight / 2);
         icon.draw(mCanvas);
         mCanvas.restore();
@@ -326,16 +368,18 @@
                 .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
         IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
 
-        Bitmap unbadgedBitmap = null;
+        final Bitmap unbadgedBitmap;
         if (unbadgedDrawable != null) {
             unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
         } else {
             if (fallbackIconProvider != null) {
-                unbadgedBitmap = fallbackIconProvider.get();
+                // Fallback icons are already badged and with appropriate shadow
+                Bitmap fullIcon = fallbackIconProvider.get();
+                if (fullIcon != null) {
+                    return createIconBitmap(fullIcon);
+                }
             }
-            if (unbadgedBitmap == null) {
-                unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
-            }
+            unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
         }
 
         BitmapInfo result = new BitmapInfo();
@@ -349,7 +393,7 @@
         final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache);
 
         result.color = badge.iconColor;
-        result.icon = UiFactory.createFromRenderer(mIconBitmapSize, mIconBitmapSize, false, (c) -> {
+        result.icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> {
             getShadowGenerator().recreateIcon(unbadgedfinal, c);
             badgeWithDrawable(c, new FastBitmapDrawable(badge));
         });
diff --git a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
index fc20926..5872689 100644
--- a/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
+++ b/src/com/android/launcher3/graphics/NinePatchDrawHelper.java
@@ -33,7 +33,9 @@
 
     private final Rect mSrc = new Rect();
     private final RectF mDst = new RectF();
-    public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    // Enable filtering to always get a nice edge. This avoids jagged line, when bitmap is
+    // translated by half pixel.
+    public final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
 
     /**
      * Draws the bitmap split into three parts horizontally, with the middle part having width
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index a40b6df..d3a7955 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -77,7 +77,7 @@
     private final Matrix mTmpMatrix = new Matrix();
     private final PathMeasure mPathMeasure = new PathMeasure();
 
-    private final Context mContext;
+    private final ItemInfoWithIcon mItem;
 
     // Path in [0, 100] bounds.
     private final Path mProgressPath;
@@ -106,7 +106,7 @@
      */
     public PreloadIconDrawable(ItemInfoWithIcon info, Path progressPath, Context context) {
         super(info);
-        mContext = context;
+        mItem = info;
         mProgressPath = progressPath;
         mScaledTrackPath = new Path();
         mScaledProgressPath = new Path();
@@ -162,9 +162,9 @@
     }
 
     @Override
-    public void draw(Canvas canvas) {
+    public void drawInternal(Canvas canvas, Rect bounds) {
         if (mRanFinishAnimation) {
-            super.draw(canvas);
+            super.drawInternal(canvas, bounds);
             return;
         }
 
@@ -172,15 +172,13 @@
         mProgressPaint.setColor(mIndicatorColor);
         mProgressPaint.setAlpha(mTrackAlpha);
         if (mShadowBitmap != null) {
-            canvas.drawBitmap(mShadowBitmap, getBounds().left, getBounds().top, mProgressPaint);
+            canvas.drawBitmap(mShadowBitmap, bounds.left, bounds.top, mProgressPaint);
         }
         canvas.drawPath(mScaledProgressPath, mProgressPaint);
 
-        int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
-        Rect bounds = getBounds();
-
+        int saveCount = canvas.save();
         canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
-        super.draw(canvas);
+        super.drawInternal(canvas, bounds);
         canvas.restoreToCount(saveCount);
     }
 
@@ -276,7 +274,7 @@
             mTrackAlpha = MAX_PAINT_ALPHA;
             setIsDisabled(true);
         } else if (progress >= 1) {
-            setIsDisabled(false);
+            setIsDisabled(mItem.isDisabled());
             mScaledTrackPath.set(mScaledProgressPath);
             float fraction = (progress - 1) / COMPLETE_ANIM_FRACTION;
 
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 5fbf502..88da853 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -126,13 +126,13 @@
         }
 
         public Bitmap createPill(int width, int height) {
-            radius = height / 2;
+            radius = height / 2f;
 
-            int centerX = Math.round(width / 2 + shadowBlur);
+            int centerX = Math.round(width / 2f + shadowBlur);
             int centerY = Math.round(radius + shadowBlur + keyShadowDistance);
             int center = Math.max(centerX, centerY);
             bounds.set(0, 0, width, height);
-            bounds.offsetTo(center - width / 2, center - height / 2);
+            bounds.offsetTo(center - width / 2f, center - height / 2f);
 
             int size = center * 2;
             Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888);
diff --git a/src/com/android/launcher3/graphics/ViewScrim.java b/src/com/android/launcher3/graphics/ViewScrim.java
new file mode 100644
index 0000000..e1727e0
--- /dev/null
+++ b/src/com/android/launcher3/graphics/ViewScrim.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import android.graphics.Canvas;
+import android.util.Property;
+import android.view.View;
+import android.view.ViewParent;
+
+import com.android.launcher3.R;
+
+/**
+ * A utility class that can be used to draw a scrim behind a view
+ */
+public abstract class ViewScrim<T extends View> {
+
+    public static Property<ViewScrim, Float> PROGRESS =
+            new Property<ViewScrim, Float>(Float.TYPE, "progress") {
+                @Override
+                public Float get(ViewScrim viewScrim) {
+                    return viewScrim.mProgress;
+                }
+
+                @Override
+                public void set(ViewScrim object, Float value) {
+                    object.setProgress(value);
+                }
+            };
+
+    protected final T mView;
+    protected float mProgress = 0;
+
+    public ViewScrim(T view) {
+        mView = view;
+    }
+
+    public void attach() {
+        mView.setTag(R.id.view_scrim, this);
+    }
+
+    public void setProgress(float progress) {
+        if (mProgress != progress) {
+            mProgress = progress;
+            onProgressChanged();
+            invalidate();
+        }
+    }
+
+    public abstract void draw(Canvas canvas, int width, int height);
+
+    protected void onProgressChanged() { }
+
+    public void invalidate() {
+        ViewParent parent = mView.getParent();
+        if (parent != null) {
+            ((View) parent).invalidate();
+        }
+    }
+
+    public static ViewScrim get(View view) {
+        return (ViewScrim) view.getTag(R.id.view_scrim);
+    }
+}
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
new file mode 100644
index 0000000..bc4a06d
--- /dev/null
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2018 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.graphics;
+
+import static android.content.Intent.ACTION_SCREEN_OFF;
+import static android.content.Intent.ACTION_USER_PRESENT;
+
+import android.animation.ObjectAnimator;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.ColorUtils;
+import android.util.DisplayMetrics;
+import android.util.Property;
+import android.view.View;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.util.Themes;
+
+/**
+ * View scrim which draws behind hotseat and workspace
+ */
+public class WorkspaceAndHotseatScrim implements
+        View.OnAttachStateChangeListener, WallpaperColorInfo.OnChangeListener {
+
+    public static Property<WorkspaceAndHotseatScrim, Float> SCRIM_PROGRESS =
+            new Property<WorkspaceAndHotseatScrim, Float>(Float.TYPE, "scrimProgress") {
+                @Override
+                public Float get(WorkspaceAndHotseatScrim scrim) {
+                    return scrim.mScrimProgress;
+                }
+
+                @Override
+                public void set(WorkspaceAndHotseatScrim scrim, Float value) {
+                    scrim.setScrimProgress(value);
+                }
+            };
+
+    public static Property<WorkspaceAndHotseatScrim, Float> SYSUI_PROGRESS =
+            new Property<WorkspaceAndHotseatScrim, Float>(Float.TYPE, "sysUiProgress") {
+                @Override
+                public Float get(WorkspaceAndHotseatScrim scrim) {
+                    return scrim.mSysUiProgress;
+                }
+
+                @Override
+                public void set(WorkspaceAndHotseatScrim scrim, Float value) {
+                    scrim.setSysUiProgress(value);
+                }
+            };
+
+    private static Property<WorkspaceAndHotseatScrim, Float> SYSUI_ANIM_MULTIPLIER =
+            new Property<WorkspaceAndHotseatScrim, Float>(Float.TYPE, "sysUiAnimMultiplier") {
+                @Override
+                public Float get(WorkspaceAndHotseatScrim scrim) {
+                    return scrim.mSysUiAnimMultiplier;
+                }
+
+                @Override
+                public void set(WorkspaceAndHotseatScrim scrim, Float value) {
+                    scrim.mSysUiAnimMultiplier = value;
+                    scrim.reapplySysUiAlpha();
+                }
+            };
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (ACTION_SCREEN_OFF.equals(action)) {
+                mAnimateScrimOnNextDraw = true;
+            } else if (ACTION_USER_PRESENT.equals(action)) {
+                // ACTION_USER_PRESENT is sent after onStart/onResume. This covers the case where
+                // the user unlocked and the Launcher is not in the foreground.
+                mAnimateScrimOnNextDraw = false;
+            }
+        }
+    };
+
+    private static final int DARK_SCRIM_COLOR = 0x55000000;
+    private static final int MAX_HOTSEAT_SCRIM_ALPHA = 100;
+    private static final int ALPHA_MASK_HEIGHT_DP = 500;
+    private static final int ALPHA_MASK_BITMAP_DP = 200;
+    private static final int ALPHA_MASK_WIDTH_DP = 2;
+
+    private final Rect mHighlightRect = new Rect();
+    private final Launcher mLauncher;
+    private final WallpaperColorInfo mWallpaperColorInfo;
+    private final View mRoot;
+
+    private Workspace mWorkspace;
+
+    private final boolean mHasSysUiScrim;
+    private boolean mDrawTopScrim, mDrawBottomScrim;
+
+    private final RectF mFinalMaskRect = new RectF();
+    private final Paint mBottomMaskPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+    private final Bitmap mBottomMask;
+    private final int mMaskHeight;
+
+    private final Drawable mTopScrim;
+
+    private int mFullScrimColor;
+
+    private float mScrimProgress;
+    private int mScrimAlpha = 0;
+
+    private float mSysUiProgress = 1;
+    private boolean mHideSysUiScrim;
+
+    private boolean mAnimateScrimOnNextDraw = false;
+    private float mSysUiAnimMultiplier = 1;
+
+    public WorkspaceAndHotseatScrim(View view) {
+        mRoot = view;
+        mLauncher = Launcher.getLauncher(view.getContext());
+        mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher);
+
+        mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_BITMAP_DP,
+                view.getResources().getDisplayMetrics());
+
+        mHasSysUiScrim = !mWallpaperColorInfo.supportsDarkText();
+        if (mHasSysUiScrim) {
+            mTopScrim = Themes.getAttrDrawable(view.getContext(), R.attr.workspaceStatusBarScrim);
+            mBottomMask = createDitheredAlphaMask();
+        } else {
+            mTopScrim = null;
+            mBottomMask = null;
+        }
+
+        view.addOnAttachStateChangeListener(this);
+        onExtractedColorsChanged(mWallpaperColorInfo);
+    }
+
+    public void setWorkspace(Workspace workspace)  {
+        mWorkspace = workspace;
+    }
+
+    public void draw(Canvas canvas) {
+        // Draw the background below children.
+        if (mScrimAlpha > 0) {
+            // Update the scroll position first to ensure scrim cutout is in the right place.
+            mWorkspace.computeScrollWithoutInvalidation();
+            CellLayout currCellLayout = mWorkspace.getCurrentDragOverlappingLayout();
+            canvas.save();
+            if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) {
+                // Cut a hole in the darkening scrim on the page that should be highlighted, if any.
+                mLauncher.getDragLayer()
+                        .getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect);
+                canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE);
+            }
+
+            canvas.drawColor(ColorUtils.setAlphaComponent(mFullScrimColor, mScrimAlpha));
+            canvas.restore();
+        }
+
+        if (!mHideSysUiScrim && mHasSysUiScrim) {
+            if (mSysUiProgress <= 0) {
+                mAnimateScrimOnNextDraw = false;
+                return;
+            }
+
+            if (mAnimateScrimOnNextDraw) {
+                mSysUiAnimMultiplier = 0;
+                reapplySysUiAlphaNoInvalidate();
+
+                ObjectAnimator anim = ObjectAnimator.ofFloat(this, SYSUI_ANIM_MULTIPLIER, 1);
+                anim.setAutoCancel(true);
+                anim.setDuration(600);
+                anim.setStartDelay(mLauncher.getWindow().getTransitionBackgroundFadeDuration());
+                anim.start();
+                mAnimateScrimOnNextDraw = false;
+            }
+
+            if (mDrawTopScrim) {
+                mTopScrim.draw(canvas);
+            }
+            if (mDrawBottomScrim) {
+                canvas.drawBitmap(mBottomMask, null, mFinalMaskRect, mBottomMaskPaint);
+            }
+        }
+    }
+
+    public void onInsetsChanged(Rect insets) {
+        mDrawTopScrim = insets.top > 0;
+        mDrawBottomScrim = !mLauncher.getDeviceProfile().isVerticalBarLayout();
+    }
+
+    private void setScrimProgress(float progress) {
+        if (mScrimProgress != progress) {
+            mScrimProgress = progress;
+            mScrimAlpha = Math.round(255 * mScrimProgress);
+            invalidate();
+        }
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View view) {
+        mWallpaperColorInfo.addOnChangeListener(this);
+        onExtractedColorsChanged(mWallpaperColorInfo);
+
+        if (mHasSysUiScrim) {
+            IntentFilter filter = new IntentFilter(ACTION_SCREEN_OFF);
+            filter.addAction(ACTION_USER_PRESENT); // When the device wakes up + keyguard is gone
+            mRoot.getContext().registerReceiver(mReceiver, filter);
+        }
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View view) {
+        mWallpaperColorInfo.removeOnChangeListener(this);
+        if (mHasSysUiScrim) {
+            mRoot.getContext().unregisterReceiver(mReceiver);
+        }
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+        // for super light wallpaper it needs to be darken for contrast to workspace
+        // for dark wallpapers the text is white so darkening works as well
+        mBottomMaskPaint.setColor(ColorUtils.compositeColors(DARK_SCRIM_COLOR,
+                wallpaperColorInfo.getMainColor()));
+        reapplySysUiAlpha();
+        mFullScrimColor = wallpaperColorInfo.getMainColor();
+        if (mScrimAlpha > 0) {
+            invalidate();
+        }
+    }
+
+    public void setSize(int w, int h) {
+        if (mHasSysUiScrim) {
+            mTopScrim.setBounds(0, 0, w, h);
+            mFinalMaskRect.set(0, h - mMaskHeight, w, h);
+        }
+    }
+
+    public void hideSysUiScrim(boolean hideSysUiScrim) {
+        mHideSysUiScrim = hideSysUiScrim;
+        if (!hideSysUiScrim) {
+            mAnimateScrimOnNextDraw = true;
+        }
+        invalidate();
+    }
+
+    private void setSysUiProgress(float progress) {
+        if (progress != mSysUiProgress) {
+            mSysUiProgress = progress;
+            reapplySysUiAlpha();
+        }
+    }
+
+    private void reapplySysUiAlpha() {
+        if (mHasSysUiScrim) {
+            reapplySysUiAlphaNoInvalidate();
+            if (!mHideSysUiScrim) {
+                invalidate();
+            }
+        }
+    }
+
+    private void reapplySysUiAlphaNoInvalidate() {
+        float factor = mSysUiProgress * mSysUiAnimMultiplier;
+        mBottomMaskPaint.setAlpha(Math.round(MAX_HOTSEAT_SCRIM_ALPHA * factor));
+        mTopScrim.setAlpha(Math.round(255 * factor));
+    }
+
+    public void invalidate() {
+        mRoot.invalidate();
+    }
+
+    public Bitmap createDitheredAlphaMask() {
+        DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics();
+        int width = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
+        int gradientHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
+        Bitmap dst = Bitmap.createBitmap(width, mMaskHeight, Bitmap.Config.ALPHA_8);
+        Canvas c = new Canvas(dst);
+        Paint paint = new Paint(Paint.DITHER_FLAG);
+        LinearGradient lg = new LinearGradient(0, 0, 0, gradientHeight,
+                new int[]{
+                        0x00FFFFFF,
+                        ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)),
+                        0xFFFFFFFF},
+                new float[]{0f, 0.8f, 1f},
+                Shader.TileMode.CLAMP);
+        paint.setShader(lg);
+        c.drawRect(0, 0, width, gradientHeight, paint);
+        return dst;
+    }
+}
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index c07ab08..c50189c 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -236,4 +236,19 @@
             }
         }
     }
+
+    /**
+     * Simple subclass which assumes that the target view is a child of the container.
+     */
+    public static class SimpleFocusIndicatorHelper extends FocusIndicatorHelper {
+
+        public SimpleFocusIndicatorHelper(View container) {
+            super(container);
+        }
+
+        @Override
+        public void viewToRect(View v, Rect outRect) {
+            outRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+        }
+    }
 }
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
index 9c80b0f..05ae406 100644
--- a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -17,13 +17,14 @@
 package com.android.launcher3.keyboard;
 
 import android.graphics.Canvas;
-import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.ItemDecoration;
 import android.support.v7.widget.RecyclerView.State;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 
+import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
+
 /**
  * {@link ItemDecoration} for drawing and animating focused view background.
  */
@@ -32,13 +33,7 @@
     private FocusIndicatorHelper mHelper;
 
     public FocusedItemDecorator(View container) {
-        mHelper = new FocusIndicatorHelper(container) {
-
-            @Override
-            public void viewToRect(View v, Rect outRect) {
-                outRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
-            }
-        };
+        mHelper = new SimpleFocusIndicatorHelper(container);
     }
 
     public OnFocusChangeListener getFocusListener() {
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
index bd5c06e..fde220c 100644
--- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Rect;
 import android.view.View;
-import android.view.View.OnFocusChangeListener;
 
 import com.android.launcher3.PagedView;
 
@@ -52,8 +51,8 @@
 
     private void computeLocationRelativeToContainer(View child, Rect outRect) {
         View parent = (View) child.getParent();
-        outRect.left += child.getLeft();
-        outRect.top += child.getTop();
+        outRect.left += child.getX();
+        outRect.top += child.getY();
 
         if (parent != mContainer) {
             if (parent instanceof PagedView) {
@@ -64,22 +63,4 @@
             computeLocationRelativeToContainer(parent, outRect);
         }
     }
-
-    /**
-     * Sets the alpha of this FocusIndicatorHelper to 0 when a view with this listener
-     * receives focus.
-     */
-    public View.OnFocusChangeListener getHideIndicatorOnFocusListener() {
-        return new OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (hasFocus) {
-                    endCurrentAnimation();
-                    setCurrentView(null);
-                    setAlpha(0);
-                    invalidateDirty();
-                }
-            }
-        };
-    }
 }
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 00ee009..1c4327c 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -15,16 +15,15 @@
  */
 package com.android.launcher3.logging;
 
+import android.content.Context;
 import android.util.ArrayMap;
 import android.util.SparseArray;
 import android.view.View;
 
+import com.android.launcher3.AppInfo;
 import com.android.launcher3.ButtonDropTarget;
-import com.android.launcher3.DeleteDropTarget;
-import com.android.launcher3.InfoDropTarget;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.UninstallDropTarget;
 import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -32,6 +31,8 @@
 import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
+import com.android.launcher3.util.InstantAppResolver;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -71,12 +72,12 @@
         switch (action.type) {
             case Action.Type.TOUCH:
                 str += getFieldName(action.touch, Action.Touch.class);
-                if (action.touch == Action.Touch.SWIPE) {
+                if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING) {
                     str += " direction=" + getFieldName(action.dir, Action.Direction.class);
                 }
                 return str;
             case Action.Type.COMMAND: return getFieldName(action.command, Action.Command.class);
-            default: return UNKNOWN;
+            default: return getFieldName(action.type, Action.Type.class);
         }
     }
 
@@ -84,23 +85,32 @@
         if (t == null){
             return "";
         }
+        String str = "";
         switch (t.type) {
             case Target.Type.ITEM:
-                return getItemStr(t);
+                str = getItemStr(t);
+                break;
             case Target.Type.CONTROL:
-                return getFieldName(t.controlType, ControlType.class);
+                str = getFieldName(t.controlType, ControlType.class);
+                break;
             case Target.Type.CONTAINER:
-                String str = getFieldName(t.containerType, ContainerType.class);
+                str = getFieldName(t.containerType, ContainerType.class);
                 if (t.containerType == ContainerType.WORKSPACE ||
                         t.containerType == ContainerType.HOTSEAT) {
                     str += " id=" + t.pageIndex;
                 } else if (t.containerType == ContainerType.FOLDER) {
                     str += " grid(" + t.gridX + "," + t.gridY+ ")";
                 }
-                return str;
+                break;
             default:
-                return "UNKNOWN TARGET TYPE";
+                str += "UNKNOWN TARGET TYPE";
         }
+
+        if (t.tipType != TipType.DEFAULT_NONE) {
+            str += " " + getFieldName(t.tipType, TipType.class);
+        }
+
+        return str;
     }
 
     private static String getItemStr(Target t) {
@@ -114,25 +124,40 @@
         if (t.intentHash != 0) {
             typeStr += ", intentHash=" + t.intentHash;
         }
-        if (t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0) {
-            typeStr += ", predictiveRank=" + t.predictedRank;
+        if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0) &&
+                t.itemType != ItemType.TASK) {
+            typeStr += ", predictiveRank=" + t.predictedRank + ", grid(" + t.gridX + "," + t.gridY
+                    + "), span(" + t.spanX + "," + t.spanY
+                    + "), pageIdx=" + t.pageIndex;
+
         }
-        return typeStr + ", grid(" + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY
-                + "), pageIdx=" + t.pageIndex;
+        if (t.itemType == ItemType.TASK) {
+            typeStr += ", pageIdx=" + t.pageIndex;
+        }
+        return typeStr;
     }
 
-    public static Target newItemTarget(View v) {
-        return (v.getTag() instanceof ItemInfo)
-                ? newItemTarget((ItemInfo) v.getTag())
+    public static Target newItemTarget(int itemType) {
+        Target t = newTarget(Target.Type.ITEM);
+        t.itemType = itemType;
+        return t;
+    }
+
+    public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
+        return (v != null) && (v.getTag() instanceof ItemInfo)
+                ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver)
                 : newTarget(Target.Type.ITEM);
     }
 
-    public static Target newItemTarget(ItemInfo info) {
+    public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
         Target t = newTarget(Target.Type.ITEM);
 
         switch (info.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                t.itemType = ItemType.APP_ICON;
+                t.itemType = (instantAppResolver != null && info instanceof AppInfo
+                        && instantAppResolver.isInstantApp(((AppInfo) info)) )
+                        ? ItemType.WEB_APP
+                        : ItemType.APP_ICON;
                 t.predictedRank = -100; // Never assigned
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
@@ -155,15 +180,10 @@
         if (!(v instanceof ButtonDropTarget)) {
             return newTarget(Target.Type.CONTAINER);
         }
-        Target t = newTarget(Target.Type.CONTROL);
-        if (v instanceof InfoDropTarget) {
-            t.controlType = ControlType.APPINFO_TARGET;
-        } else if (v instanceof UninstallDropTarget) {
-            t.controlType = ControlType.UNINSTALL_TARGET;
-        } else if (v instanceof DeleteDropTarget) {
-            t.controlType = ControlType.REMOVE_TARGET;
+        if (v instanceof ButtonDropTarget) {
+            return ((ButtonDropTarget) v).getDropTargetForLogging();
         }
-        return t;
+        return newTarget(Target.Type.CONTROL);
     }
 
     public static Target newTarget(int targetType, TargetExtension extension) {
@@ -178,6 +198,13 @@
         t.type = targetType;
         return t;
     }
+
+    public static Target newControlTarget(int controlType) {
+        Target t = newTarget(Target.Type.CONTROL);
+        t.controlType = controlType;
+        return t;
+    }
+
     public static Target newContainerTarget(int containerType) {
         Target t = newTarget(Target.Type.CONTAINER);
         t.containerType = containerType;
@@ -189,11 +216,13 @@
         a.type = type;
         return a;
     }
+
     public static Action newCommandAction(int command) {
         Action a = newAction(Action.Type.COMMAND);
         a.command = command;
         return a;
     }
+
     public static Action newTouchAction(int touch) {
         Action a = newAction(Action.Type.TOUCH);
         a.touch = touch;
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 243dbea..7087fdb 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -16,6 +16,16 @@
 
 package com.android.launcher3.logging;
 
+import static com.android.launcher3.logging.LoggerUtils.newAction;
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newControlTarget;
+import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+import static com.android.launcher3.logging.LoggerUtils.newTarget;
+import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
+
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -32,30 +42,26 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.LogConfig;
+import com.android.launcher3.util.ResourceBasedOverride;
 
 import java.util.Locale;
 import java.util.UUID;
 
-import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
-import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-import static com.android.launcher3.logging.LoggerUtils.newTarget;
-import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
-
 /**
  * Manages the creation of {@link LauncherEvent}.
  * To debug this class, execute following command before side loading a new apk.
  *
  * $ adb shell setprop log.tag.UserEvent VERBOSE
  */
-public class UserEventDispatcher {
+public class UserEventDispatcher implements ResourceBasedOverride {
 
     private final static int MAXIMUM_VIEW_HIERARCHY_LEVEL = 5;
 
@@ -64,22 +70,30 @@
             FeatureFlags.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
     private static final String UUID_STORAGE = "uuid";
 
-    public static UserEventDispatcher newInstance(Context context, boolean isInLandscapeMode,
-            boolean isInMultiWindowMode) {
+    public static UserEventDispatcher newInstance(Context context,
+            UserEventDelegate delegate) {
         SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
         String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
         if (uuidStr == null) {
             uuidStr = UUID.randomUUID().toString();
             sharedPrefs.edit().putString(UUID_STORAGE, uuidStr).apply();
         }
-        UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
+        UserEventDispatcher ued = Overrides.getObject(UserEventDispatcher.class,
                 context.getApplicationContext(), R.string.user_event_dispatcher_class);
-        ued.mIsInLandscapeMode = isInLandscapeMode;
-        ued.mIsInMultiWindowMode = isInMultiWindowMode;
+        ued.mDelegate = delegate;
         ued.mUuidStr = uuidStr;
+        ued.mInstantAppResolver = InstantAppResolver.newInstance(context);
         return ued;
     }
 
+    public static UserEventDispatcher newInstance(Context context) {
+        return newInstance(context, null);
+    }
+
+    public interface UserEventDelegate {
+        void modifyUserEvent(LauncherEvent event);
+    }
+
     /**
      * Implemented by containers to provide a container source for a given child.
      */
@@ -119,12 +133,14 @@
         return null;
     }
 
+    private boolean mSessionStarted;
     private long mElapsedContainerMillis;
     private long mElapsedSessionMillis;
     private long mActionDurationMillis;
-    private boolean mIsInMultiWindowMode;
-    private boolean mIsInLandscapeMode;
     private String mUuidStr;
+    protected InstantAppResolver mInstantAppResolver;
+    private boolean mAppOrTaskLaunch;
+    private UserEventDelegate mDelegate;
 
     //                      APP_ICON    SHORTCUT    WIDGET
     // --------------------------------------------------------------
@@ -150,17 +166,41 @@
 
     public void logAppLaunch(View v, Intent intent) {
         LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
-                newItemTarget(v), newTarget(Target.Type.CONTAINER));
+                newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
 
         if (fillInLogContainerData(event, v)) {
+            if (mDelegate != null) {
+                mDelegate.modifyUserEvent(event);
+            }
             fillIntentInfo(event.srcTarget[0], intent);
         }
         dispatchUserEvent(event, intent);
+        mAppOrTaskLaunch = true;
+    }
+
+    public void logActionTip(int actionType, int viewType) { }
+
+    public void logTaskLaunchOrDismiss(int action, int direction, int taskIndex,
+            ComponentKey componentKey) {
+        LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE or FLING
+                newTarget(Target.Type.ITEM));
+        if (action == Action.Touch.SWIPE || action == Action.Touch.FLING) {
+            // Direction DOWN means the task was launched, UP means it was dismissed.
+            event.action.dir = direction;
+        }
+        event.srcTarget[0].itemType = LauncherLogProto.ItemType.TASK;
+        event.srcTarget[0].pageIndex = taskIndex;
+        fillComponentInfo(event.srcTarget[0], componentKey.componentName);
+        dispatchUserEvent(event, null);
+        mAppOrTaskLaunch = true;
     }
 
     protected void fillIntentInfo(Target target, Intent intent) {
         target.intentHash = intent.hashCode();
-        ComponentName cn = intent.getComponent();
+        fillComponentInfo(target, intent.getComponent());
+    }
+
+    private void fillComponentInfo(Target target, ComponentName cn) {
         if (cn != null) {
             target.packageNameHash = (mUuidStr + cn.getPackageName()).hashCode();
             target.componentHash = (mUuidStr + cn.flattenToString()).hashCode();
@@ -169,49 +209,92 @@
 
     public void logNotificationLaunch(View v, PendingIntent intent) {
         LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
-                newItemTarget(v), newTarget(Target.Type.CONTAINER));
+                newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
         if (fillInLogContainerData(event, v)) {
             event.srcTarget[0].packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode();
         }
         dispatchUserEvent(event, null);
     }
 
-    public void logActionCommand(int command, int containerType) {
-        logActionCommand(command, newContainerTarget(containerType));
+    public void logActionCommand(int command, Target srcTarget) {
+        logActionCommand(command, srcTarget, null);
     }
 
-    public void logActionCommand(int command, Target target) {
-        LauncherEvent event = newLauncherEvent(newCommandAction(command), target);
+    public void logActionCommand(int command, int srcContainerType, int dstContainerType) {
+        logActionCommand(command, newContainerTarget(srcContainerType),
+                dstContainerType >=0 ? newContainerTarget(dstContainerType) : null);
+    }
+
+    public void logActionCommand(int command, Target srcTarget, Target dstTarget) {
+        LauncherEvent event = newLauncherEvent(newCommandAction(command), srcTarget);
+        if (command == Action.Command.STOP) {
+            if (mAppOrTaskLaunch || !mSessionStarted) {
+                mSessionStarted = false;
+                return;
+            }
+        }
+
+        if (dstTarget != null) {
+            event.destTarget = new Target[1];
+            event.destTarget[0] = dstTarget;
+            event.action.isStateChange = true;
+        }
         dispatchUserEvent(event, null);
     }
 
     /**
      * TODO: Make this function work when a container view is passed as the 2nd param.
      */
-    public void logActionCommand(int command, View itemView, int containerType) {
+    public void logActionCommand(int command, View itemView, int srcContainerType) {
         LauncherEvent event = newLauncherEvent(newCommandAction(command),
-                newItemTarget(itemView), newTarget(Target.Type.CONTAINER));
+                newItemTarget(itemView, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
 
         if (fillInLogContainerData(event, itemView)) {
             // TODO: Remove the following two lines once fillInLogContainerData can take in a
             // container view.
             event.srcTarget[0].type = Target.Type.CONTAINER;
-            event.srcTarget[0].containerType = containerType;
+            event.srcTarget[0].containerType = srcContainerType;
         }
         dispatchUserEvent(event, null);
     }
 
     public void logActionOnControl(int action, int controlType) {
-        logActionOnControl(action, controlType, null);
+        logActionOnControl(action, controlType, null, -1);
+    }
+
+    public void logActionOnControl(int action, int controlType, int parentContainerType) {
+        logActionOnControl(action, controlType, null, parentContainerType);
     }
 
     public void logActionOnControl(int action, int controlType, @Nullable View controlInContainer) {
-        final LauncherEvent event = controlInContainer == null
+        logActionOnControl(action, controlType, controlInContainer, -1);
+    }
+
+    public void logActionOnControl(int action, int controlType, int parentContainer,
+                                   int grandParentContainer){
+        LauncherEvent event = newLauncherEvent(newTouchAction(action),
+                newControlTarget(controlType),
+                newContainerTarget(parentContainer),
+                newContainerTarget(grandParentContainer));
+        dispatchUserEvent(event, null);
+    }
+
+    public void logActionOnControl(int action, int controlType, @Nullable View controlInContainer,
+                                   int parentContainerType) {
+        final LauncherEvent event = (controlInContainer == null && parentContainerType < 0)
                 ? newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL))
                 : newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL),
                         newTarget(Target.Type.CONTAINER));
         event.srcTarget[0].controlType = controlType;
-        fillInLogContainerData(event, controlInContainer);
+        if (controlInContainer != null) {
+            fillInLogContainerData(event, controlInContainer);
+        }
+        if (parentContainerType >= 0) {
+            event.srcTarget[1].containerType = parentContainerType;
+        }
+        if (action == Action.Touch.DRAGDROP) {
+            event.actionDurationMillis = SystemClock.uptimeMillis() - mActionDurationMillis;
+        }
         dispatchUserEvent(event, null);
     }
 
@@ -222,6 +305,13 @@
         dispatchUserEvent(event, null);
     }
 
+    public void logActionBounceTip(int containerType) {
+        LauncherEvent event = newLauncherEvent(newAction(Action.Type.TIP),
+                newContainerTarget(containerType));
+        event.srcTarget[0].tipType = LauncherLogProto.TipType.BOUNCE;
+        dispatchUserEvent(event, null);
+    }
+
     public void logActionOnContainer(int action, int dir, int containerType) {
         logActionOnContainer(action, dir, containerType, 0);
     }
@@ -232,10 +322,35 @@
         event.action.dir = dir;
         event.srcTarget[0].pageIndex = pageIndex;
         dispatchUserEvent(event, null);
+    }
 
-        if (action == Action.Touch.SWIPE) {
-            resetElapsedContainerMillis();
+    /**
+     * Used primarily for swipe up and down when state changes when swipe up happens from the
+     * navbar bezel, the {@param srcChildContainerType} is NAVBAR and
+     * {@param srcParentContainerType} is either one of the two
+     * (1) WORKSPACE: if the launcher is the foreground activity
+     * (2) APP: if another app was the foreground activity
+     */
+    public void logStateChangeAction(int action, int dir, int srcChildTargetType,
+                                     int srcParentContainerType, int dstContainerType,
+                                     int pageIndex) {
+        LauncherEvent event;
+        if (srcChildTargetType == LauncherLogProto.ItemType.TASK) {
+            event = newLauncherEvent(newTouchAction(action),
+                    newItemTarget(srcChildTargetType),
+                    newContainerTarget(srcParentContainerType));
+        } else {
+            event = newLauncherEvent(newTouchAction(action),
+                    newContainerTarget(srcChildTargetType),
+                    newContainerTarget(srcParentContainerType));
         }
+        event.destTarget = new Target[1];
+        event.destTarget[0] = newContainerTarget(dstContainerType);
+        event.action.dir = dir;
+        event.action.isStateChange = true;
+        event.srcTarget[0].pageIndex = pageIndex;
+        dispatchUserEvent(event, null);
+        resetElapsedContainerMillis("state changed");
     }
 
     public void logActionOnItem(int action, int dir, int itemType) {
@@ -253,11 +368,11 @@
         }
         ItemInfo info = (ItemInfo) icon.getTag();
         LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.LONGPRESS),
-                newItemTarget(info), newTarget(Target.Type.CONTAINER));
+                newItemTarget(info, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
         provider.fillInLogContainerData(icon, info, event.srcTarget[0], event.srcTarget[1]);
         dispatchUserEvent(event, null);
 
-        resetElapsedContainerMillis();
+        resetElapsedContainerMillis("deep shortcut open");
     }
 
     /* Currently we are only interested in whether this event happens or not and don't
@@ -271,9 +386,11 @@
 
     public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
         LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP),
-                newItemTarget(dragObj.originalDragInfo), newTarget(Target.Type.CONTAINER));
+                newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
+                newTarget(Target.Type.CONTAINER));
         event.destTarget = new Target[] {
-                newItemTarget(dragObj.originalDragInfo), newDropTarget(dropTargetAsView)
+                newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
+                newDropTarget(dropTargetAsView)
         };
 
         dragObj.dragSource.fillInLogContainerData(null, dragObj.originalDragInfo,
@@ -290,12 +407,19 @@
 
     /**
      * Currently logs following containers: workspace, allapps, widget tray.
+     * @param reason
      */
-    public final void resetElapsedContainerMillis() {
+    public final void resetElapsedContainerMillis(String reason) {
         mElapsedContainerMillis = SystemClock.uptimeMillis();
+        if (!IS_VERBOSE) {
+            return;
+        }
+        Log.d(TAG, "resetElapsedContainerMillis reason=" + reason);
+
     }
 
-    public final void resetElapsedSessionMillis() {
+    public final void startSession() {
+        mSessionStarted = true;
         mElapsedSessionMillis = SystemClock.uptimeMillis();
         mElapsedContainerMillis = SystemClock.uptimeMillis();
     }
@@ -305,15 +429,15 @@
     }
 
     public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
-        ev.isInLandscapeMode = mIsInLandscapeMode;
-        ev.isInMultiWindowMode = mIsInMultiWindowMode;
+        mAppOrTaskLaunch = false;
         ev.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
         ev.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
 
         if (!IS_VERBOSE) {
             return;
         }
-        String log = "action:" + LoggerUtils.getActionStr(ev.action);
+        String log = "\n-----------------------------------------------------"
+                + "\naction:" + LoggerUtils.getActionStr(ev.action);
         if (ev.srcTarget != null && ev.srcTarget.length > 0) {
             log += "\n Source " + getTargetsStr(ev.srcTarget);
         }
@@ -321,13 +445,11 @@
             log += "\n Destination " + getTargetsStr(ev.destTarget);
         }
         log += String.format(Locale.US,
-                "\n Elapsed container %d ms session %d ms action %d ms",
+                "\n Elapsed container %d ms, session %d ms, action %d ms",
                 ev.elapsedContainerMillis,
                 ev.elapsedSessionMillis,
                 ev.actionDurationMillis);
-        log += "\n isInLandscapeMode " + ev.isInLandscapeMode;
-        log += "\n isInMultiWindowMode " + ev.isInMultiWindowMode;
-        log += "\n";
+        log += "\n\n";
         Log.d(TAG, log);
     }
 
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index a33a039..fefe07d 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -17,10 +17,7 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.LauncherActivityInfo;
-import android.os.Process;
 import android.os.UserHandle;
-import android.util.ArrayMap;
 import android.util.LongSparseArray;
 import android.util.Pair;
 import com.android.launcher3.AllAppsList;
@@ -37,7 +34,6 @@
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.GridOccupancy;
-import com.android.launcher3.util.ManagedProfileHeuristic.UserFolderInfo;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -64,7 +60,6 @@
 
         final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
         final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<>();
-        ArrayMap<UserHandle, UserFolderInfo> userFolderMap = new ArrayMap<>();
 
         // Get the list of workspace screens.  We need to append to this list and
         // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
@@ -87,21 +82,6 @@
                     if (item instanceof AppInfo) {
                         item = ((AppInfo) item).makeShortcut();
                     }
-
-                    if (!Process.myUserHandle().equals(item.user)) {
-                        // Check if this belongs to a work folder.
-                        if (!(entry.second instanceof LauncherActivityInfo)) {
-                            continue;
-                        }
-
-                        UserFolderInfo userFolderInfo = userFolderMap.get(item.user);
-                        if (userFolderInfo == null) {
-                            userFolderInfo = new UserFolderInfo(context, item.user, dataModel);
-                            userFolderMap.put(item.user, userFolderInfo);
-                        }
-                        item = userFolderInfo.convertToWorkspaceItem(
-                                (ShortcutInfo) item, (LauncherActivityInfo) entry.second);
-                    }
                 }
                 if (item != null) {
                     filteredItems.add(item);
@@ -160,10 +140,6 @@
                 }
             });
         }
-
-        for (UserFolderInfo userFolderInfo : userFolderMap.values()) {
-            userFolderInfo.applyPendingState(getModelWriter());
-        }
     }
 
     protected void updateScreens(Context context, ArrayList<Long> workspaceScreens) {
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index 9aa30e7..fcdc088 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -29,7 +29,6 @@
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.widget.WidgetListRowEntry;
-import com.android.launcher3.widget.WidgetsListAdapter;
 
 import java.util.ArrayList;
 import java.util.concurrent.Executor;
@@ -80,19 +79,18 @@
      */
     public final void scheduleCallbackTask(final CallbackTask task) {
         final Callbacks callbacks = mModel.getCallback();
-        mUiExecutor.execute(new Runnable() {
-            public void run() {
-                Callbacks cb = mModel.getCallback();
-                if (callbacks == cb && cb != null) {
-                    task.execute(callbacks);
-                }
+        mUiExecutor.execute(() -> {
+            Callbacks cb = mModel.getCallback();
+            if (callbacks == cb && cb != null) {
+                task.execute(callbacks);
             }
         });
     }
 
     public ModelWriter getModelWriter() {
-        // Updates from model task, do not deal with icon position in hotseat.
-        return mModel.getWriter(false /* hasVerticalHotseat */);
+        // Updates from model task, do not deal with icon position in hotseat. Also no need to
+        // verify changes as the ModelTasks always push the changes to callbacks
+        return mModel.getWriter(false /* hasVerticalHotseat */, false /* verifyChanges */);
     }
 
 
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 8640401..fff1e69 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -106,6 +106,11 @@
     public final WidgetsModel widgetsModel = new WidgetsModel();
 
     /**
+     * Id when the model was last bound
+     */
+    public int lastBindId = 0;
+
+    /**
      * Clears all the data
      */
     public synchronized void clear() {
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
new file mode 100644
index 0000000..1149b55
--- /dev/null
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 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.model;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.util.Log;
+
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.util.MultiHashMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Helper class to send broadcasts to package installers that have:
+ * - Items on the first screen
+ * - Items with an active install session
+ *
+ * The packages are broken down by: folder items, workspace items, hotseat items, and widgets.
+ *
+ * Package installers only receive data for items that they are installing.
+ */
+public class FirstScreenBroadcast {
+
+    private static final String TAG = "FirstScreenBroadcast";
+    private static final boolean DEBUG = false;
+
+    private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
+            = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
+
+    private static final String FOLDER_ITEM_EXTRA = "folderItem";
+    private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
+    private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
+    private static final String WIDGET_ITEM_EXTRA = "widgetItem";
+
+    private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken";
+
+    private final MultiHashMap<String, String> mPackagesForInstaller;
+
+    public FirstScreenBroadcast(HashMap<String, SessionInfo> sessionInfoForPackage) {
+        mPackagesForInstaller = getPackagesForInstaller(sessionInfoForPackage);
+    }
+
+    /**
+     * @return Map where the key is the package name of the installer, and the value is a list
+     *         of packages with active sessions for that installer.
+     */
+    private MultiHashMap<String, String> getPackagesForInstaller(
+            HashMap<String, SessionInfo> sessionInfoForPackage) {
+        MultiHashMap<String, String> packagesForInstaller = new MultiHashMap<>();
+        for (Map.Entry<String, SessionInfo> entry : sessionInfoForPackage.entrySet()) {
+            packagesForInstaller.addToList(entry.getValue().getInstallerPackageName(),
+                    entry.getKey());
+        }
+        return packagesForInstaller;
+    }
+
+    /**
+     * Sends a broadcast to all package installers that have items with active sessions on the users
+     * first screen.
+     */
+    public void sendBroadcasts(Context context, List<ItemInfo> firstScreenItems) {
+        for (Map.Entry<String, ArrayList<String>> entry : mPackagesForInstaller.entrySet()) {
+            sendBroadcastToInstaller(context, entry.getKey(), entry.getValue(), firstScreenItems);
+        }
+    }
+
+    /**
+     * @param installerPackageName Package name of the package installer.
+     * @param packages List of packages with active sessions for this package installer.
+     * @param firstScreenItems List of items on the first screen.
+     */
+    private void sendBroadcastToInstaller(Context context, String installerPackageName,
+            List<String> packages, List<ItemInfo> firstScreenItems) {
+        Set<String> folderItems = new HashSet<>();
+        Set<String> workspaceItems = new HashSet<>();
+        Set<String> hotseatItems = new HashSet<>();
+        Set<String> widgetItems = new HashSet<>();
+
+        for (ItemInfo info : firstScreenItems) {
+            if (info instanceof FolderInfo) {
+                FolderInfo folderInfo = (FolderInfo) info;
+                String folderItemInfoPackage;
+                for (ItemInfo folderItemInfo : folderInfo.contents) {
+                    folderItemInfoPackage = getPackageName(folderItemInfo);
+                    if (folderItemInfoPackage != null
+                            && packages.contains(folderItemInfoPackage)) {
+                        folderItems.add(folderItemInfoPackage);
+                    }
+                }
+            }
+
+            String packageName = getPackageName(info);
+            if (packageName == null || !packages.contains(packageName)) {
+                continue;
+            }
+            if (info instanceof LauncherAppWidgetInfo) {
+                widgetItems.add(packageName);
+            } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+                hotseatItems.add(packageName);
+            } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                workspaceItems.add(packageName);
+            }
+        }
+
+        if (DEBUG) {
+            printList(installerPackageName, "Folder item", folderItems);
+            printList(installerPackageName, "Workspace item", workspaceItems);
+            printList(installerPackageName, "Hotseat item", hotseatItems);
+            printList(installerPackageName, "Widget item", widgetItems);
+        }
+
+        context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
+                .setPackage(installerPackageName)
+                .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
+                .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
+                .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
+                .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
+                .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0,
+                        new Intent(), PendingIntent.FLAG_ONE_SHOT)));
+    }
+
+    private static String getPackageName(ItemInfo info) {
+        String packageName = null;
+        if (info instanceof LauncherAppWidgetInfo) {
+            LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
+            if (widgetInfo.providerName != null) {
+                packageName = widgetInfo.providerName.getPackageName();
+            }
+        } else if (info.getTargetComponent() != null){
+            packageName = info.getTargetComponent().getPackageName();
+        }
+        return packageName;
+    }
+
+    private static void printList(String packageInstaller, String label, Set<String> packages) {
+        for (String pkg : packages) {
+            Log.d(TAG, packageInstaller + ":" + label + ":" + pkg);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java
index 24e5b9c..0fd9b73 100644
--- a/src/com/android/launcher3/model/LoaderResults.java
+++ b/src/com/android/launcher3/model/LoaderResults.java
@@ -25,7 +25,6 @@
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetInfo;
-import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherModel.Callbacks;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.MainThreadExecutor;
@@ -37,7 +36,6 @@
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.ViewOnDrawExecutor;
 import com.android.launcher3.widget.WidgetListRowEntry;
-import com.android.launcher3.widget.WidgetsListAdapter;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -100,6 +98,7 @@
             workspaceItems.addAll(mBgDataModel.workspaceItems);
             appWidgets.addAll(mBgDataModel.appWidgets);
             orderedScreenIds.addAll(mBgDataModel.workspaceScreens);
+            mBgDataModel.lastBindId++;
         }
 
         final int currentScreen;
@@ -162,7 +161,7 @@
         // This ensures that the first screen is immediately visible (eg. during rotation)
         // In case of !validFirstPage, bind all pages one after other.
         final Executor deferredExecutor =
-                validFirstPage ? new ViewOnDrawExecutor(mUiExecutor) : mainExecutor;
+                validFirstPage ? new ViewOnDrawExecutor() : mainExecutor;
 
         mainExecutor.execute(new Runnable() {
             @Override
@@ -210,7 +209,7 @@
 
     /** Filters the set of items who are directly or indirectly (via another container) on the
      * specified screen. */
-    private <T extends ItemInfo> void filterCurrentWorkspaceItems(long currentScreenId,
+    public static <T extends ItemInfo> void filterCurrentWorkspaceItems(long currentScreenId,
             ArrayList<T> allWorkspaceItems,
             ArrayList<T> currentScreenItems,
             ArrayList<T> otherScreenItems) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 00dd3aa..e82c8f1 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -16,6 +16,12 @@
 
 package com.android.launcher3.model;
 
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.model.LoaderResults.filterCurrentWorkspaceItems;
+
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -24,8 +30,8 @@
 import android.content.IntentFilter;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
 import android.graphics.Bitmap;
-import android.graphics.drawable.AdaptiveIconDrawable;
 import android.os.Handler;
 import android.os.Process;
 import android.os.UserHandle;
@@ -36,7 +42,6 @@
 
 import com.android.launcher3.AllAppsList;
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.ClickShadowView;
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.IconCache;
 import com.android.launcher3.InstallShortcutReceiver;
@@ -62,7 +67,6 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.LooperIdleLock;
-import com.android.launcher3.util.ManagedProfileHeuristic;
 import com.android.launcher3.util.MultiHashMap;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Provider;
@@ -76,11 +80,6 @@
 import java.util.Map;
 import java.util.concurrent.CancellationException;
 
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
-import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
-
 /**
  * Runnable for the thread that loads the contents of the launcher:
  *   - workspace icons
@@ -95,6 +94,8 @@
     private final AllAppsList mBgAllAppsList;
     private final BgDataModel mBgDataModel;
 
+    private FirstScreenBroadcast mFirstScreenBroadcast;
+
     private final LoaderResults mResults;
 
     private final LauncherAppsCompat mLauncherApps;
@@ -137,6 +138,22 @@
         }
     }
 
+    private void sendFirstScreenActiveInstallsBroadcast() {
+        ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
+
+        ArrayList<ItemInfo> allItems = new ArrayList<>();
+        synchronized (mBgDataModel) {
+            allItems.addAll(mBgDataModel.workspaceItems);
+            allItems.addAll(mBgDataModel.appWidgets);
+        }
+        long firstScreen = mBgDataModel.workspaceScreens.isEmpty()
+                ? -1 // In this case, we can still look at the items in the hotseat.
+                : mBgDataModel.workspaceScreens.get(0);
+        filterCurrentWorkspaceItems(firstScreen, allItems, firstScreenItems,
+                new ArrayList<>() /* otherScreenItems are ignored */);
+        mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
+    }
+
     public void run() {
         synchronized (this) {
             // Skip fast if we are already stopped.
@@ -147,15 +164,17 @@
 
         TraceHelper.beginSection(TAG);
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
-            TraceHelper.partitionSection(TAG, "step 1.1: loading UI resources");
-            loadUiResources();
-            TraceHelper.partitionSection(TAG, "step 1.2: loading workspace");
+            TraceHelper.partitionSection(TAG, "step 1.1: loading workspace");
             loadWorkspace();
 
             verifyNotStopped();
             TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
             mResults.bindWorkspace();
 
+            // Notify the installer packages of packages with active installs on the first screen.
+            TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast");
+            sendFirstScreenActiveInstallsBroadcast();
+
             // Take a break
             TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
             waitForIdle();
@@ -212,15 +231,6 @@
         this.notify();
     }
 
-    public void loadUiResources() {
-        if (Utilities.ATLEAST_OREO) {
-            LauncherIcons li = LauncherIcons.obtain(mApp.getContext());
-            ClickShadowView.setAdaptiveIconScaleFactor(li.getNormalizer()
-                    .getScale(new AdaptiveIconDrawable(null, null), null, null, null));
-            li.recycle();
-        }
-    }
-
     private void loadWorkspace() {
         final Context context = mApp.getContext();
         final ContentResolver contentResolver = context.getContentResolver();
@@ -256,8 +266,9 @@
         synchronized (mBgDataModel) {
             mBgDataModel.clear();
 
-            final HashMap<String, Integer> installingPkgs =
+            final HashMap<String, SessionInfo> installingPkgs =
                     mPackageInstaller.updateAndGetActiveSessionCache();
+            mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
             mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));
 
             Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
@@ -467,15 +478,11 @@
                                     }
                                     info = new ShortcutInfo(pinnedShortcut, context);
                                     final ShortcutInfo finalInfo = info;
-                                    Provider<Bitmap> fallbackIconProvider = new Provider<Bitmap>() {
-                                        @Override
-                                        public Bitmap get() {
-                                            // If the pinned deep shortcut is no longer published,
-                                            // use the last saved icon instead of the default.
-                                            return c.loadIcon(finalInfo)
-                                                    ? finalInfo.iconBitmap : null;
-                                        }
-                                    };
+                                    // If the pinned deep shortcut is no longer published,
+                                    // use the last saved icon instead of the default.
+                                    Provider<Bitmap> fallbackIconProvider = () ->
+                                            c.loadIcon(finalInfo) ? finalInfo.iconBitmap : null;
+
                                     LauncherIcons li = LauncherIcons.obtain(context);
                                     li.createShortcutIcon(pinnedShortcut,
                                             true /* badged */, fallbackIconProvider).applyTo(info);
@@ -525,11 +532,11 @@
                                 }
 
                                 if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
-                                    Integer progress = installingPkgs.get(targetPkg);
-                                    if (progress != null) {
-                                        info.setInstallProgress(progress);
-                                    } else {
+                                    SessionInfo si = installingPkgs.get(targetPkg);
+                                    if (si == null) {
                                         info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+                                    } else {
+                                        info.setInstallProgress((int) (si.getProgress() * 100));
                                     }
                                 }
 
@@ -619,7 +626,11 @@
                                     appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
                                             component);
                                     appWidgetInfo.restoreStatus = c.restoreFlag;
-                                    Integer installProgress = installingPkgs.get(component.getPackageName());
+                                    SessionInfo si =
+                                            installingPkgs.get(component.getPackageName());
+                                    Integer installProgress = si == null
+                                            ? null
+                                            : (int) (si.getProgress() * 100);
 
                                     if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
                                         // Restore has started once.
@@ -812,8 +823,6 @@
                 // This builds the icon bitmaps.
                 mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
             }
-
-            ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user);
         }
 
         if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 032ed78..eba7515 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -21,17 +21,21 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherModel.Callbacks;
 import com.android.launcher3.LauncherProvider;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.LauncherSettings.Settings;
 import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LooperExecutor;
@@ -48,15 +52,23 @@
     private static final String TAG = "ModelWriter";
 
     private final Context mContext;
+    private final LauncherModel mModel;
     private final BgDataModel mBgDataModel;
+    private final Handler mUiHandler;
+
     private final Executor mWorkerExecutor;
     private final boolean mHasVerticalHotseat;
+    private final boolean mVerifyChanges;
 
-    public ModelWriter(Context context, BgDataModel dataModel, boolean hasVerticalHotseat) {
+    public ModelWriter(Context context, LauncherModel model, BgDataModel dataModel,
+            boolean hasVerticalHotseat, boolean verifyChanges) {
         mContext = context;
+        mModel = model;
         mBgDataModel = dataModel;
         mWorkerExecutor = new LooperExecutor(LauncherModel.getWorkerLooper());
         mHasVerticalHotseat = hasVerticalHotseat;
+        mVerifyChanges = verifyChanges;
+        mUiHandler = new Handler(Looper.getMainLooper());
     }
 
     private void updateItemInfoProps(
@@ -212,15 +224,16 @@
         item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getLong(Settings.EXTRA_VALUE);
         writer.put(Favorites._ID, item.id);
 
-        final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
-        mWorkerExecutor.execute(new Runnable() {
-            public void run() {
-                cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext));
+        ModelVerifier verifier = new ModelVerifier();
 
-                synchronized (mBgDataModel) {
-                    checkItemInfoLocked(item.id, item, stackTrace);
-                    mBgDataModel.addItem(mContext, item, true);
-                }
+        final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+        mWorkerExecutor.execute(() -> {
+            cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext));
+
+            synchronized (mBgDataModel) {
+                checkItemInfoLocked(item.id, item, stackTrace);
+                mBgDataModel.addItem(mContext, item, true);
+                verifier.verifyModel();
             }
         });
     }
@@ -243,14 +256,15 @@
      * Removes the specified items from the database
      */
     public void deleteItemsFromDatabase(final Iterable<? extends ItemInfo> items) {
-        mWorkerExecutor.execute(new Runnable() {
-            public void run() {
-                for (ItemInfo item : items) {
-                    final Uri uri = Favorites.getContentUri(item.id);
-                    mContext.getContentResolver().delete(uri, null, null);
+        ModelVerifier verifier = new ModelVerifier();
 
-                    mBgDataModel.removeItem(mContext, item);
-                }
+        mWorkerExecutor.execute(() -> {
+            for (ItemInfo item : items) {
+                final Uri uri = Favorites.getContentUri(item.id);
+                mContext.getContentResolver().delete(uri, null, null);
+
+                mBgDataModel.removeItem(mContext, item);
+                verifier.verifyModel();
             }
         });
     }
@@ -259,17 +273,18 @@
      * Remove the specified folder and all its contents from the database.
      */
     public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
-        mWorkerExecutor.execute(new Runnable() {
-            public void run() {
-                ContentResolver cr = mContext.getContentResolver();
-                cr.delete(LauncherSettings.Favorites.CONTENT_URI,
-                        LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
-                mBgDataModel.removeItem(mContext, info.contents);
-                info.contents.clear();
+        ModelVerifier verifier = new ModelVerifier();
 
-                cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
-                mBgDataModel.removeItem(mContext, info);
-            }
+        mWorkerExecutor.execute(() -> {
+            ContentResolver cr = mContext.getContentResolver();
+            cr.delete(LauncherSettings.Favorites.CONTENT_URI,
+                    LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
+            mBgDataModel.removeItem(mContext, info.contents);
+            info.contents.clear();
+
+            cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
+            mBgDataModel.removeItem(mContext, info);
+            verifier.verifyModel();
         });
     }
 
@@ -324,6 +339,7 @@
 
     private abstract class UpdateItemBaseRunnable implements Runnable {
         private final StackTraceElement[] mStackTrace;
+        private final ModelVerifier mVerifier = new ModelVerifier();
 
         UpdateItemBaseRunnable() {
             mStackTrace = new Throwable().getStackTrace();
@@ -368,7 +384,45 @@
                 } else {
                     mBgDataModel.workspaceItems.remove(modelItem);
                 }
+                mVerifier.verifyModel();
             }
         }
     }
+
+    /**
+     * Utility class to verify model updates are propagated properly to the callback.
+     */
+    public class ModelVerifier {
+
+        final int startId;
+
+        ModelVerifier() {
+            startId = mBgDataModel.lastBindId;
+        }
+
+        void verifyModel() {
+            if (!mVerifyChanges || mModel.getCallback() == null) {
+                return;
+            }
+
+            int executeId = mBgDataModel.lastBindId;
+
+            mUiHandler.post(() -> {
+                int currentId = mBgDataModel.lastBindId;
+                if (currentId > executeId) {
+                    // Model was already bound after job was executed.
+                    return;
+                }
+                if (executeId == startId) {
+                    // Bound model has not changed during the job
+                    return;
+                }
+                // Bound model was changed between submitting the job and executing the job
+                Callbacks callbacks = mModel.getCallback();
+                if (callbacks != null) {
+                    callbacks.rebindModel();
+                }
+            });
+        }
+    }
 }
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 089303e..977dcd7 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -18,7 +18,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -42,6 +41,9 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.BitmapInfo;
 import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutInfoCompat;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LongArrayMap;
@@ -52,6 +54,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * Handles updates due to changes in package manager (app installed/updated/removed)
@@ -162,12 +165,7 @@
 
         final ArrayMap<ComponentName, AppInfo> addedOrUpdatedApps = new ArrayMap<>();
         if (!addedOrModified.isEmpty()) {
-            scheduleCallbackTask(new CallbackTask() {
-                @Override
-                public void execute(Callbacks callbacks) {
-                    callbacks.bindAppsAddedOrUpdated(addedOrModified);
-                }
-            });
+            scheduleCallbackTask((callbacks) -> callbacks.bindAppsAddedOrUpdated(addedOrModified));
             for (AppInfo ai : addedOrModified) {
                 addedOrUpdatedApps.put(ai.componentName, ai);
             }
@@ -213,11 +211,26 @@
                             }
 
                             if (si.isPromise() && isNewApkAvailable) {
+                                boolean isTargetValid = true;
+                                if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                                    List<ShortcutInfoCompat> shortcut = DeepShortcutManager
+                                            .getInstance(context).queryForPinnedShortcuts(
+                                                    cn.getPackageName(),
+                                                    Arrays.asList(si.getDeepShortcutId()), mUser);
+                                    if (shortcut.isEmpty()) {
+                                        isTargetValid = false;
+                                    } else {
+                                        si.updateFromDeepShortcutInfo(shortcut.get(0), context);
+                                        infoUpdated = true;
+                                    }
+                                } else if (!cn.getClassName().equals(IconCache.EMPTY_CLASS_NAME)) {
+                                    isTargetValid = LauncherAppsCompat.getInstance(context)
+                                            .isActivityEnabledForProfile(cn, mUser);
+                                }
+
                                 if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINSTALL_ICON)) {
                                     // Auto install icon
-                                    LauncherAppsCompat launcherApps
-                                            = LauncherAppsCompat.getInstance(context);
-                                    if (!launcherApps.isActivityEnabledForProfile(cn, mUser)) {
+                                    if (!isTargetValid) {
                                         // Try to find the best match activity.
                                         Intent intent = new PackageManagerHelper(context)
                                                 .getAppLaunchIntent(cn.getPackageName(), mUser);
@@ -235,6 +248,11 @@
                                             continue;
                                         }
                                     }
+                                } else if (!isTargetValid) {
+                                    removedShortcuts.put(si.id, true);
+                                    FileLog.e(TAG, "Restored shortcut no longer valid "
+                                            + si.intent);
+                                    continue;
                                 } else {
                                     si.status = ShortcutInfo.DEFAULT;
                                     infoUpdated = true;
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 1ff0dac..9f8f263 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -1,6 +1,8 @@
 
 package com.android.launcher3.model;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
+
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -153,6 +155,11 @@
         // add and update.
         for (WidgetItem item : rawWidgetsShortcuts) {
             if (item.widgetInfo != null) {
+                if ((item.widgetInfo.getWidgetFeatures() & WIDGET_FEATURE_HIDE_FROM_PICKER) != 0) {
+                    // Widget is hidden from picker
+                    continue;
+                }
+
                 // Ensure that all widgets we show can be added on a workspace of this size
                 int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX);
                 int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY);
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 2fefa85..32410a6 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.support.annotation.Nullable;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -83,7 +82,7 @@
 
     public void addGutter() {
         if (mGutter == null) {
-            mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter);
+            mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter, mContainer);
         }
     }
 
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 114b2b8..ac5aaf8 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.notification;
 
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
 import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -43,8 +45,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
-
 /**
  * A {@link NotificationListenerService} that sends updates to its
  * {@link NotificationsChangedListener} when notifications are posted or canceled,
@@ -71,6 +71,11 @@
     private final Ranking mTempRanking = new Ranking();
     /** Maps groupKey's to the corresponding group of notifications. */
     private final Map<String, NotificationGroup> mNotificationGroupMap = new HashMap<>();
+    /** Maps keys to their corresponding current group key */
+    private final Map<String, String> mNotificationGroupKeyMap = new HashMap<>();
+
+    /** The last notification key that was dismissed from launcher UI */
+    private String mLastKeyDismissedByLauncher;
 
     private SettingsObserver mNotificationBadgingObserver;
 
@@ -145,22 +150,12 @@
     public void onCreate() {
         super.onCreate();
         sIsCreated = true;
-        mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
-            @Override
-            public void onSettingChanged(boolean isNotificationBadgingEnabled) {
-                if (!isNotificationBadgingEnabled) {
-                    requestUnbind();
-                }
-            }
-        };
-        mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
         sIsCreated = false;
-        mNotificationBadgingObserver.unregister();
     }
 
     public static @Nullable NotificationListener getInstanceIfConnected() {
@@ -198,6 +193,17 @@
     public void onListenerConnected() {
         super.onListenerConnected();
         sIsConnected = true;
+
+        mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
+            @Override
+            public void onSettingChanged(boolean isNotificationBadgingEnabled) {
+                if (!isNotificationBadgingEnabled && sIsConnected) {
+                    requestUnbind();
+                }
+            }
+        };
+        mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+
         onNotificationFullRefresh();
     }
 
@@ -209,11 +215,16 @@
     public void onListenerDisconnected() {
         super.onListenerDisconnected();
         sIsConnected = false;
+        mNotificationBadgingObserver.unregister();
     }
 
     @Override
     public void onNotificationPosted(final StatusBarNotification sbn) {
         super.onNotificationPosted(sbn);
+        if (sbn == null) {
+            // There is a bug in platform where we can get a null notification; just ignore it.
+            return;
+        }
         mWorkerHandler.obtainMessage(MSG_NOTIFICATION_POSTED, new NotificationPostedMsg(sbn))
             .sendToTarget();
         if (sStatusBarNotificationsChangedListener != null) {
@@ -239,6 +250,10 @@
     @Override
     public void onNotificationRemoved(final StatusBarNotification sbn) {
         super.onNotificationRemoved(sbn);
+        if (sbn == null) {
+            // There is a bug in platform where we can get a null notification; just ignore it.
+            return;
+        }
         Pair<PackageUserKey, NotificationKeyData> packageUserKeyAndNotificationKey
             = new Pair<>(PackageUserKey.fromNotification(sbn),
             NotificationKeyData.fromNotification(sbn));
@@ -249,13 +264,67 @@
         }
 
         NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
+        String key = sbn.getKey();
         if (notificationGroup != null) {
-            notificationGroup.removeChildKey(sbn.getKey());
+            notificationGroup.removeChildKey(key);
             if (notificationGroup.isEmpty()) {
-                cancelNotification(notificationGroup.getGroupSummaryKey());
+                if (key.equals(mLastKeyDismissedByLauncher)) {
+                    // Only cancel the group notification if launcher dismissed the last child.
+                    cancelNotification(notificationGroup.getGroupSummaryKey());
+                }
                 mNotificationGroupMap.remove(sbn.getGroupKey());
             }
         }
+        if (key.equals(mLastKeyDismissedByLauncher)) {
+            mLastKeyDismissedByLauncher = null;
+        }
+    }
+
+    public void cancelNotificationFromLauncher(String key) {
+        mLastKeyDismissedByLauncher = key;
+        cancelNotification(key);
+    }
+
+    @Override
+    public void onNotificationRankingUpdate(RankingMap rankingMap) {
+        super.onNotificationRankingUpdate(rankingMap);
+        String[] keys = rankingMap.getOrderedKeys();
+        for (StatusBarNotification sbn : getActiveNotifications(keys)) {
+            updateGroupKeyIfNecessary(sbn);
+        }
+    }
+
+    private void updateGroupKeyIfNecessary(StatusBarNotification sbn) {
+        String childKey = sbn.getKey();
+        String oldGroupKey = mNotificationGroupKeyMap.get(childKey);
+        String newGroupKey = sbn.getGroupKey();
+        if (oldGroupKey == null || !oldGroupKey.equals(newGroupKey)) {
+            // The group key has changed.
+            mNotificationGroupKeyMap.put(childKey, newGroupKey);
+            if (oldGroupKey != null && mNotificationGroupMap.containsKey(oldGroupKey)) {
+                // Remove the child key from the old group.
+                NotificationGroup oldGroup = mNotificationGroupMap.get(oldGroupKey);
+                oldGroup.removeChildKey(childKey);
+                if (oldGroup.isEmpty()) {
+                    mNotificationGroupMap.remove(oldGroupKey);
+                }
+            }
+        }
+        if (sbn.isGroup() && newGroupKey != null) {
+            // Maintain group info so we can cancel the summary when the last child is canceled.
+            NotificationGroup notificationGroup = mNotificationGroupMap.get(newGroupKey);
+            if (notificationGroup == null) {
+                notificationGroup = new NotificationGroup();
+                mNotificationGroupMap.put(newGroupKey, notificationGroup);
+            }
+            boolean isGroupSummary = (sbn.getNotification().flags
+                    & Notification.FLAG_GROUP_SUMMARY) != 0;
+            if (isGroupSummary) {
+                notificationGroup.setGroupSummaryKey(childKey);
+            } else {
+                notificationGroup.addChildKey(childKey);
+            }
+        }
     }
 
     /** This makes a potentially expensive binder call and should be run on a background thread. */
@@ -295,20 +364,7 @@
     private boolean shouldBeFilteredOut(StatusBarNotification sbn) {
         Notification notification = sbn.getNotification();
 
-        boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
-        if (sbn.isGroup()) {
-            // Maintain group info so we can cancel the summary when the last child is canceled.
-            NotificationGroup notificationGroup = mNotificationGroupMap.get(sbn.getGroupKey());
-            if (notificationGroup == null) {
-                notificationGroup = new NotificationGroup();
-                mNotificationGroupMap.put(sbn.getGroupKey(), notificationGroup);
-            }
-            if (isGroupHeader) {
-                notificationGroup.setGroupSummaryKey(sbn.getKey());
-            } else {
-                notificationGroup.addChildKey(sbn.getKey());
-            }
-        }
+        updateGroupKeyIfNecessary(sbn);
 
         getCurrentRanking().getRanking(sbn.getKey(), mTempRanking);
         if (!mTempRanking.canShowBadge()) {
@@ -324,6 +380,7 @@
         CharSequence title = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
         CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
         boolean missingTitleAndText = TextUtils.isEmpty(title) && TextUtils.isEmpty(text);
+        boolean isGroupHeader = (notification.flags & Notification.FLAG_GROUP_SUMMARY) != 0;
         return (isGroupHeader || missingTitleAndText);
     }
 
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
index 33caded..5c0e259 100644
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ b/src/com/android/launcher3/notification/NotificationMainView.java
@@ -116,6 +116,10 @@
      */
     public void applyNotificationInfo(NotificationInfo mainNotification, boolean animate) {
         mNotificationInfo = mainNotification;
+        NotificationListener listener = NotificationListener.getInstanceIfConnected();
+        if (listener != null) {
+            listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey});
+        }
         CharSequence title = mNotificationInfo.title;
         CharSequence text = mNotificationInfo.text;
         if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(text)) {
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 3ce7291..8fafb6f 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -25,6 +25,4 @@
     void setActiveMarker(int activePage);
 
     void setMarkersCount(int numMarkers);
-
-    void setPageDescription(CharSequence description);
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 524ec3c..709975f 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -228,11 +228,6 @@
     }
 
     @Override
-    public void setPageDescription(CharSequence description) {
-        setContentDescription(description);
-    }
-
-    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Add extra spacing of mDotRadius on all sides so than entry animation could be run.
         int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 4fc7d8a..654e593 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -1,9 +1,5 @@
 package com.android.launcher3.pageindicators;
 
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -20,9 +16,7 @@
 import android.util.Property;
 import android.view.Gravity;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
 import com.android.launcher3.DeviceProfile;
@@ -30,19 +24,14 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
 
 /**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages in
- * portrait mode. In Landscape simply draws the caret drawable bottom-corner aligned in
- * the drag-layer.
+ * A PageIndicator that briefly shows a fraction of a line when moving between pages
  *
  * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
  */
-public class WorkspacePageIndicator extends View
-        implements Insettable, OnClickListener, PageIndicator {
+public class WorkspacePageIndicator extends View implements Insettable, PageIndicator {
 
     private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
     private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -52,12 +41,12 @@
     private static final int LINE_ALPHA_ANIMATOR_INDEX = 0;
     private static final int NUM_PAGES_ANIMATOR_INDEX = 1;
     private static final int TOTAL_SCROLL_ANIMATOR_INDEX = 2;
+    private static final int ANIMATOR_COUNT = 3;
 
-    private ValueAnimator[] mAnimators = new ValueAnimator[3];
+    private ValueAnimator[] mAnimators = new ValueAnimator[ANIMATOR_COUNT];
 
     private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
     private final Launcher mLauncher;
-    private final AccessibilityManager mAccessibilityManager;
 
     private boolean mShouldAutoHide = true;
 
@@ -72,8 +61,6 @@
     private Paint mLinePaint;
     private final int mLineHeight;
 
-    private boolean mIsLandscapeUi;
-
     private static final Property<WorkspacePageIndicator, Integer> PAINT_ALPHA
             = new Property<WorkspacePageIndicator, Integer>(Integer.class, "paint_alpha") {
         @Override
@@ -84,7 +71,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Integer alpha) {
             obj.mLinePaint.setAlpha(alpha);
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -98,7 +85,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Float numPages) {
             obj.mNumPagesFloat = numPages;
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -112,7 +99,7 @@
         @Override
         public void set(WorkspacePageIndicator obj, Integer totalScroll) {
             obj.mTotalScroll = totalScroll;
-            obj.invalidateIfPortrait();
+            obj.invalidate();
         }
     };
 
@@ -139,24 +126,23 @@
         boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
         mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
         mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
-        mAccessibilityManager = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
-        if (mTotalScroll == 0 || mNumPagesFloat == 0 || mIsLandscapeUi) {
+        if (mTotalScroll == 0 || mNumPagesFloat == 0) {
             return;
         }
 
         // Compute and draw line rect.
         float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
-        int availableWidth = canvas.getWidth();
+        int availableWidth = getWidth();
         int lineWidth = (int) (availableWidth / mNumPagesFloat);
         int lineLeft = (int) (progress * (availableWidth - lineWidth));
         int lineRight = lineLeft + lineWidth;
-        canvas.drawRect(lineLeft, canvas.getHeight() - mLineHeight, lineRight, canvas.getHeight(),
-                mLinePaint);
+
+        canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight,
+                getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
     }
 
     @Override
@@ -172,7 +158,7 @@
         } else if (mTotalScroll != totalScroll) {
             animateToTotalScroll(totalScroll);
         } else {
-            invalidateIfPortrait();
+            invalidate();
         }
 
         if (mShouldAutoHide) {
@@ -191,15 +177,16 @@
     @Override
     public void setMarkersCount(int numMarkers) {
         if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
-            animateToNumPages(numMarkers);
+            setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers),
+                    NUM_PAGES_ANIMATOR_INDEX);
+        } else {
+            if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) {
+                mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel();
+                mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null;
+            }
         }
     }
 
-    @Override
-    public void setPageDescription(CharSequence description) {
-        setContentDescription(description);
-    }
-
     public void setShouldAutoHide(boolean shouldAutoHide) {
         mShouldAutoHide = shouldAutoHide;
         if (shouldAutoHide && mLinePaint.getAlpha() > 0) {
@@ -219,11 +206,6 @@
                 LINE_ALPHA_ANIMATOR_INDEX);
     }
 
-    private void animateToNumPages(int numPages) {
-        setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages),
-                NUM_PAGES_ANIMATOR_INDEX);
-    }
-
     private void animateToTotalScroll(int totalScroll) {
         setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
                 TOTAL_SCROLL_ANIMATOR_INDEX);
@@ -251,57 +233,43 @@
         mAnimators[animatorIndex].start();
     }
 
+    /**
+     * Pauses all currently running animations.
+     */
+    public void pauseAnimations() {
+        for (int i = 0; i < ANIMATOR_COUNT; i++) {
+            if (mAnimators[i] != null) {
+                mAnimators[i].pause();
+            }
+        }
+    }
+
+    /**
+     * Force-ends all currently running or paused animations.
+     */
+    public void skipAnimationsToEnd() {
+        for (int i = 0; i < ANIMATOR_COUNT; i++) {
+            if (mAnimators[i] != null) {
+                mAnimators[i].end();
+            }
+        }
+    }
+
     @Override
     public void setInsets(Rect insets) {
         DeviceProfile grid = mLauncher.getDeviceProfile();
-        mIsLandscapeUi = grid.isVerticalBarLayout();
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
 
-        if (mIsLandscapeUi) {
-            if (grid.isSeascape()) {
-                lp.leftMargin = grid.hotseatBarSidePaddingPx;
-                lp.rightMargin = insets.right;
-                lp.gravity =  Gravity.RIGHT | Gravity.BOTTOM;
-            } else {
-                lp.leftMargin = insets.left;
-                lp.rightMargin = grid.hotseatBarSidePaddingPx;
-                lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
-            }
-            lp.bottomMargin = grid.workspacePadding.bottom;
-            lp.width = lp.height = getResources()
-                    .getDimensionPixelSize(R.dimen.dynamic_grid_min_page_indicator_size);
-
-            setBackgroundResource(R.drawable.all_apps_handle_landscape);
-            setOnFocusChangeListener(mLauncher.mFocusHandler);
-            setOnClickListener(this);
-
+        if (grid.isVerticalBarLayout()) {
+            Rect padding = grid.workspacePadding;
+            lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
+            lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
+            lp.bottomMargin = padding.bottom;
         } else {
             lp.leftMargin = lp.rightMargin = 0;
             lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
-            lp.height = grid.pageIndicatorSizePx;
             lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
-            lp.width = MATCH_PARENT;
-
-            setBackgroundResource(0);
-            setOnFocusChangeListener(null);
-            setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null);
         }
-
         setLayoutParams(lp);
     }
-
-    private void invalidateIfPortrait() {
-        if (!mIsLandscapeUi) {
-            invalidate();
-        }
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (!mLauncher.isInState(ALL_APPS)) {
-            mLauncher.getUserEventDispatcher().logActionOnControl(
-                    Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
-            mLauncher.getStateManager().goToState(ALL_APPS);
-        }
-    }
 }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
new file mode 100644
index 0000000..e157482
--- /dev/null
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2018 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.popup;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.CornerPathEffect;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.RevealOutlineAnimation;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.TriangleShape;
+import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.BaseDragLayer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * A container for shortcuts to deep links and notifications associated with an app.
+ */
+public abstract class ArrowPopup extends AbstractFloatingView {
+
+    private final Rect mTempRect = new Rect();
+
+    protected final LayoutInflater mInflater;
+    private final float mOutlineRadius;
+    protected final Launcher mLauncher;
+    protected final boolean mIsRtl;
+
+    private final int mArrayOffset;
+    private final View mArrow;
+
+    protected boolean mIsLeftAligned;
+    protected boolean mIsAboveIcon;
+    private int mGravity;
+
+    protected Animator mOpenCloseAnimator;
+    protected boolean mDeferContainerRemoval;
+    private final Rect mStartRect = new Rect();
+    private final Rect mEndRect = new Rect();
+
+    public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mInflater = LayoutInflater.from(context);
+        mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
+        mLauncher = Launcher.getLauncher(context);
+        mIsRtl = Utilities.isRtl(getResources());
+
+        setClipToOutline(true);
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
+            }
+        });
+
+        // Initialize arrow view
+        final Resources resources = getResources();
+        final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
+        final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
+        mArrow = new View(context);
+        mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
+        mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
+    }
+
+    public ArrowPopup(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ArrowPopup(Context context) {
+        this(context, null, 0);
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        if (animate) {
+            animateClose();
+        } else {
+            closeComplete();
+        }
+    }
+
+    public <T extends View> T inflateAndAdd(int resId, ViewGroup container) {
+        View view = mInflater.inflate(resId, container, false);
+        container.addView(view);
+        return (T) view;
+    }
+
+    /**
+     * Called when all view inflation and reordering in complete.
+     */
+    protected void onInflationComplete(boolean isReversed) { }
+
+    /**
+     * Shows the popup at the desired location, optionally reversing the children.
+     * @param viewsToFlip number of views from the top to to flip in case of reverse order
+     */
+    protected void reorderAndShow(int viewsToFlip) {
+        setVisibility(View.INVISIBLE);
+        mIsOpen = true;
+        getPopupContainer().addView(this);
+        orientAboutObject();
+
+        boolean reverseOrder = mIsAboveIcon;
+        if (reverseOrder) {
+            int count = getChildCount();
+            ArrayList<View> allViews = new ArrayList<>(count);
+            for (int i = 0; i < count; i++) {
+                if (i == viewsToFlip) {
+                    Collections.reverse(allViews);
+                }
+                allViews.add(getChildAt(i));
+            }
+            Collections.reverse(allViews);
+            removeAllViews();
+            for (int i = 0; i < count; i++) {
+                addView(allViews.get(i));
+            }
+
+            orientAboutObject();
+        }
+        onInflationComplete(reverseOrder);
+
+        // Add the arrow.
+        final Resources res = getResources();
+        final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
+                ? R.dimen.popup_arrow_horizontal_center_start
+                : R.dimen.popup_arrow_horizontal_center_end);
+        final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
+        getPopupContainer().addView(mArrow);
+        DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
+        if (mIsLeftAligned) {
+            mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
+        } else {
+            mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
+        }
+
+        if (Gravity.isVertical(mGravity)) {
+            // This is only true if there wasn't room for the container next to the icon,
+            // so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
+            mArrow.setVisibility(INVISIBLE);
+        } else {
+            ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
+                    arrowLp.width, arrowLp.height, !mIsAboveIcon));
+            Paint arrowPaint = arrowDrawable.getPaint();
+            arrowPaint.setColor(Themes.getAttrColor(getContext(), R.attr.popupColorPrimary));
+            // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+            int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
+            arrowPaint.setPathEffect(new CornerPathEffect(radius));
+            mArrow.setBackground(arrowDrawable);
+            mArrow.setElevation(getElevation());
+        }
+
+        mArrow.setPivotX(arrowLp.width / 2);
+        mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height);
+
+        animateOpen();
+    }
+
+    protected boolean isAlignedWithStart() {
+        return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl;
+    }
+
+    /**
+     * Provide the location of the target object relative to the dragLayer.
+     */
+    protected abstract void getTargetObjectLocation(Rect outPos);
+
+    /**
+     * Orients this container above or below the given icon, aligning with the left or right.
+     *
+     * These are the preferred orientations, in order (RTL prefers right-aligned over left):
+     * - Above and left-aligned
+     * - Above and right-aligned
+     * - Below and left-aligned
+     * - Below and right-aligned
+     *
+     * So we always align left if there is enough horizontal space
+     * and align above if there is enough vertical space.
+     */
+    protected void orientAboutObject() {
+        measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+        int width = getMeasuredWidth();
+        int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset
+                + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+        int height = getMeasuredHeight() + extraVerticalSpace;
+
+        getTargetObjectLocation(mTempRect);
+        InsettableFrameLayout dragLayer = getPopupContainer();
+        Rect insets = dragLayer.getInsets();
+
+        // Align left (right in RTL) if there is room.
+        int leftAlignedX = mTempRect.left;
+        int rightAlignedX = mTempRect.right - width;
+        int x = leftAlignedX;
+        boolean canBeLeftAligned = leftAlignedX + width + insets.left
+                < dragLayer.getRight() - insets.right;
+        boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
+        if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {
+            x = rightAlignedX;
+        }
+        mIsLeftAligned = x == leftAlignedX;
+
+        // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
+        int iconWidth = mTempRect.width();
+        Resources resources = getResources();
+        int xOffset;
+        if (isAlignedWithStart()) {
+            // Aligning with the shortcut icon.
+            int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);
+            int shortcutPaddingStart = resources.getDimensionPixelSize(
+                    R.dimen.popup_padding_start);
+            xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;
+        } else {
+            // Aligning with the drag handle.
+            int shortcutDragHandleWidth = resources.getDimensionPixelSize(
+                    R.dimen.deep_shortcut_drag_handle_size);
+            int shortcutPaddingEnd = resources.getDimensionPixelSize(
+                    R.dimen.popup_padding_end);
+            xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;
+        }
+        x += mIsLeftAligned ? xOffset : -xOffset;
+
+        // Open above icon if there is room.
+        int iconHeight = mTempRect.height();
+        int y = mTempRect.top - height;
+        mIsAboveIcon = y > dragLayer.getTop() + insets.top;
+        if (!mIsAboveIcon) {
+            y = mTempRect.top + iconHeight + extraVerticalSpace;
+        }
+
+        // Insets are added later, so subtract them now.
+        x -= insets.left;
+        y -= insets.top;
+
+        mGravity = 0;
+        if (y + height > dragLayer.getBottom() - insets.bottom) {
+            // The container is opening off the screen, so just center it in the drag layer instead.
+            mGravity = Gravity.CENTER_VERTICAL;
+            // Put the container next to the icon, preferring the right side in ltr (left in rtl).
+            int rightSide = leftAlignedX + iconWidth - insets.left;
+            int leftSide = rightAlignedX - iconWidth - insets.left;
+            if (!mIsRtl) {
+                if (rightSide + width < dragLayer.getRight()) {
+                    x = rightSide;
+                    mIsLeftAligned = true;
+                } else {
+                    x = leftSide;
+                    mIsLeftAligned = false;
+                }
+            } else {
+                if (leftSide > dragLayer.getLeft()) {
+                    x = leftSide;
+                    mIsLeftAligned = false;
+                } else {
+                    x = rightSide;
+                    mIsLeftAligned = true;
+                }
+            }
+            mIsAboveIcon = true;
+        }
+
+        setX(x);
+        if (Gravity.isVertical(mGravity)) {
+            return;
+        }
+
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        FrameLayout.LayoutParams arrowLp = (FrameLayout.LayoutParams) mArrow.getLayoutParams();
+        if (mIsAboveIcon) {
+            arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
+            lp.bottomMargin = getPopupContainer().getHeight() - y - getMeasuredHeight() - insets.top;
+            arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom;
+        } else {
+            arrowLp.gravity = lp.gravity = Gravity.TOP;
+            lp.topMargin = y + insets.top;
+            arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset;
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+
+        // enforce contained is within screen
+        ViewGroup dragLayer = getPopupContainer();
+        if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) {
+            // If we are still off screen, center horizontally too.
+            mGravity |= Gravity.CENTER_HORIZONTAL;
+        }
+
+        if (Gravity.isHorizontal(mGravity)) {
+            setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
+            mArrow.setVisibility(INVISIBLE);
+        }
+        if (Gravity.isVertical(mGravity)) {
+            setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
+        }
+    }
+
+    private void animateOpen() {
+        setVisibility(View.VISIBLE);
+
+        final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+        final Resources res = getResources();
+        final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+
+        // Rectangular reveal.
+        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+                .createRevealAnimator(this, false);
+        revealAnim.setDuration(revealDuration);
+        revealAnim.setInterpolator(revealInterpolator);
+
+        Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
+        fadeIn.setDuration(revealDuration);
+        fadeIn.setInterpolator(revealInterpolator);
+        openAnim.play(fadeIn);
+
+        // Animate the arrow.
+        mArrow.setScaleX(0);
+        mArrow.setScaleY(0);
+        Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
+                .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration));
+
+        openAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                announceAccessibilityChanges();
+                mOpenCloseAnimator = null;
+            }
+        });
+
+        mOpenCloseAnimator = openAnim;
+        openAnim.playSequentially(revealAnim, arrowScale);
+        openAnim.start();
+    }
+
+    protected void animateClose() {
+        if (!mIsOpen) {
+            return;
+        }
+        mEndRect.setEmpty();
+        if (getOutlineProvider() instanceof RevealOutlineAnimation) {
+            ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
+        }
+        if (mOpenCloseAnimator != null) {
+            mOpenCloseAnimator.cancel();
+        }
+        mIsOpen = false;
+
+        final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
+        // Hide the arrow
+        closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
+        closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
+
+        final Resources res = getResources();
+        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+
+        // Rectangular reveal (reversed).
+        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+                .createRevealAnimator(this, true);
+        revealAnim.setInterpolator(revealInterpolator);
+        closeAnim.play(revealAnim);
+
+        Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+        fadeOut.setInterpolator(revealInterpolator);
+        closeAnim.play(fadeOut);
+
+        onCreateCloseAnimation(closeAnim);
+        closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
+        closeAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mOpenCloseAnimator = null;
+                if (mDeferContainerRemoval) {
+                    setVisibility(INVISIBLE);
+                } else {
+                    closeComplete();
+                }
+            }
+        });
+        mOpenCloseAnimator = closeAnim;
+        closeAnim.start();
+    }
+
+    /**
+     * Called when creating the close transition allowing subclass can add additional animations.
+     */
+    protected void onCreateCloseAnimation(AnimatorSet anim) { }
+
+    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
+        int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
+                R.dimen.popup_arrow_horizontal_center_start:
+                R.dimen.popup_arrow_horizontal_center_end);
+        if (!mIsLeftAligned) {
+            arrowCenterX = getMeasuredWidth() - arrowCenterX;
+        }
+        int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
+
+        mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY);
+        if (mEndRect.isEmpty()) {
+            mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+        }
+
+        return new RoundedRectRevealOutlineProvider
+                (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect);
+    }
+
+    /**
+     * Closes the popup without animation.
+     */
+    protected void closeComplete() {
+        if (mOpenCloseAnimator != null) {
+            mOpenCloseAnimator.cancel();
+            mOpenCloseAnimator = null;
+        }
+        mIsOpen = false;
+        mDeferContainerRemoval = false;
+        getPopupContainer().removeView(this);
+        getPopupContainer().removeView(mArrow);
+    }
+
+    protected BaseDragLayer getPopupContainer() {
+        return mLauncher.getDragLayer();
+    }
+}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index b3ef7bb..635e043 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,36 +16,29 @@
 
 package com.android.launcher3.popup;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
 import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.CornerPathEffect;
-import android.graphics.Outline;
-import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.drawable.ShapeDrawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateDecelerateInterpolator;
 import android.widget.ImageView;
 
 import com.android.launcher3.AbstractFloatingView;
@@ -56,20 +49,14 @@
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.ItemInfoWithIcon;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
-import com.android.launcher3.anim.RevealOutlineAnimation;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.badge.BadgeInfo;
 import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.graphics.TriangleShape;
 import com.android.launcher3.logging.LoggerUtils;
 import com.android.launcher3.notification.NotificationInfo;
 import com.android.launcher3.notification.NotificationItemView;
@@ -77,86 +64,42 @@
 import com.android.launcher3.shortcuts.DeepShortcutManager;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-
 /**
  * A container for shortcuts to deep links and notifications associated with an app.
  */
 @TargetApi(Build.VERSION_CODES.N)
-public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource,
+public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
         DragController.DragListener, View.OnLongClickListener,
         View.OnTouchListener {
 
     private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
     private final PointF mInterceptTouchDown = new PointF();
-    private final Rect mTempRect = new Rect();
     private final Point mIconLastTouchPos = new Point();
 
     private final int mStartDragThreshold;
-    private final LayoutInflater mInflater;
-    private final float mOutlineRadius;
-    private final Launcher mLauncher;
     private final LauncherAccessibilityDelegate mAccessibilityDelegate;
-    private final boolean mIsRtl;
-
-    private final int mArrayOffset;
-    private final View mArrow;
 
     private BubbleTextView mOriginalIcon;
     private NotificationItemView mNotificationItemView;
+    private int mNumNotifications;
 
     private ViewGroup mSystemShortcutContainer;
 
-    private boolean mIsLeftAligned;
-    protected boolean mIsAboveIcon;
-    private int mNumNotifications;
-    private int mGravity;
-
-    protected Animator mOpenCloseAnimator;
-    protected boolean mDeferContainerRemoval;
-    private final Rect mStartRect = new Rect();
-    private final Rect mEndRect = new Rect();
-
     public PopupContainerWithArrow(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mStartDragThreshold = getResources().getDimensionPixelSize(
                 R.dimen.deep_shortcuts_start_drag_threshold);
-        mInflater = LayoutInflater.from(context);
-        mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
-        mLauncher = Launcher.getLauncher(context);
         mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
-        mIsRtl = Utilities.isRtl(getResources());
-
-        setClipToOutline(true);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
-            }
-        });
-
-        // Initialize arrow view
-        final Resources resources = getResources();
-        final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
-        final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
-        mArrow = new View(context);
-        mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
-        mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
     }
 
     public PopupContainerWithArrow(Context context, AttributeSet attrs) {
@@ -188,7 +131,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (mNotificationItemView != null) {
-            return mNotificationItemView.onTouchEvent(ev);
+            return mNotificationItemView.onTouchEvent(ev) || super.onTouchEvent(ev);
         }
         return super.onTouchEvent(ev);
     }
@@ -204,10 +147,14 @@
                 command, mOriginalIcon, ContainerType.DEEPSHORTCUTS);
     }
 
+    public OnClickListener getItemClickListener() {
+        return ItemClickHandler.INSTANCE;
+    }
+
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            DragLayer dl = mLauncher.getDragLayer();
+            BaseDragLayer dl = getPopupContainer();
             if (!dl.isEventOverView(this, ev)) {
                 mLauncher.getUserEventDispatcher().logActionTapOutside(
                         LoggerUtils.newContainerTarget(ContainerType.DEEPSHORTCUTS));
@@ -221,21 +168,6 @@
         return false;
     }
 
-    @Override
-    protected void handleClose(boolean animate) {
-        if (animate) {
-            animateClose();
-        } else {
-            closeComplete();
-        }
-    }
-
-    public  <T extends View> T inflateAndAdd(int resId) {
-        View view = mInflater.inflate(resId, this, false);
-        addView(view);
-        return (T) view;
-    }
-
     /**
      * Shows the notifications and deep shortcuts associated with {@param icon}.
      * @return the container if shown or null.
@@ -266,13 +198,31 @@
         return container;
     }
 
-    private void populateAndShow(final BubbleTextView originalIcon, final List<String> shortcutIds,
+    @Override
+    protected void onInflationComplete(boolean isReversed) {
+        if (isReversed && mNotificationItemView != null) {
+            mNotificationItemView.inverseGutterMargin();
+        }
+
+        // Update dividers
+        int count = getChildCount();
+        DeepShortcutView lastView = null;
+        for (int i = 0; i < count; i++) {
+            View view = getChildAt(i);
+            if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) {
+                if (lastView != null) {
+                    lastView.setDividerVisibility(VISIBLE);
+                }
+                lastView = (DeepShortcutView) view;
+                lastView.setDividerVisibility(INVISIBLE);
+            }
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.P)
+    protected void populateAndShow(final BubbleTextView originalIcon, final List<String> shortcutIds,
             final List<NotificationKeyData> notificationKeys, List<SystemShortcut> systemShortcuts) {
         mNumNotifications = notificationKeys.size();
-
-        setVisibility(View.INVISIBLE);
-        mLauncher.getDragLayer().addView(this);
-
         mOriginalIcon = originalIcon;
 
         // Add views
@@ -294,17 +244,15 @@
             }
 
             for (int i = shortcutIds.size(); i > 0; i--) {
-                mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut));
+                mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut, this));
             }
             updateHiddenShortcuts();
 
             if (!systemShortcuts.isEmpty()) {
-                mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons);
+                mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
                 for (SystemShortcut shortcut : systemShortcuts) {
-                    View view = mInflater.inflate(R.layout.system_shortcut_icon_only,
-                            mSystemShortcutContainer, false);
-                    mSystemShortcutContainer.addView(view);
-                    initializeSystemShortcut(view, shortcut);
+                    initializeSystemShortcut(
+                            R.layout.system_shortcut_icon_only, mSystemShortcutContainer, shortcut);
                 }
             }
         } else if (!systemShortcuts.isEmpty()) {
@@ -313,78 +261,15 @@
             }
 
             for (SystemShortcut shortcut : systemShortcuts) {
-                initializeSystemShortcut(inflateAndAdd(R.layout.system_shortcut), shortcut);
+                initializeSystemShortcut(R.layout.system_shortcut, this, shortcut);
             }
         }
-        orientAboutIcon();
 
-        boolean reverseOrder = mIsAboveIcon;
-        if (reverseOrder) {
-            int count = getChildCount();
-            ArrayList<View> allViews = new ArrayList<>(count);
-            for (int i = 0; i < count; i++) {
-                if (i == viewsToFlip) {
-                    Collections.reverse(allViews);
-                }
-                allViews.add(getChildAt(i));
-            }
-            Collections.reverse(allViews);
-            removeAllViews();
-            for (int i = 0; i < count; i++) {
-                addView(allViews.get(i));
-            }
-            if (mNotificationItemView != null) {
-                mNotificationItemView.inverseGutterMargin();
-            }
-
-            orientAboutIcon();
-        }
-        updateDividers();
-
-        // Add the arrow.
-        final Resources res = getResources();
-        final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
-                ? R.dimen.popup_arrow_horizontal_center_start
-                : R.dimen.popup_arrow_horizontal_center_end);
-        final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
-        mLauncher.getDragLayer().addView(mArrow);
-        DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
-        if (mIsLeftAligned) {
-            mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
-        } else {
-            mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
-        }
-
-        if (Gravity.isVertical(mGravity)) {
-            // This is only true if there wasn't room for the container next to the icon,
-            // so we centered it instead. In that case we don't want to show the arrow.
-            mArrow.setVisibility(INVISIBLE);
-        } else {
-            ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
-                    arrowLp.width, arrowLp.height, !mIsAboveIcon));
-            Paint arrowPaint = arrowDrawable.getPaint();
-            arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary));
-            // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
-            int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
-            arrowPaint.setPathEffect(new CornerPathEffect(radius));
-            mArrow.setBackground(arrowDrawable);
-            mArrow.setElevation(getElevation());
-        }
-
-        mArrow.setPivotX(arrowLp.width / 2);
-        mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height);
-
-        animateOpen();
+        reorderAndShow(viewsToFlip);
 
         ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
-        int numShortcuts = mShortcuts.size() + systemShortcuts.size();
-        if (mNumNotifications == 0) {
-            setContentDescription(getContext().getString(R.string.shortcuts_menu_description,
-                    numShortcuts, originalIcon.getContentDescription().toString()));
-        } else {
-            setContentDescription(getContext().getString(
-                    R.string.shortcuts_menu_with_notifications_description, numShortcuts,
-                    mNumNotifications, originalIcon.getContentDescription().toString()));
+        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+            setAccessibilityPaneTitle(getTitleForAccessibility());
         }
 
         mLauncher.getDragController().addDragListener(this);
@@ -400,189 +285,26 @@
                 this, shortcutIds, mShortcuts, notificationKeys));
     }
 
-    protected boolean isAlignedWithStart() {
-        return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl;
-    }
-
-    /**
-     * Orients this container above or below the given icon, aligning with the left or right.
-     *
-     * These are the preferred orientations, in order (RTL prefers right-aligned over left):
-     * - Above and left-aligned
-     * - Above and right-aligned
-     * - Below and left-aligned
-     * - Below and right-aligned
-     *
-     * So we always align left if there is enough horizontal space
-     * and align above if there is enough vertical space.
-     */
-    protected void orientAboutIcon() {
-        measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-        int width = getMeasuredWidth();
-        int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset
-                + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
-        int height = getMeasuredHeight() + extraVerticalSpace;
-
-        DragLayer dragLayer = mLauncher.getDragLayer();
-        dragLayer.getDescendantRectRelativeToSelf(mOriginalIcon, mTempRect);
-        Rect insets = dragLayer.getInsets();
-
-        // Align left (right in RTL) if there is room.
-        int leftAlignedX = mTempRect.left + mOriginalIcon.getPaddingLeft();
-        int rightAlignedX = mTempRect.right - width - mOriginalIcon.getPaddingRight();
-        int x = leftAlignedX;
-        boolean canBeLeftAligned = leftAlignedX + width + insets.left
-                < dragLayer.getRight() - insets.right;
-        boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
-        if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {
-            x = rightAlignedX;
-        }
-        mIsLeftAligned = x == leftAlignedX;
-
-        // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
-        int iconWidth = mOriginalIcon.getWidth()
-                - mOriginalIcon.getTotalPaddingLeft() - mOriginalIcon.getTotalPaddingRight();
-        iconWidth *= mOriginalIcon.getScaleX();
-        Resources resources = getResources();
-        int xOffset;
-        if (isAlignedWithStart()) {
-            // Aligning with the shortcut icon.
-            int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);
-            int shortcutPaddingStart = resources.getDimensionPixelSize(
-                    R.dimen.popup_padding_start);
-            xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;
-        } else {
-            // Aligning with the drag handle.
-            int shortcutDragHandleWidth = resources.getDimensionPixelSize(
-                    R.dimen.deep_shortcut_drag_handle_size);
-            int shortcutPaddingEnd = resources.getDimensionPixelSize(
-                    R.dimen.popup_padding_end);
-            xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;
-        }
-        x += mIsLeftAligned ? xOffset : -xOffset;
-
-        // Open above icon if there is room.
-        int iconHeight = getIconHeightForPopupPlacement();
-        int y = mTempRect.top + mOriginalIcon.getPaddingTop() - height;
-        mIsAboveIcon = y > dragLayer.getTop() + insets.top;
-        if (!mIsAboveIcon) {
-            y = mTempRect.top + mOriginalIcon.getPaddingTop() + iconHeight + extraVerticalSpace;
-        }
-
-        // Insets are added later, so subtract them now.
-        if (mIsRtl) {
-            x += insets.right;
-        } else {
-            x -= insets.left;
-        }
-        y -= insets.top;
-
-        mGravity = 0;
-        if (y + height > dragLayer.getBottom() - insets.bottom) {
-            // The container is opening off the screen, so just center it in the drag layer instead.
-            mGravity = Gravity.CENTER_VERTICAL;
-            // Put the container next to the icon, preferring the right side in ltr (left in rtl).
-            int rightSide = leftAlignedX + iconWidth - insets.left;
-            int leftSide = rightAlignedX - iconWidth - insets.left;
-            if (!mIsRtl) {
-                if (rightSide + width < dragLayer.getRight()) {
-                    x = rightSide;
-                    mIsLeftAligned = true;
-                } else {
-                    x = leftSide;
-                    mIsLeftAligned = false;
-                }
-            } else {
-                if (leftSide > dragLayer.getLeft()) {
-                    x = leftSide;
-                    mIsLeftAligned = false;
-                } else {
-                    x = rightSide;
-                    mIsLeftAligned = true;
-                }
-            }
-            mIsAboveIcon = true;
-        }
-
-        setX(x);
-        if (Gravity.isVertical(mGravity)) {
-            return;
-        }
-
-        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
-        if (mIsAboveIcon) {
-            arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
-            lp.bottomMargin =
-                    mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top;
-            arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom;
-        } else {
-            arrowLp.gravity = lp.gravity = Gravity.TOP;
-            lp.topMargin = y + insets.top;
-            arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset;
-        }
+    private String getTitleForAccessibility() {
+        return getContext().getString(mNumNotifications == 0 ?
+                R.string.action_deep_shortcut :
+                R.string.shortcuts_menu_with_notifications_description);
     }
 
     @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        // enforce contained is within screen
-        DragLayer dragLayer = mLauncher.getDragLayer();
-        if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) {
-            // If we are still off screen, center horizontally too.
-            mGravity |= Gravity.CENTER_HORIZONTAL;
-        }
-
-        if (Gravity.isHorizontal(mGravity)) {
-            setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
-            mArrow.setVisibility(INVISIBLE);
-        }
-        if (Gravity.isVertical(mGravity)) {
-            setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
-        }
+    protected Pair<View, String> getAccessibilityTarget() {
+        return Pair.create(this, "");
     }
 
-    protected void animateOpen() {
-        setVisibility(View.VISIBLE);
-        mIsOpen = true;
-
-        final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
-        final Resources res = getResources();
-        final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
-        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
-
-        // Rectangular reveal.
-        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, false);
-        revealAnim.setDuration(revealDuration);
-        revealAnim.setInterpolator(revealInterpolator);
-
-        Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
-        fadeIn.setDuration(revealDuration);
-        fadeIn.setInterpolator(revealInterpolator);
-        openAnim.play(fadeIn);
-
-        // Animate the arrow.
-        mArrow.setScaleX(0);
-        mArrow.setScaleY(0);
-        Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
-                .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration));
-
-        openAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mOpenCloseAnimator = null;
-                sendCustomAccessibilityEvent(
-                        PopupContainerWithArrow.this,
-                        AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                        getContext().getString(R.string.action_deep_shortcut));
-            }
-        });
-
-        mOpenCloseAnimator = openAnim;
-        openAnim.playSequentially(revealAnim, arrowScale);
-        openAnim.start();
+    @Override
+    protected void getTargetObjectLocation(Rect outPos) {
+        getPopupContainer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
+        outPos.top += mOriginalIcon.getPaddingTop();
+        outPos.left += mOriginalIcon.getPaddingLeft();
+        outPos.right -= mOriginalIcon.getPaddingRight();
+        outPos.bottom = outPos.top + (mOriginalIcon.getIcon() != null
+                ? mOriginalIcon.getIcon().getBounds().height()
+                : mOriginalIcon.getHeight());
     }
 
     public void applyNotificationInfos(List<NotificationInfo> notificationInfos) {
@@ -641,10 +363,8 @@
         if (onClickListener != null && widgetsView == null) {
             // We didn't have any widgets cached but now there are some, so enable the shortcut.
             if (mSystemShortcutContainer != this) {
-                View view = mInflater.inflate(R.layout.system_shortcut_icon_only,
-                        mSystemShortcutContainer, false);
-                mSystemShortcutContainer.addView(view);
-                initializeSystemShortcut(view, widgetInfo);
+                initializeSystemShortcut(
+                        R.layout.system_shortcut_icon_only, mSystemShortcutContainer, widgetInfo);
             } else {
                 // If using the expanded system shortcut (as opposed to just the icon), we need to
                 // reopen the container to ensure measurements etc. all work out. While this could
@@ -664,7 +384,8 @@
         }
     }
 
-    private void initializeSystemShortcut(View view, SystemShortcut info) {
+    private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) {
+        View view = inflateAndAdd(resId, container);
         if (view instanceof DeepShortcutView) {
             // Expanded system shortcut, with both icon and text shown on white background.
             final DeepShortcutView shortcutView = (DeepShortcutView) view;
@@ -681,12 +402,6 @@
                 (ItemInfo) mOriginalIcon.getTag()));
     }
 
-    protected int getIconHeightForPopupPlacement() {
-        return mOriginalIcon.getIcon() != null
-                ? mOriginalIcon.getIcon().getBounds().height()
-                : mOriginalIcon.getHeight();
-    }
-
     /**
      * Determines when the deferred drag should be started.
      *
@@ -744,7 +459,7 @@
 
     private void updateNotificationHeader() {
         ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag();
-        BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
+        BadgeInfo badgeInfo = mLauncher.getBadgeInfoForItem(itemInfo);
         if (mNotificationItemView != null && badgeInfo != null) {
             mNotificationItemView.updateHeader(
                     badgeInfo.getNotificationCount(), itemInfo.iconColor);
@@ -806,91 +521,18 @@
         targetParent.containerType = ContainerType.DEEPSHORTCUTS;
     }
 
-    protected void animateClose() {
-        if (!mIsOpen) {
-            return;
-        }
-        mEndRect.setEmpty();
-        if (getOutlineProvider() instanceof RevealOutlineAnimation) {
-            ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
-        }
-        if (mOpenCloseAnimator != null) {
-            mOpenCloseAnimator.cancel();
-        }
-        mIsOpen = false;
-
-        final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
-        // Hide the arrow
-        closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
-        closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
-
+    @Override
+    protected void onCreateCloseAnimation(AnimatorSet anim) {
         // Animate original icon's text back in.
-        closeAnim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
+        anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
         mOriginalIcon.forceHideBadge(false);
-
-        final Resources res = getResources();
-        final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
-
-        // Rectangular reveal (reversed).
-        final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, true);
-        revealAnim.setInterpolator(revealInterpolator);
-        closeAnim.play(revealAnim);
-
-        Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
-        fadeOut.setInterpolator(revealInterpolator);
-        closeAnim.play(fadeOut);
-        closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
-
-        closeAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mOpenCloseAnimator = null;
-                if (mDeferContainerRemoval) {
-                    setVisibility(INVISIBLE);
-                } else {
-                    closeComplete();
-                }
-            }
-        });
-        mOpenCloseAnimator = closeAnim;
-        closeAnim.start();
     }
 
-    private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
-        int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
-                R.dimen.popup_arrow_horizontal_center_start:
-                R.dimen.popup_arrow_horizontal_center_end);
-        if (!mIsLeftAligned) {
-            arrowCenterX = getMeasuredWidth() - arrowCenterX;
-        }
-        int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
-
-        mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY);
-        if (mEndRect.isEmpty()) {
-            mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
-        }
-
-        return new RoundedRectRevealOutlineProvider
-                (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect);
-    }
-
-    /**
-     * Closes the popup without animation.
-     */
-    private void closeComplete() {
+    @Override
+    protected void closeComplete() {
+        super.closeComplete();
         mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
         mOriginalIcon.forceHideBadge(false);
-
-        mLauncher.getDragController().removeDragListener(this);
-        if (mOpenCloseAnimator != null) {
-            mOpenCloseAnimator.cancel();
-            mOpenCloseAnimator = null;
-        }
-        mIsOpen = false;
-        mDeferContainerRemoval = false;
-        mLauncher.getDragLayer().removeView(this);
-        mLauncher.getDragLayer().removeView(mArrow);
     }
 
     @Override
@@ -907,12 +549,9 @@
 
     @Override
     public boolean onLongClick(View v) {
+        if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
         // Return early if not the correct view
         if (!(v.getParent() instanceof DeepShortcutView)) return false;
-        // Return early if global dragging is not enabled
-        if (!mLauncher.isDraggingEnabled()) return false;
-        // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
-        if (mLauncher.getDragController().isDragging()) return false;
 
         // Long clicked on a shortcut.
         DeepShortcutView sv = (DeepShortcutView) v.getParent();
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 335426c..f1b8ec0 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -206,7 +206,7 @@
         if (notificationListener == null) {
             return;
         }
-        notificationListener.cancelNotification(notificationKey);
+        notificationListener.cancelNotificationFromLauncher(notificationKey);
     }
 
     public void setAllWidgets(ArrayList<WidgetListRowEntry> allWidgets) {
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index d2bcd18..693e532 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -9,7 +9,7 @@
 import android.view.View;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.InfoDropTarget;
+import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
@@ -28,7 +28,7 @@
  *
  * Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
  */
-public abstract class SystemShortcut extends ItemInfo {
+public abstract class SystemShortcut<T extends BaseDraggingActivity> extends ItemInfo {
     public final int iconResId;
     public final int labelResId;
 
@@ -37,10 +37,9 @@
         this.labelResId = labelResId;
     }
 
-    public abstract View.OnClickListener getOnClickListener(final Launcher launcher,
-            final ItemInfo itemInfo);
+    public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo);
 
-    public static class Widgets extends SystemShortcut {
+    public static class Widgets extends SystemShortcut<Launcher> {
 
         public Widgets() {
             super(R.drawable.ic_widget, R.string.widget_button_text);
@@ -55,17 +54,14 @@
             if (widgets == null) {
                 return null;
             }
-            return new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    AbstractFloatingView.closeAllOpenViews(launcher);
-                    WidgetsBottomSheet widgetsBottomSheet =
-                            (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
-                                    R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
-                    widgetsBottomSheet.populateAndShow(itemInfo);
-                    launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
-                            ControlType.WIDGETS_BUTTON, view);
-                }
+            return (view) -> {
+                AbstractFloatingView.closeAllOpenViews(launcher);
+                WidgetsBottomSheet widgetsBottomSheet =
+                        (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
+                                R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
+                widgetsBottomSheet.populateAndShow(itemInfo);
+                launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+                        ControlType.WIDGETS_BUTTON, view);
             };
         }
     }
@@ -76,17 +72,16 @@
         }
 
         @Override
-        public View.OnClickListener getOnClickListener(final Launcher launcher,
-                final ItemInfo itemInfo) {
-            return new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    Rect sourceBounds = launcher.getViewBounds(view);
-                    Bundle opts = launcher.getActivityLaunchOptions(view, false);
-                    InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, sourceBounds, opts);
-                    launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
-                            ControlType.APPINFO_TARGET, view);
-                }
+        public View.OnClickListener getOnClickListener(
+                BaseDraggingActivity activity, ItemInfo itemInfo) {
+            return (view) -> {
+                dismissTaskMenuView(activity);
+                Rect sourceBounds = activity.getViewBounds(view);
+                Bundle opts = activity.getActivityLaunchOptionsAsBundle(view);
+                new PackageManagerHelper(activity).startDetailsActivityForInfo(
+                        itemInfo, sourceBounds, opts);
+                activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+                        ControlType.APPINFO_TARGET, view);
             };
         }
     }
@@ -97,29 +92,35 @@
         }
 
         @Override
-        public View.OnClickListener getOnClickListener(final Launcher launcher,
-                final ItemInfo itemInfo) {
+        public View.OnClickListener getOnClickListener(
+                BaseDraggingActivity activity, ItemInfo itemInfo) {
             boolean supportsWebUI = (itemInfo instanceof ShortcutInfo) &&
                     ((ShortcutInfo) itemInfo).hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI);
             boolean isInstantApp = false;
             if (itemInfo instanceof com.android.launcher3.AppInfo) {
                 com.android.launcher3.AppInfo appInfo = (com.android.launcher3.AppInfo) itemInfo;
-                isInstantApp = InstantAppResolver.newInstance(launcher).isInstantApp(appInfo);
+                isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo);
             }
             boolean enabled = supportsWebUI || isInstantApp;
             if (!enabled) {
                 return null;
             }
-            return createOnClickListener(launcher, itemInfo);
+            return createOnClickListener(activity, itemInfo);
         }
 
-        public View.OnClickListener createOnClickListener(Launcher launcher, ItemInfo itemInfo) {
+        public View.OnClickListener createOnClickListener(
+                BaseDraggingActivity activity, ItemInfo itemInfo) {
             return view -> {
                 Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
                         itemInfo.getTargetComponent().getPackageName());
-                launcher.startActivitySafely(view, intent, itemInfo);
-                AbstractFloatingView.closeAllOpenViews(launcher);
+                activity.startActivitySafely(view, intent, itemInfo);
+                AbstractFloatingView.closeAllOpenViews(activity);
             };
         }
     }
+
+    protected static void dismissTaskMenuView(BaseDraggingActivity activity) {
+        AbstractFloatingView.closeOpenViews(activity, true,
+            AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+    }
 }
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index b83d3c0..b1dd003 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -142,6 +142,8 @@
                 // First row of first screen is not empty
                 createEmptyRowOnFirstScreen = c.moveToNext();
             }
+        } else {
+            createEmptyRowOnFirstScreen = false;
         }
 
         ArrayList<ContentProviderOperation> insertOperations = new ArrayList<>(BATCH_INSERT_SIZE);
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 65acaa9..8e29df1 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -16,6 +16,10 @@
 
 package com.android.launcher3.qsb;
 
+import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_BIND;
+import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
+import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;
+
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.SearchManager;
@@ -36,7 +40,6 @@
 
 import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -68,14 +71,19 @@
         super.setPadding(0, 0, 0, 0);
     }
 
+    protected void setPaddingUnchecked(int left, int top, int right, int bottom) {
+        super.setPadding(left, top, right, bottom);
+    }
+
     /**
      * A fragment to display the QSB.
      */
-    public static class QsbFragment extends Fragment implements View.OnClickListener {
+    public static class QsbFragment extends Fragment {
 
+        public static final int QSB_WIDGET_HOST_ID = 1026;
         private static final int REQUEST_BIND_QSB = 1;
-        private static final String QSB_WIDGET_ID = "qsb_widget_id";
 
+        protected String mKeyWidgetId = "qsb_widget_id";
         private QsbWidgetHost mQsbWidgetHost;
         private AppWidgetProviderInfo mWidgetInfo;
         private QsbWidgetHostView mQsb;
@@ -87,10 +95,15 @@
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            mQsbWidgetHost = new QsbWidgetHost(getActivity());
+            mQsbWidgetHost = createHost();
             mOrientation = getContext().getResources().getConfiguration().orientation;
         }
 
+        protected QsbWidgetHost createHost() {
+            return new QsbWidgetHost(getActivity(), QSB_WIDGET_HOST_ID,
+                    (c) -> new QsbWidgetHostView(c));
+        }
+
         private FrameLayout mWrapper;
 
         @Override
@@ -100,31 +113,23 @@
             mWrapper = new FrameLayout(getActivity());
 
             // Only add the view when enabled
-            if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
+            if (isQsbEnabled()) {
                 mWrapper.addView(createQsb(mWrapper));
             }
             return mWrapper;
         }
 
         private View createQsb(ViewGroup container) {
-            Activity activity = getActivity();
-            mWidgetInfo = getSearchWidgetProvider(activity);
+            mWidgetInfo = getSearchWidgetProvider();
             if (mWidgetInfo == null) {
                 // There is no search provider, just show the default widget.
-                return QsbWidgetHostView.getDefaultView(container);
+                return getDefaultView(container, false /* show setup icon */);
             }
-
+            Bundle opts = createBindOptions();
+            Activity activity = getActivity();
             AppWidgetManager widgetManager = AppWidgetManager.getInstance(activity);
-            InvariantDeviceProfile idp = LauncherAppState.getIDP(activity);
 
-            Bundle opts = new Bundle();
-            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(activity, idp.numColumns, 1, null);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
-            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
-
-            int widgetId = Utilities.getPrefs(activity).getInt(QSB_WIDGET_ID, -1);
+            int widgetId = Utilities.getPrefs(activity).getInt(mKeyWidgetId, -1);
             AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId);
             boolean isWidgetBound = (widgetInfo != null) &&
                     widgetInfo.provider.equals(mWidgetInfo.provider);
@@ -163,32 +168,18 @@
             }
 
             // Return a default widget with setup icon.
-            View v = QsbWidgetHostView.getDefaultView(container);
-            View setupButton = v.findViewById(R.id.btn_qsb_setup);
-            setupButton.setVisibility(View.VISIBLE);
-            setupButton.setOnClickListener(this);
-            return v;
+            return getDefaultView(container, true /* show setup icon */);
         }
 
         private void saveWidgetId(int widgetId) {
-            Utilities.getPrefs(getActivity()).edit().putInt(QSB_WIDGET_ID, widgetId).apply();
-        }
-
-        @Override
-        public void onClick(View view) {
-            // Start intent for bind the widget
-            Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
-            // Allocate a new widget id for QSB
-            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mQsbWidgetHost.allocateAppWidgetId());
-            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider);
-            startActivityForResult(intent, REQUEST_BIND_QSB);
+            Utilities.getPrefs(getActivity()).edit().putInt(mKeyWidgetId, widgetId).apply();
         }
 
         @Override
         public void onActivityResult(int requestCode, int resultCode, Intent data) {
             if (requestCode == REQUEST_BIND_QSB) {
                 if (resultCode == Activity.RESULT_OK) {
-                    saveWidgetId(data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1));
+                    saveWidgetId(data.getIntExtra(EXTRA_APPWIDGET_ID, -1));
                     rebindFragment();
                 } else {
                     mQsbWidgetHost.deleteHost();
@@ -212,7 +203,7 @@
 
         private void rebindFragment() {
             // Exit if the embedded qsb is disabled
-            if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
+            if (!isQsbEnabled()) {
                 return;
             }
 
@@ -221,48 +212,87 @@
                 mWrapper.addView(createQsb(mWrapper));
             }
         }
-    }
 
-    /**
-     * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
-     * provided by the same package which is set to be global search activity.
-     * If widgetCategory is not supported, or no such widget is found, returns the first widget
-     * provided by the package.
-     */
-    public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) {
-        SearchManager searchManager =
-                (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
-        ComponentName searchComponent = searchManager.getGlobalSearchActivity();
-        if (searchComponent == null) return null;
-        String providerPkg = searchComponent.getPackageName();
+        public boolean isQsbEnabled() {
+            return FeatureFlags.QSB_ON_FIRST_SCREEN;
+        }
 
-        AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
+        protected Bundle createBindOptions() {
+            InvariantDeviceProfile idp = LauncherAppState.getIDP(getActivity());
 
-        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
-        for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
-            if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
-                if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
-                    return info;
-                } else if (defaultWidgetForSearchPackage == null) {
-                    defaultWidgetForSearchPackage = info;
+            Bundle opts = new Bundle();
+            Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(getActivity(),
+                    idp.numColumns, 1, null);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right);
+            opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom);
+            return opts;
+        }
+
+        protected View getDefaultView(ViewGroup container, boolean showSetupIcon) {
+            // Return a default widget with setup icon.
+            View v = QsbWidgetHostView.getDefaultView(container);
+            if (showSetupIcon) {
+                View setupButton = v.findViewById(R.id.btn_qsb_setup);
+                setupButton.setVisibility(View.VISIBLE);
+                setupButton.setOnClickListener((v2) -> startActivityForResult(
+                        new Intent(ACTION_APPWIDGET_BIND)
+                                .putExtra(EXTRA_APPWIDGET_ID, mQsbWidgetHost.allocateAppWidgetId())
+                                .putExtra(EXTRA_APPWIDGET_PROVIDER, mWidgetInfo.provider),
+                        REQUEST_BIND_QSB));
+            }
+            return v;
+        }
+
+        /**
+         * Returns a widget with category {@link AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX}
+         * provided by the same package which is set to be global search activity.
+         * If widgetCategory is not supported, or no such widget is found, returns the first widget
+         * provided by the package.
+         */
+        protected AppWidgetProviderInfo getSearchWidgetProvider() {
+            SearchManager searchManager =
+                    (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
+            ComponentName searchComponent = searchManager.getGlobalSearchActivity();
+            if (searchComponent == null) return null;
+            String providerPkg = searchComponent.getPackageName();
+
+            AppWidgetProviderInfo defaultWidgetForSearchPackage = null;
+
+            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getActivity());
+            for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) {
+                if (info.provider.getPackageName().equals(providerPkg) && info.configure == null) {
+                    if ((info.widgetCategory
+                            & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) {
+                        return info;
+                    } else if (defaultWidgetForSearchPackage == null) {
+                        defaultWidgetForSearchPackage = info;
+                    }
                 }
             }
+            return defaultWidgetForSearchPackage;
         }
-        return defaultWidgetForSearchPackage;
     }
 
-    private static class QsbWidgetHost extends AppWidgetHost {
+    public static class QsbWidgetHost extends AppWidgetHost {
 
-        private static final int QSB_WIDGET_HOST_ID = 1026;
+        private final WidgetViewFactory mViewFactory;
 
-        public QsbWidgetHost(Context context) {
-            super(context, QSB_WIDGET_HOST_ID);
+        public QsbWidgetHost(Context context, int hostId, WidgetViewFactory viewFactory) {
+            super(context, hostId);
+            mViewFactory = viewFactory;
         }
 
         @Override
         protected AppWidgetHostView onCreateView(
                 Context context, int appWidgetId, AppWidgetProviderInfo appWidget) {
-            return new QsbWidgetHostView(context);
+            return mViewFactory.newView(context);
         }
     }
+
+    public interface WidgetViewFactory {
+
+        QsbWidgetHostView newView(Context context);
+    }
 }
diff --git a/src/com/android/launcher3/qsb/QsbWidgetHostView.java b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
index a8a41f6..407812d 100644
--- a/src/com/android/launcher3/qsb/QsbWidgetHostView.java
+++ b/src/com/android/launcher3/qsb/QsbWidgetHostView.java
@@ -58,13 +58,9 @@
         try {
             super.onLayout(changed, left, top, right, bottom);
         } catch (final RuntimeException e) {
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    // Update the widget with 0 Layout id, to reset the view to error view.
-                    updateAppWidget(new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0));
-                }
-            });
+            // Update the widget with 0 Layout id, to reset the view to error view.
+            post(() -> updateAppWidget(
+                    new RemoteViews(getAppWidgetInfo().provider.getPackageName(), 0)));
         }
     }
 
@@ -73,15 +69,19 @@
         return getDefaultView(this);
     }
 
+    @Override
+    protected View getDefaultView() {
+        View v = super.getDefaultView();
+        v.setOnClickListener((v2) ->
+                Launcher.getLauncher(getContext()).startSearch("", false, null, true));
+        return v;
+    }
+
     public static View getDefaultView(ViewGroup parent) {
         View v = LayoutInflater.from(parent.getContext())
                 .inflate(R.layout.qsb_default_view, parent, false);
-        v.findViewById(R.id.btn_qsb_search).setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                Launcher.getLauncher(view.getContext()).startSearch("", false, null, true);
-            }
-        });
+        v.findViewById(R.id.btn_qsb_search).setOnClickListener((v2) ->
+                Launcher.getLauncher(v2.getContext()).startSearch("", false, null, true));
         return v;
     }
 }
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
index f44f5c8..24e2e2f 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
@@ -181,7 +181,12 @@
      * If packageName is null, returns all pinned shortcuts regardless of package.
      */
     public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName, UserHandle user) {
-        return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, null, user);
+        return queryForPinnedShortcuts(packageName, null, user);
+    }
+
+    public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName,
+            List<String> shortcutIds, UserHandle user) {
+        return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, shortcutIds, user);
     }
 
     public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandle user) {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
index 1a5297d..c809f27 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -22,6 +22,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.widget.Toast;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
@@ -33,7 +34,9 @@
 public class DeepShortcutTextView extends BubbleTextView {
     private final Rect mDragHandleBounds = new Rect();
     private final int mDragHandleWidth;
-    private boolean mShouldPerformClick = true;
+    private boolean mShowInstructionToast = false;
+
+    private Toast mInstructionToast;
 
     public DeepShortcutTextView(Context context) {
         this(context, null, 0);
@@ -70,14 +73,29 @@
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            // Ignore clicks on the drag handle (long clicks still start the drag).
-            mShouldPerformClick = !mDragHandleBounds.contains((int) ev.getX(), (int) ev.getY());
+            // Show toast if user touches the drag handle (long clicks still start the drag).
+            mShowInstructionToast = mDragHandleBounds.contains((int) ev.getX(), (int) ev.getY());
         }
         return super.onTouchEvent(ev);
     }
 
     @Override
     public boolean performClick() {
-        return mShouldPerformClick && super.performClick();
+        if (mShowInstructionToast) {
+            showToast();
+            return true;
+        }
+        return super.performClick();
+    }
+
+    private void showToast() {
+        if (mInstructionToast != null) {
+            mInstructionToast.cancel();
+        }
+        CharSequence msg = Utilities.wrapForTts(
+                getContext().getText(R.string.long_press_shortcut_to_add),
+                getContext().getString(R.string.long_accessible_way_to_add_shortcut));
+        mInstructionToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
+        mInstructionToast.show();
     }
 }
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 450a690..7d0ea7b 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -30,6 +30,7 @@
 import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.touch.ItemClickHandler;
 
 /**
  * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
@@ -120,7 +121,7 @@
         mBubbleText.setText(usingLongLabel ? longLabel : mDetail.getShortLabel());
 
         // TODO: Add the click handler to this view directly and not the child view.
-        mBubbleText.setOnClickListener(Launcher.getLauncher(getContext()));
+        mBubbleText.setOnClickListener(container.getItemClickListener());
         mBubbleText.setOnLongClickListener(container);
         mBubbleText.setOnTouchListener(container);
     }
diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
index cfb9258..ee97641 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -50,12 +50,10 @@
                 Bitmap.Config.ARGB_8888);
 
         Canvas canvas = new Canvas(b);
-        canvas.save(Canvas.MATRIX_SAVE_FLAG);
         canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2);
         canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0);
         canvas.translate(bounds.left, bounds.top);
         d.draw(canvas);
-        canvas.restore();
         return b;
     }
 
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index 704d82f..cbef85a 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -1,7 +1,6 @@
 package com.android.launcher3.shortcuts;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
 
@@ -18,8 +17,8 @@
         super(new ComponentName(packageName, id), user);
     }
 
-    public ShortcutKey(Context context, String componentKeyStr) {
-        super(context, componentKeyStr);
+    public ShortcutKey(ComponentName componentName, UserHandle user) {
+        super(componentName, user);
     }
 
     public String getId() {
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index 7298383..c6370c5 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -24,7 +24,6 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel.Callbacks;
 import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.util.Preconditions;
 
 import java.lang.ref.WeakReference;
 
@@ -38,7 +37,7 @@
 
     public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
 
-    private static WeakReference<InternalStateHandler> sPendingHandler = new WeakReference<>(null);
+    private static final Scheduler sScheduler = new Scheduler();
 
     /**
      * Initializes the handler when the launcher is ready.
@@ -53,30 +52,16 @@
         return intent;
     }
 
-    public final void initWhenReady(MainThreadExecutor executor) {
-        sPendingHandler = new WeakReference<>(this);
-        executor.execute(this::initIfReadOnUIThread);
+    public final void initWhenReady() {
+        sScheduler.schedule(this);
     }
 
-    private void initIfReadOnUIThread() {
-        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app == null) {
-            return;
-        }
-        Callbacks cb = app.getModel().getCallback();
-        if (!(cb instanceof Launcher)) {
-            return;
-        }
-        Launcher launcher = (Launcher) cb;
-        if (!init(launcher, launcher.isStarted())) {
-            sPendingHandler.clear();
-        }
+    public boolean clearReference() {
+        return sScheduler.clearReference(this);
     }
 
-    public void clearReference() {
-        if (sPendingHandler.get() == this) {
-            sPendingHandler.clear();
-        }
+    public static boolean hasPending() {
+        return sScheduler.hasPending();
     }
 
     public static boolean handleCreate(Launcher launcher, Intent intent) {
@@ -101,14 +86,63 @@
             }
         }
         if (!result && !explicitIntent) {
-            InternalStateHandler pendingHandler = sPendingHandler.get();
-            if (pendingHandler != null) {
-                if (!pendingHandler.init(launcher, alreadyOnHome)) {
-                    sPendingHandler.clear();
-                }
-                result = true;
-            }
+            result = sScheduler.initIfPending(launcher, alreadyOnHome);
         }
         return result;
     }
+
+    private static class Scheduler implements Runnable {
+
+        private WeakReference<InternalStateHandler> mPendingHandler = new WeakReference<>(null);
+        private MainThreadExecutor mMainThreadExecutor;
+
+        public void schedule(InternalStateHandler handler) {
+            synchronized (this) {
+                mPendingHandler = new WeakReference<>(handler);
+                if (mMainThreadExecutor == null) {
+                    mMainThreadExecutor = new MainThreadExecutor();
+                }
+            }
+            mMainThreadExecutor.execute(this);
+        }
+
+        @Override
+        public void run() {
+            LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+            if (app == null) {
+                return;
+            }
+            Callbacks cb = app.getModel().getCallback();
+            if (!(cb instanceof Launcher)) {
+                return;
+            }
+            Launcher launcher = (Launcher) cb;
+            initIfPending(launcher, launcher.isStarted());
+        }
+
+        public boolean initIfPending(Launcher launcher, boolean alreadyOnHome) {
+            InternalStateHandler pendingHandler = mPendingHandler.get();
+            if (pendingHandler != null) {
+                if (!pendingHandler.init(launcher, alreadyOnHome)) {
+                    clearReference(pendingHandler);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public boolean clearReference(InternalStateHandler handler) {
+            synchronized (this) {
+                if (mPendingHandler.get() == handler) {
+                    mPendingHandler.clear();
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        public boolean hasPending() {
+            return mPendingHandler.get() != null;
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
new file mode 100644
index 0000000..e866445
--- /dev/null
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2018 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.states;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
+
+import static com.android.launcher3.Utilities.ATLEAST_NOUGAT;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.content.res.Resources;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+/**
+ * Utility class to manage launcher rotation
+ */
+public class RotationHelper implements OnSharedPreferenceChangeListener {
+
+    public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
+
+    public static boolean getAllowRotationDefaultValue() {
+        if (ATLEAST_NOUGAT) {
+            // If the device was scaled, used the original dimensions to determine if rotation
+            // is allowed of not.
+            Resources res = Resources.getSystem();
+            int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
+                    * res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
+            return originalSmallestWidth >= 600;
+        }
+        return false;
+    }
+
+    public static final int REQUEST_NONE = 0;
+    public static final int REQUEST_ROTATE = 1;
+    public static final int REQUEST_LOCK = 2;
+
+    private final Activity mActivity;
+    private final SharedPreferences mPrefs;
+
+    private final boolean mIgnoreAutoRotateSettings;
+    private boolean mAutoRotateEnabled;
+
+    /**
+     * Rotation request made by {@link InternalStateHandler}. This supersedes any other request.
+     */
+    private int mStateHandlerRequest = REQUEST_NONE;
+    /**
+     * Rotation request made by a Launcher State
+     */
+    private int mCurrentStateRequest = REQUEST_NONE;
+
+    // This is used to defer setting rotation flags until the activity is being created
+    private boolean mInitialized;
+    public boolean mDestroyed;
+
+    private int mLastActivityFlags = -1;
+
+    public RotationHelper(Activity activity) {
+        mActivity = activity;
+
+        // On large devices we do not handle auto-rotate differently.
+        mIgnoreAutoRotateSettings = mActivity.getResources().getBoolean(R.bool.allow_rotation);
+        if (!mIgnoreAutoRotateSettings) {
+            mPrefs = Utilities.getPrefs(mActivity);
+            mPrefs.registerOnSharedPreferenceChangeListener(this);
+            mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
+                    getAllowRotationDefaultValue());
+        } else {
+            mPrefs = null;
+        }
+    }
+
+    @Override
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
+        mAutoRotateEnabled = mPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
+                getAllowRotationDefaultValue());
+        notifyChange();
+    }
+
+    public void setStateHandlerRequest(int request) {
+        if (mStateHandlerRequest != request) {
+            mStateHandlerRequest = request;
+            notifyChange();
+        }
+    }
+
+    public void setCurrentStateRequest(int request) {
+        if (mCurrentStateRequest != request) {
+            mCurrentStateRequest = request;
+            notifyChange();
+        }
+    }
+
+    public void initialize() {
+        if (!mInitialized) {
+            mInitialized = true;
+            notifyChange();
+        }
+    }
+
+    public void destroy() {
+        if (!mDestroyed) {
+            mDestroyed = true;
+            if (mPrefs != null) {
+                mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+            }
+        }
+    }
+
+    private void notifyChange() {
+        if (!mInitialized || mDestroyed) {
+            return;
+        }
+
+        final int activityFlags;
+        if (mStateHandlerRequest != REQUEST_NONE) {
+            activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
+                    SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
+        } else if (mCurrentStateRequest == REQUEST_LOCK) {
+            activityFlags = SCREEN_ORIENTATION_LOCKED;
+        } else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE
+                || mAutoRotateEnabled) {
+            activityFlags = SCREEN_ORIENTATION_UNSPECIFIED;
+        } else {
+            // If auto rotation is off, allow rotation on the activity, in case the user is using
+            // forced rotation.
+            activityFlags = SCREEN_ORIENTATION_NOSENSOR;
+        }
+        if (activityFlags != mLastActivityFlags) {
+            mLastActivityFlags = activityFlags;
+            mActivity.setRequestedOrientation(activityFlags);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("[mStateHandlerRequest=%d, mCurrentStateRequest=%d,"
+                + " mLastActivityFlags=%d, mIgnoreAutoRotateSettings=%b, mAutoRotateEnabled=%b]",
+                mStateHandlerRequest, mCurrentStateRequest, mLastActivityFlags,
+                mIgnoreAutoRotateSettings, mAutoRotateEnabled);
+    }
+}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 6d584cd..35f7f88 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -16,11 +16,9 @@
 package com.android.launcher3.states;
 
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
 
-import android.content.pm.ActivityInfo;
 import android.graphics.Rect;
-import android.os.Handler;
-import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InstallShortcutReceiver;
@@ -34,13 +32,9 @@
  */
 public class SpringLoadedState extends LauncherState {
 
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
+    private static final int STATE_FLAGS = FLAG_MULTI_PAGE |
             FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
-            FLAG_DISABLE_PAGE_CLIPPING;
-
-    // Determines how long to wait after a rotation before restoring the screen orientation to
-    // match the sensor state.
-    private static final int RESTORE_SCREEN_ORIENTATION_DELAY = 500;
+            FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS | FLAG_HIDE_BACK_BUTTON;
 
     public SpringLoadedState(int id) {
         super(id, ContainerType.OVERVIEW, SPRING_LOADED_TRANSITION_MS, STATE_FLAGS);
@@ -84,37 +78,23 @@
         ws.showPageIndicatorAtCurrentScroll();
         ws.getPageIndicator().setShouldAutoHide(false);
 
-        // Lock the orientation:
-        if (launcher.isRotationEnabled()) {
-            launcher.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
-        }
-
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are
         // in spring loaded mode
         InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_DRAG_AND_DROP);
+        launcher.getRotationHelper().setCurrentStateRequest(REQUEST_LOCK);
+    }
+
+    @Override
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
+        return 0.3f;
     }
 
     @Override
     public void onStateDisabled(final Launcher launcher) {
         launcher.getWorkspace().getPageIndicator().setShouldAutoHide(true);
 
-        // Unlock rotation lock
-        if (launcher.isRotationEnabled()) {
-            new Handler().postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    launcher.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-                }
-            }, RESTORE_SCREEN_ORIENTATION_DELAY);
-        }
-
         // Re-enable any Un/InstallShortcutReceiver and now process any queued items
         InstallShortcutReceiver.disableAndFlushInstallQueue(
                 InstallShortcutReceiver.FLAG_DRAG_AND_DROP, launcher);
     }
-
-    @Override
-    public View getFinalFocus(Launcher launcher) {
-        return null;
-    }
 }
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
new file mode 100644
index 0000000..0e277ea
--- /dev/null
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.touch;
+
+import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.LauncherStateManager.ANIM_ALL;
+import static com.android.launcher3.LauncherStateManager.ATOMIC_COMPONENT;
+import static com.android.launcher3.LauncherStateManager.NON_ATOMIC_COMPONENT;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.os.SystemClock;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.AnimationComponents;
+import com.android.launcher3.LauncherStateManager.AnimationConfig;
+import com.android.launcher3.LauncherStateManager.StateHandler;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.FlingBlockCheck;
+import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.util.TouchController;
+
+/**
+ * TouchController for handling state changes
+ */
+public abstract class AbstractStateChangeTouchController
+        implements TouchController, SwipeDetector.Listener {
+
+    private static final String TAG = "ASCTouchController";
+
+    // Progress after which the transition is assumed to be a success in case user does not fling
+    public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
+
+    /**
+     * Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
+     */
+    public static final float ATOMIC_OVERVIEW_ANIM_THRESHOLD = 0.5f;
+    protected static final long ATOMIC_DURATION = 200;
+
+    protected final Launcher mLauncher;
+    protected final SwipeDetector mDetector;
+
+    private boolean mNoIntercept;
+    protected int mStartContainerType;
+
+    protected LauncherState mStartState;
+    protected LauncherState mFromState;
+    protected LauncherState mToState;
+    protected AnimatorPlaybackController mCurrentAnimation;
+    protected PendingAnimation mPendingAnimation;
+
+    private float mStartProgress;
+    // Ratio of transition process [0, 1] to drag displacement (px)
+    private float mProgressMultiplier;
+    private float mDisplacementShift;
+    private boolean mCanBlockFling;
+    private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
+
+    protected AnimatorSet mAtomicAnim;
+    // True if we want to resume playing atomic components when mAtomicAnim completes.
+    private boolean mScheduleResumeAtomicComponent;
+    private AutoPlayAtomicAnimationInfo mAtomicAnimAutoPlayInfo;
+
+    private boolean mPassedOverviewAtomicThreshold;
+    // mAtomicAnim plays the atomic components of the state animations when we pass the threshold.
+    // However, if we reinit to transition to a new state (e.g. OVERVIEW -> ALL_APPS) before the
+    // atomic animation finishes, we only control the non-atomic components so that we don't
+    // interfere with the atomic animation. When the atomic animation ends, we start controlling
+    // the atomic components as well, using this controller.
+    private AnimatorPlaybackController mAtomicComponentsController;
+    private LauncherState mAtomicComponentsTargetState = NORMAL;
+
+    private float mAtomicComponentsStartProgress;
+
+    public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
+        mLauncher = l;
+        mDetector = new SwipeDetector(l, this, dir);
+    }
+
+    protected abstract boolean canInterceptTouch(MotionEvent ev);
+
+    @Override
+    public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mNoIntercept = !canInterceptTouch(ev);
+            if (mNoIntercept) {
+                return false;
+            }
+
+            // Now figure out which direction scroll events the controller will start
+            // calling the callbacks.
+            final int directionsToDetectScroll;
+            boolean ignoreSlopWhenSettling = false;
+
+            if (mCurrentAnimation != null) {
+                directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+                ignoreSlopWhenSettling = true;
+            } else {
+                directionsToDetectScroll = getSwipeDirection();
+                if (directionsToDetectScroll == 0) {
+                    mNoIntercept = true;
+                    return false;
+                }
+            }
+            mDetector.setDetectableScrollConditions(
+                    directionsToDetectScroll, ignoreSlopWhenSettling);
+        }
+
+        if (mNoIntercept) {
+            return false;
+        }
+
+        onControllerTouchEvent(ev);
+        return mDetector.isDraggingOrSettling();
+    }
+
+    private int getSwipeDirection() {
+        LauncherState fromState = mLauncher.getStateManager().getState();
+        int swipeDirection = 0;
+        if (getTargetState(fromState, true /* isDragTowardPositive */) != fromState) {
+            swipeDirection |= SwipeDetector.DIRECTION_POSITIVE;
+        }
+        if (getTargetState(fromState, false /* isDragTowardPositive */) != fromState) {
+            swipeDirection |= SwipeDetector.DIRECTION_NEGATIVE;
+        }
+        return swipeDirection;
+    }
+
+    @Override
+    public final boolean onControllerTouchEvent(MotionEvent ev) {
+        return mDetector.onTouchEvent(ev);
+    }
+
+    protected float getShiftRange() {
+        return mLauncher.getAllAppsController().getShiftRange();
+    }
+
+    /**
+     * Returns the state to go to from fromState given the drag direction. If there is no state in
+     * that direction, returns fromState.
+     */
+    protected abstract LauncherState getTargetState(LauncherState fromState,
+            boolean isDragTowardPositive);
+
+    protected abstract float initCurrentAnimation(@AnimationComponents int animComponents);
+
+    /**
+     * Returns the container that the touch started from when leaving NORMAL state.
+     */
+    protected abstract int getLogContainerTypeForNormalState();
+
+    private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
+        LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState()
+                : reachedToState ? mToState : mFromState;
+        LauncherState newToState = getTargetState(newFromState, isDragTowardPositive);
+
+        if (newFromState == mFromState && newToState == mToState || (newFromState == newToState)) {
+            return false;
+        }
+
+        mFromState = newFromState;
+        mToState = newToState;
+
+        mStartProgress = 0;
+        mPassedOverviewAtomicThreshold = false;
+        if (mCurrentAnimation != null) {
+            mCurrentAnimation.setOnCancelRunnable(null);
+        }
+        int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
+                ? NON_ATOMIC_COMPONENT : ANIM_ALL;
+        mScheduleResumeAtomicComponent = false;
+        if (mAtomicAnim != null) {
+            animComponents = NON_ATOMIC_COMPONENT;
+            // Control the non-atomic components until the atomic animation finishes, then control
+            // the atomic components as well.
+            mScheduleResumeAtomicComponent = true;
+        }
+        if (goingBetweenNormalAndOverview(mFromState, mToState)
+                || mAtomicComponentsTargetState != mToState) {
+            cancelAtomicComponentsController();
+        }
+
+        if (mAtomicComponentsController != null) {
+            animComponents &= ~ATOMIC_COMPONENT;
+        }
+        mProgressMultiplier = initCurrentAnimation(animComponents);
+        mCurrentAnimation.dispatchOnStart();
+        return true;
+    }
+
+    private boolean goingBetweenNormalAndOverview(LauncherState fromState, LauncherState toState) {
+        return (fromState == NORMAL || fromState == OVERVIEW)
+                && (toState == NORMAL || toState == OVERVIEW)
+                && mPendingAnimation == null;
+    }
+
+    @Override
+    public void onDragStart(boolean start) {
+        mStartState = mLauncher.getStateManager().getState();
+        if (mStartState == ALL_APPS) {
+            mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS;
+        } else if (mStartState == NORMAL) {
+            mStartContainerType = getLogContainerTypeForNormalState();
+        } else if (mStartState   == OVERVIEW){
+            mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER;
+        }
+        if (mCurrentAnimation == null) {
+            mFromState = mStartState;
+            mToState = null;
+            cancelAnimationControllers();
+            reinitCurrentAnimation(false, mDetector.wasInitialTouchPositive());
+            mDisplacementShift = 0;
+        } else {
+            mCurrentAnimation.pause();
+            mStartProgress = mCurrentAnimation.getProgressFraction();
+
+            mAtomicAnimAutoPlayInfo = null;
+            if (mAtomicComponentsController != null) {
+                mAtomicComponentsController.pause();
+            }
+        }
+        mCanBlockFling = mFromState == NORMAL;
+        mFlingBlockCheck.unblockFling();
+    }
+
+    @Override
+    public boolean onDrag(float displacement, float velocity) {
+        float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
+        float progress = deltaProgress + mStartProgress;
+        updateProgress(progress);
+        boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0;
+        if (progress <= 0) {
+            if (reinitCurrentAnimation(false, isDragTowardPositive)) {
+                mDisplacementShift = displacement;
+                if (mCanBlockFling) {
+                    mFlingBlockCheck.blockFling();
+                }
+            }
+        } else if (progress >= 1) {
+            if (reinitCurrentAnimation(true, isDragTowardPositive)) {
+                mDisplacementShift = displacement;
+                if (mCanBlockFling) {
+                    mFlingBlockCheck.blockFling();
+                }
+            }
+        } else {
+            mFlingBlockCheck.onEvent();
+        }
+
+        return true;
+    }
+
+    protected void updateProgress(float fraction) {
+        mCurrentAnimation.setPlayFraction(fraction);
+        if (mAtomicComponentsController != null) {
+            // Make sure we don't divide by 0, and have at least a small runway.
+            float start = Math.min(mAtomicComponentsStartProgress, 0.9f);
+            mAtomicComponentsController.setPlayFraction((fraction - start) / (1 - start));
+        }
+        maybeUpdateAtomicAnim(mFromState, mToState, fraction);
+    }
+
+    /**
+     * When going between normal and overview states, see if we passed the overview threshold and
+     * play the appropriate atomic animation if so.
+     */
+    private void maybeUpdateAtomicAnim(LauncherState fromState, LauncherState toState,
+            float progress) {
+        if (!goingBetweenNormalAndOverview(fromState, toState)) {
+            return;
+        }
+        float threshold = toState == OVERVIEW ? ATOMIC_OVERVIEW_ANIM_THRESHOLD
+                : 1f - ATOMIC_OVERVIEW_ANIM_THRESHOLD;
+        boolean passedThreshold = progress >= threshold;
+        if (passedThreshold != mPassedOverviewAtomicThreshold) {
+            LauncherState atomicFromState = passedThreshold ? fromState: toState;
+            LauncherState atomicToState = passedThreshold ? toState : fromState;
+            mPassedOverviewAtomicThreshold = passedThreshold;
+            if (mAtomicAnim != null) {
+                mAtomicAnim.cancel();
+            }
+            mAtomicAnim = createAtomicAnimForState(atomicFromState, atomicToState, ATOMIC_DURATION);
+            mAtomicAnim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    mAtomicAnim = null;
+                    mScheduleResumeAtomicComponent = false;
+                }
+
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    if (!mScheduleResumeAtomicComponent) {
+                        return;
+                    }
+                    cancelAtomicComponentsController();
+
+                    if (mCurrentAnimation != null) {
+                        mAtomicComponentsStartProgress = mCurrentAnimation.getProgressFraction();
+                        long duration = (long) (getShiftRange() * 2);
+                        mAtomicComponentsController = AnimatorPlaybackController.wrap(
+                                createAtomicAnimForState(mFromState, mToState, duration), duration);
+                        mAtomicComponentsController.dispatchOnStart();
+                        mAtomicComponentsTargetState = mToState;
+                        maybeAutoPlayAtomicComponentsAnim();
+                    }
+                }
+            });
+            mAtomicAnim.start();
+            mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+        }
+    }
+
+    private AnimatorSet createAtomicAnimForState(LauncherState fromState, LauncherState targetState,
+            long duration) {
+        AnimatorSetBuilder builder = getAnimatorSetBuilderForStates(fromState, targetState);
+        mLauncher.getStateManager().prepareForAtomicAnimation(fromState, targetState, builder);
+        AnimationConfig config = new AnimationConfig();
+        config.animComponents = ATOMIC_COMPONENT;
+        config.duration = duration;
+        for (StateHandler handler : mLauncher.getStateManager().getStateHandlers()) {
+            handler.setStateWithAnimation(targetState, builder, config);
+        }
+        return builder.build();
+    }
+
+    protected AnimatorSetBuilder getAnimatorSetBuilderForStates(LauncherState fromState,
+            LauncherState toState) {
+        return new AnimatorSetBuilder();
+    }
+
+    @Override
+    public void onDragEnd(float velocity, boolean fling) {
+        final int logAction = fling ? Touch.FLING : Touch.SWIPE;
+
+        boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
+        if (blockedFling) {
+            fling = false;
+        }
+
+        final LauncherState targetState;
+        final float progress = mCurrentAnimation.getProgressFraction();
+        final float interpolatedProgress = mCurrentAnimation.getInterpolator()
+                .getInterpolation(progress);
+        if (fling) {
+            targetState =
+                    Float.compare(Math.signum(velocity), Math.signum(mProgressMultiplier)) == 0
+                            ? mToState : mFromState;
+            // snap to top or bottom using the release velocity
+        } else {
+            float successProgress = mToState == ALL_APPS
+                    ? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS;
+            targetState = (interpolatedProgress > successProgress) ? mToState : mFromState;
+        }
+
+        final float endProgress;
+        final float startProgress;
+        final long duration;
+        // Increase the duration if we prevented the fling, as we are going against a high velocity.
+        final int durationMultiplier = blockedFling && targetState == mFromState
+                ? LauncherAnimUtils.blockedFlingDurationFactor(velocity) : 1;
+
+        if (targetState == mToState) {
+            endProgress = 1;
+            if (progress >= 1) {
+                duration = 0;
+                startProgress = 1;
+            } else {
+                startProgress = Utilities.boundToRange(
+                        progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
+                duration = SwipeDetector.calculateDuration(velocity,
+                        endProgress - Math.max(progress, 0)) * durationMultiplier;
+            }
+        } else {
+            // Let the state manager know that the animation didn't go to the target state,
+            // but don't cancel ourselves (we already clean up when the animation completes).
+            Runnable onCancel = mCurrentAnimation.getOnCancelRunnable();
+            mCurrentAnimation.setOnCancelRunnable(null);
+            mCurrentAnimation.dispatchOnCancel();
+            mCurrentAnimation.setOnCancelRunnable(onCancel);
+
+            endProgress = 0;
+            if (progress <= 0) {
+                duration = 0;
+                startProgress = 0;
+            } else {
+                startProgress = Utilities.boundToRange(
+                        progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
+                duration = SwipeDetector.calculateDuration(velocity,
+                        Math.min(progress, 1) - endProgress) * durationMultiplier;
+            }
+        }
+
+        mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction));
+        ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+        anim.setFloatValues(startProgress, endProgress);
+        maybeUpdateAtomicAnim(mFromState, targetState, targetState == mToState ? 1f : 0f);
+        updateSwipeCompleteAnimation(anim, Math.max(duration, getRemainingAtomicDuration()),
+                targetState, velocity, fling);
+        mCurrentAnimation.dispatchOnStart();
+        if (fling && targetState == LauncherState.ALL_APPS) {
+            mLauncher.getAppsView().addSpringFromFlingUpdateListener(anim, velocity);
+        }
+        anim.start();
+        mAtomicAnimAutoPlayInfo = new AutoPlayAtomicAnimationInfo(endProgress, anim.getDuration());
+        maybeAutoPlayAtomicComponentsAnim();
+    }
+
+    /**
+     * Animates the atomic components from the current progress to the final progress.
+     *
+     * Note that this only applies when we are controlling the atomic components separately from
+     * the non-atomic components, which only happens if we reinit before the atomic animation
+     * finishes.
+     */
+    private void maybeAutoPlayAtomicComponentsAnim() {
+        if (mAtomicComponentsController == null || mAtomicAnimAutoPlayInfo == null) {
+            return;
+        }
+
+        final AnimatorPlaybackController controller = mAtomicComponentsController;
+        ValueAnimator atomicAnim = controller.getAnimationPlayer();
+        atomicAnim.setFloatValues(controller.getProgressFraction(),
+                mAtomicAnimAutoPlayInfo.toProgress);
+        long duration = mAtomicAnimAutoPlayInfo.endTime - SystemClock.elapsedRealtime();
+        mAtomicAnimAutoPlayInfo = null;
+        if (duration <= 0) {
+            atomicAnim.start();
+            atomicAnim.end();
+            mAtomicComponentsController = null;
+        } else {
+            atomicAnim.setDuration(duration);
+            atomicAnim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (mAtomicComponentsController == controller) {
+                        mAtomicComponentsController = null;
+                    }
+                }
+            });
+            atomicAnim.start();
+        }
+    }
+
+    private long getRemainingAtomicDuration() {
+        if (mAtomicAnim == null) {
+            return 0;
+        }
+        if (Utilities.ATLEAST_OREO) {
+            return mAtomicAnim.getTotalDuration() - mAtomicAnim.getCurrentPlayTime();
+        } else {
+            long remainingDuration = 0;
+            for (Animator anim : mAtomicAnim.getChildAnimations()) {
+                remainingDuration = Math.max(remainingDuration, anim.getDuration());
+            }
+            return remainingDuration;
+        }
+    }
+
+    protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
+            LauncherState targetState, float velocity, boolean isFling) {
+        animator.setDuration(expectedDuration)
+                .setInterpolator(scrollInterpolatorForVelocity(velocity));
+    }
+
+    protected int getDirectionForLog() {
+        return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN;
+    }
+
+    protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+        if (mAtomicComponentsController != null) {
+            mAtomicComponentsController.getAnimationPlayer().end();
+            mAtomicComponentsController = null;
+        }
+        cancelAnimationControllers();
+        boolean shouldGoToTargetState = true;
+        if (mPendingAnimation != null) {
+            boolean reachedTarget = mToState == targetState;
+            mPendingAnimation.finish(reachedTarget, logAction);
+            mPendingAnimation = null;
+            shouldGoToTargetState = !reachedTarget;
+        }
+        if (shouldGoToTargetState) {
+            if (targetState != mStartState) {
+                logReachedState(logAction, targetState);
+            }
+            mLauncher.getStateManager().goToState(targetState, false /* animated */);
+
+            AccessibilityManagerCompat.sendEventToTest(mLauncher, "TAPL_WENT_TO_STATE");
+        }
+    }
+
+    private void logReachedState(int logAction, LauncherState targetState) {
+        // Transition complete. log the action
+        mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+                getDirectionForLog(),
+                mStartContainerType,
+                mStartState.containerType,
+                targetState.containerType,
+                mLauncher.getWorkspace().getCurrentPage());
+    }
+
+    protected void clearState() {
+        cancelAnimationControllers();
+        if (mAtomicAnim != null) {
+            mAtomicAnim.cancel();
+            mAtomicAnim = null;
+        }
+        mScheduleResumeAtomicComponent = false;
+    }
+
+    private void cancelAnimationControllers() {
+        mCurrentAnimation = null;
+        cancelAtomicComponentsController();
+        mDetector.finishedScrolling();
+        mDetector.setDetectableScrollConditions(0, false);
+    }
+
+    private void cancelAtomicComponentsController() {
+        if (mAtomicComponentsController != null) {
+            mAtomicComponentsController.getAnimationPlayer().cancel();
+            mAtomicComponentsController = null;
+        }
+        mAtomicAnimAutoPlayInfo = null;
+    }
+
+    private static class AutoPlayAtomicAnimationInfo {
+
+        public final float toProgress;
+        public final long endTime;
+
+        AutoPlayAtomicAnimationInfo(float toProgress, long duration) {
+            this.toProgress = toProgress;
+            this.endTime = duration + SystemClock.elapsedRealtime();
+        }
+    }
+}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
new file mode 100644
index 0000000..97f836f
--- /dev/null
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 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.touch;
+
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
+import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.os.Process;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.PromiseAppInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
+import com.android.launcher3.widget.WidgetAddFlowHandler;
+
+/**
+ * Class for handling clicks on workspace and all-apps items
+ */
+public class ItemClickHandler {
+
+    /**
+     * Instance used for click handling on items
+     */
+    public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
+
+    private static void onClick(View v) {
+        // Make sure that rogue clicks don't get through while allapps is launching, or after the
+        // view has detached (it's possible for this to happen if the view is removed mid touch).
+        if (v.getWindowToken() == null) {
+            return;
+        }
+
+        Launcher launcher = Launcher.getLauncher(v.getContext());
+        if (!launcher.getWorkspace().isFinishedSwitchingState()) {
+            return;
+        }
+
+        Object tag = v.getTag();
+        if (tag instanceof ShortcutInfo) {
+            onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
+        } else if (tag instanceof FolderInfo) {
+            if (v instanceof FolderIcon) {
+                onClickFolderIcon(v);
+            }
+        } else if (tag instanceof AppInfo) {
+            startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
+        } else if (tag instanceof LauncherAppWidgetInfo) {
+            if (v instanceof PendingAppWidgetHostView) {
+                onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
+            }
+        }
+    }
+
+    /**
+     * Event handler for a folder icon click.
+     *
+     * @param v The view that was clicked. Must be an instance of {@link FolderIcon}.
+     */
+    private static void onClickFolderIcon(View v) {
+        Folder folder = ((FolderIcon) v).getFolder();
+        if (!folder.isOpen() && !folder.isDestroyed()) {
+            // Open the requested folder
+            folder.animateOpen();
+        }
+    }
+
+    /**
+     * Event handler for the app widget view which has not fully restored.
+     */
+    private static void onClickPendingWidget(PendingAppWidgetHostView v, Launcher launcher) {
+        if (launcher.getPackageManager().isSafeMode()) {
+            Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+            return;
+        }
+
+        final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
+        if (v.isReadyForClickSetup()) {
+            LauncherAppWidgetProviderInfo appWidgetInfo = AppWidgetManagerCompat
+                    .getInstance(launcher).findProvider(info.providerName, info.user);
+            if (appWidgetInfo == null) {
+                return;
+            }
+            WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
+
+            if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+                if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
+                    // This should not happen, as we make sure that an Id is allocated during bind.
+                    return;
+                }
+                addFlowHandler.startBindFlow(launcher, info.appWidgetId, info,
+                        REQUEST_BIND_PENDING_APPWIDGET);
+            } else {
+                addFlowHandler.startConfigActivity(launcher, info, REQUEST_RECONFIGURE_APPWIDGET);
+            }
+        } else {
+            final String packageName = info.providerName.getPackageName();
+            onClickPendingAppItem(v, launcher, packageName, info.installProgress >= 0);
+        }
+    }
+
+    private static void onClickPendingAppItem(View v, Launcher launcher, String packageName,
+            boolean downloadStarted) {
+        if (downloadStarted) {
+            // If the download has started, simply direct to the market app.
+            startMarketIntentForPackage(v, launcher, packageName);
+            return;
+        }
+        new AlertDialog.Builder(launcher)
+                .setTitle(R.string.abandoned_promises_title)
+                .setMessage(R.string.abandoned_promise_explanation)
+                .setPositiveButton(R.string.abandoned_search,
+                        (d, i) -> startMarketIntentForPackage(v, launcher, packageName))
+                .setNeutralButton(R.string.abandoned_clean_this,
+                        (d, i) -> launcher.getWorkspace()
+                                .removeAbandonedPromise(packageName, Process.myUserHandle()))
+                .create().show();
+    }
+
+    private static void startMarketIntentForPackage(View v, Launcher launcher, String packageName) {
+        ItemInfo item = (ItemInfo) v.getTag();
+        Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
+        launcher.startActivitySafely(v, intent, item);
+    }
+
+    /**
+     * Event handler for an app shortcut click.
+     *
+     * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
+     */
+    public static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher) {
+        if (shortcut.isDisabled()) {
+            final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
+            if ((disabledFlags &
+                    ~FLAG_DISABLED_SUSPENDED &
+                    ~FLAG_DISABLED_QUIET_USER) == 0) {
+                // If the app is only disabled because of the above flags, launch activity anyway.
+                // Framework will tell the user why the app is suspended.
+            } else {
+                if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
+                    // Use a message specific to this shortcut, if it has one.
+                    Toast.makeText(launcher, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
+                    return;
+                }
+                // Otherwise just use a generic error message.
+                int error = R.string.activity_not_available;
+                if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) {
+                    error = R.string.safemode_shortcut_error;
+                } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 ||
+                        (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) {
+                    error = R.string.shortcut_not_available;
+                }
+                Toast.makeText(launcher, error, Toast.LENGTH_SHORT).show();
+                return;
+            }
+        }
+
+        // Check for abandoned promise
+        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
+            String packageName = shortcut.intent.getComponent() != null ?
+                    shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
+            if (!TextUtils.isEmpty(packageName)) {
+                onClickPendingAppItem(v, launcher, packageName,
+                        shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
+                return;
+            }
+        }
+
+        // Start activities
+        startAppShortcutOrInfoActivity(v, shortcut, launcher);
+    }
+
+    private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
+        Intent intent;
+        if (item instanceof PromiseAppInfo) {
+            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
+            intent = promiseAppInfo.getMarketIntent(launcher);
+        } else {
+            intent = item.getIntent();
+        }
+        if (intent == null) {
+            throw new IllegalArgumentException("Input must have a valid intent");
+        }
+        if (item instanceof ShortcutInfo) {
+            ShortcutInfo si = (ShortcutInfo) item;
+            if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
+                    && intent.getAction() == Intent.ACTION_VIEW) {
+                // make a copy of the intent that has the package set to null
+                // we do this because the platform sometimes disables instant
+                // apps temporarily (triggered by the user) and fallbacks to the
+                // web ui. This only works though if the package isn't set
+                intent = new Intent(intent);
+                intent.setPackage(null);
+            }
+        }
+        launcher.startActivitySafely(v, intent, item);
+    }
+}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
new file mode 100644
index 0000000..6f012f6
--- /dev/null
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 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.touch;
+
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.folder.Folder;
+
+/**
+ * Class to handle long-clicks on workspace items and start drag as a result.
+ */
+public class ItemLongClickListener {
+
+    public static OnLongClickListener INSTANCE_WORKSPACE =
+            ItemLongClickListener::onWorkspaceItemLongClick;
+
+    public static OnLongClickListener INSTANCE_ALL_APPS =
+            ItemLongClickListener::onAllAppsItemLongClick;
+
+    private static boolean onWorkspaceItemLongClick(View v) {
+        Launcher launcher = Launcher.getLauncher(v.getContext());
+        if (!canStartDrag(launcher)) return false;
+        if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
+        if (!(v.getTag() instanceof ItemInfo)) return false;
+
+        launcher.setWaitingForResult(null);
+        beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());
+        return true;
+    }
+
+    public static void beginDrag(View v, Launcher launcher, ItemInfo info,
+            DragOptions dragOptions) {
+        if (info.container >= 0) {
+            Folder folder = Folder.getOpen(launcher);
+            if (folder != null) {
+                if (!folder.getItemsInReadingOrder().contains(v)) {
+                    folder.close(true);
+                } else {
+                    folder.startDrag(v, dragOptions);
+                    return;
+                }
+            }
+        }
+
+        CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info);
+        launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
+    }
+
+    private static boolean onAllAppsItemLongClick(View v) {
+        Launcher launcher = Launcher.getLauncher(v.getContext());
+        if (!canStartDrag(launcher)) return false;
+        // When we have exited all apps or are in transition, disregard long clicks
+        if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
+        if (launcher.getWorkspace().isSwitchingState()) return false;
+
+        // Start the drag
+        final DragController dragController = launcher.getDragController();
+        dragController.addDragListener(new DragController.DragListener() {
+            @Override
+            public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+                v.setVisibility(INVISIBLE);
+            }
+
+            @Override
+            public void onDragEnd() {
+                v.setVisibility(VISIBLE);
+                dragController.removeDragListener(this);
+            }
+        });
+
+        DeviceProfile grid = launcher.getDeviceProfile();
+        DragOptions options = new DragOptions();
+        options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
+        launcher.getWorkspace().beginDragShared(v, launcher.getAppsView(), options);
+        return false;
+    }
+
+    public static boolean canStartDrag(Launcher launcher) {
+        if (launcher == null) {
+            return false;
+        }
+        // We prevent dragging when we are loading the workspace as it is possible to pick up a view
+        // that is subsequently removed from the workspace in startBinding().
+        if (launcher.isWorkspaceLocked()) return false;
+        // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
+        if (launcher.getDragController().isDragging()) return false;
+
+        return true;
+    }
+}
diff --git a/src/com/android/launcher3/touch/SwipeDetector.java b/src/com/android/launcher3/touch/SwipeDetector.java
index 4b36ad9..703e4fd 100644
--- a/src/com/android/launcher3/touch/SwipeDetector.java
+++ b/src/com/android/launcher3/touch/SwipeDetector.java
@@ -194,6 +194,10 @@
         mIgnoreSlopWhenSettling = ignoreSlop;
     }
 
+    public int getScrollDirections() {
+        return mScrollConditions;
+    }
+
     private boolean shouldScrollStart(MotionEvent ev, int pointerIndex) {
         // reject cases where the angle or slop condition is not met.
         if (Math.max(mDir.getActiveTouchSlop(ev, pointerIndex, mDownPos), mTouchSlop)
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
new file mode 100644
index 0000000..f59f14e
--- /dev/null
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 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.touch;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.ViewConfiguration.getLongPressTimeout;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.HapticFeedbackConstants;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.OptionsPopupView;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+
+/**
+ * Helper class to handle touch on empty space in workspace and show options popup on long press
+ */
+public class WorkspaceTouchListener implements OnTouchListener, Runnable {
+
+    /**
+     * STATE_PENDING_PARENT_INFORM is the state between longPress performed & the next motionEvent.
+     * This next event is used to send an ACTION_CANCEL to Workspace, to that it clears any
+     * temporary scroll state. After that, the state is set to COMPLETED, and we just eat up all
+     * subsequent motion events.
+     */
+    private static final int STATE_CANCELLED = 0;
+    private static final int STATE_REQUESTED = 1;
+    private static final int STATE_PENDING_PARENT_INFORM = 2;
+    private static final int STATE_COMPLETED = 3;
+
+    private final Rect mTempRect = new Rect();
+    private final Launcher mLauncher;
+    private final Workspace mWorkspace;
+    private final PointF mTouchDownPoint = new PointF();
+
+    private int mLongPressState = STATE_CANCELLED;
+
+    public WorkspaceTouchListener(Launcher launcher, Workspace workspace) {
+        mLauncher = launcher;
+        mWorkspace = workspace;
+    }
+
+    @Override
+    public boolean onTouch(View view, MotionEvent ev) {
+        int action = ev.getActionMasked();
+        if (action == ACTION_DOWN) {
+            // Check if we can handle long press.
+            boolean handleLongPress = canHandleLongPress();
+
+            if (handleLongPress) {
+                // Check if the event is not near the edges
+                DeviceProfile dp = mLauncher.getDeviceProfile();
+                DragLayer dl = mLauncher.getDragLayer();
+                Rect insets = dp.getInsets();
+
+                mTempRect.set(insets.left, insets.top, dl.getWidth() - insets.right,
+                        dl.getHeight() - insets.bottom);
+                mTempRect.inset(dp.edgeMarginPx, dp.edgeMarginPx);
+                handleLongPress = mTempRect.contains((int) ev.getX(), (int) ev.getY());
+            }
+
+            cancelLongPress();
+            if (handleLongPress) {
+                mLongPressState = STATE_REQUESTED;
+                mTouchDownPoint.set(ev.getX(), ev.getY());
+                mWorkspace.postDelayed(this, getLongPressTimeout());
+            }
+
+            mWorkspace.onTouchEvent(ev);
+            // Return true to keep receiving touch events
+            return true;
+        }
+
+        if (mLongPressState == STATE_PENDING_PARENT_INFORM) {
+            // Inform the workspace to cancel touch handling
+            ev.setAction(ACTION_CANCEL);
+            mWorkspace.onTouchEvent(ev);
+
+            ev.setAction(action);
+            mLongPressState = STATE_COMPLETED;
+        }
+
+        final boolean result;
+        if (mLongPressState == STATE_COMPLETED) {
+            // We have handled the touch, so workspace does not need to know anything anymore.
+            result = true;
+        } else if (mLongPressState == STATE_REQUESTED) {
+            mWorkspace.onTouchEvent(ev);
+            if (mWorkspace.isHandlingTouch()) {
+                cancelLongPress();
+            }
+
+            result = true;
+        } else {
+            // We don't want to handle touch, let workspace handle it as usual.
+            result = false;
+        }
+
+        if (action == ACTION_UP || action == ACTION_POINTER_UP) {
+            if (!mWorkspace.isTouchActive()) {
+                final CellLayout currentPage =
+                        (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
+                if (currentPage != null) {
+                    mWorkspace.onWallpaperTap(ev);
+                }
+            }
+        }
+
+        if (action == ACTION_UP || action == ACTION_CANCEL) {
+            cancelLongPress();
+        }
+        return result;
+    }
+
+    private boolean canHandleLongPress() {
+        return AbstractFloatingView.getTopOpenView(mLauncher) == null
+                && mLauncher.isInState(NORMAL);
+    }
+
+    private void cancelLongPress() {
+        mWorkspace.removeCallbacks(this);
+        mLongPressState = STATE_CANCELLED;
+    }
+
+    @Override
+    public void run() {
+        if (mLongPressState == STATE_REQUESTED) {
+            if (canHandleLongPress()) {
+                mLongPressState = STATE_PENDING_PARENT_INFORM;
+                mWorkspace.getParent().requestDisallowInterceptTouchEvent(true);
+
+                mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+                mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
+                        Action.Direction.NONE, ContainerType.WORKSPACE,
+                        mWorkspace.getCurrentPage());
+                OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+            } else {
+                cancelLongPress();
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
index 242df2e..d478ffa 100644
--- a/src/com/android/launcher3/util/ComponentKey.java
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -17,12 +17,8 @@
  */
 
 import android.content.ComponentName;
-import android.content.Context;
-import android.os.Process;
 import android.os.UserHandle;
 
-import com.android.launcher3.compat.UserManagerCompat;
-
 import java.util.Arrays;
 
 public class ComponentKey {
@@ -41,29 +37,6 @@
 
     }
 
-    /**
-     * Creates a new component key from an encoded component key string in the form of
-     * [flattenedComponentString#userId].  If the userId is not present, then it defaults
-     * to the current user.
-     */
-    public ComponentKey(Context context, String componentKeyStr) {
-        int userDelimiterIndex = componentKeyStr.indexOf("#");
-        if (userDelimiterIndex != -1) {
-            String componentStr = componentKeyStr.substring(0, userDelimiterIndex);
-            Long componentUser = Long.valueOf(componentKeyStr.substring(userDelimiterIndex + 1));
-            componentName = ComponentName.unflattenFromString(componentStr);
-            user = UserManagerCompat.getInstance(context)
-                    .getUserForSerialNumber(componentUser.longValue());
-        } else {
-            // No user provided, default to the current user
-            componentName = ComponentName.unflattenFromString(componentKeyStr);
-            user = Process.myUserHandle();
-        }
-        Preconditions.assertNotNull(componentName);
-        Preconditions.assertNotNull(user);
-        mHashCode = Arrays.hashCode(new Object[] {componentName, user});
-    }
-
     @Override
     public int hashCode() {
         return mHashCode;
diff --git a/src/com/android/launcher3/util/FlingBlockCheck.java b/src/com/android/launcher3/util/FlingBlockCheck.java
new file mode 100644
index 0000000..f9575b9
--- /dev/null
+++ b/src/com/android/launcher3/util/FlingBlockCheck.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.os.SystemClock;
+
+/**
+ * Determines whether a fling should be blocked. Currently we block flings when crossing thresholds
+ * to new states, and unblock after a short duration.
+ */
+public class FlingBlockCheck {
+    // Allow flinging to a new state after waiting this many milliseconds.
+    private static final long UNBLOCK_FLING_PAUSE_DURATION = 200;
+
+    private boolean mBlockFling;
+    private long mBlockFlingTime;
+
+    public void blockFling() {
+        mBlockFling = true;
+        mBlockFlingTime = SystemClock.uptimeMillis();
+    }
+
+    public void unblockFling() {
+        mBlockFling = false;
+        mBlockFlingTime = 0;
+    }
+
+    public void onEvent() {
+        // We prevent flinging after passing a state, but allow it if the user pauses briefly.
+        if (SystemClock.uptimeMillis() - mBlockFlingTime >= UNBLOCK_FLING_PAUSE_DURATION) {
+            mBlockFling = false;
+        }
+    }
+
+    public boolean isBlocked() {
+        return mBlockFling;
+    }
+}
diff --git a/src/com/android/launcher3/util/FloatRange.java b/src/com/android/launcher3/util/FloatRange.java
deleted file mode 100644
index 12772f3..0000000
--- a/src/com/android/launcher3/util/FloatRange.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-/**
- * A mutable class for describing the range of two int values.
- */
-public class FloatRange {
-
-    public float start, end;
-
-    public FloatRange() { }
-
-    public FloatRange(float s, float e) {
-        set(s, e);
-    }
-
-    public void set(float s, float e) {
-        start = s;
-        end = e;
-    }
-
-    public boolean contains(float value) {
-        return value >= start && value <= end;
-    }
-}
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index b80e94d..b793f54 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -177,7 +177,10 @@
             }
             int cx = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellX;
             int cy = ((CellLayout.LayoutParams) cell.getLayoutParams()).cellY;
-            matrix[invert ? (m - cx - 1) : cx][cy] = i;
+            int x = invert ? (m - cx - 1) : cx;
+            if (x < m && cy < n) { // check if view fits into matrix, else skip
+                matrix[x][cy] = i;
+            }
         }
         if (DEBUG) {
             printMatrix(matrix);
diff --git a/src/com/android/launcher3/util/InstantAppResolver.java b/src/com/android/launcher3/util/InstantAppResolver.java
index 601a5ab..5dc7af8 100644
--- a/src/com/android/launcher3/util/InstantAppResolver.java
+++ b/src/com/android/launcher3/util/InstantAppResolver.java
@@ -22,9 +22,7 @@
 import android.util.Log;
 
 import com.android.launcher3.AppInfo;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,10 +30,10 @@
 /**
  * A wrapper class to access instant app related APIs.
  */
-public class InstantAppResolver {
+public class InstantAppResolver implements ResourceBasedOverride {
 
     public static InstantAppResolver newInstance(Context context) {
-        return Utilities.getOverrideObject(
+        return Overrides.getObject(
                 InstantAppResolver.class, context, R.string.instant_app_resolver_class);
     }
 
@@ -47,8 +45,8 @@
         return false;
     }
 
-    public boolean isInstantApp(Launcher launcher, String packageName) {
-        PackageManager packageManager = launcher.getPackageManager();
+    public boolean isInstantApp(Context context, String packageName) {
+        PackageManager packageManager = context.getPackageManager();
         try {
             return isInstantApp(packageManager.getPackageInfo(packageName, 0).applicationInfo);
         } catch (PackageManager.NameNotFoundException e) {
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index daedaef..19cf6c1 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -18,7 +18,6 @@
 
 import android.content.ComponentName;
 import android.os.UserHandle;
-import android.util.SparseLongArray;
 
 import com.android.launcher3.FolderInfo;
 import com.android.launcher3.ItemInfo;
@@ -32,14 +31,14 @@
 /**
  * A utility class to check for {@link ItemInfo}
  */
-public abstract class ItemInfoMatcher {
+public interface ItemInfoMatcher {
 
-    public abstract boolean matches(ItemInfo info, ComponentName cn);
+    boolean matches(ItemInfo info, ComponentName cn);
 
     /**
      * Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
      */
-    public final HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
+    default HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
         HashSet<ItemInfo> filtered = new HashSet<>();
         for (ItemInfo i : infos) {
             if (i instanceof ShortcutInfo) {
@@ -70,88 +69,43 @@
     /**
      * Returns a new matcher with returns true if either this or {@param matcher} returns true.
      */
-    public ItemInfoMatcher or(final ItemInfoMatcher matcher) {
-       final ItemInfoMatcher that = this;
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return that.matches(info, cn) || matcher.matches(info, cn);
-            }
-        };
+    default ItemInfoMatcher or(ItemInfoMatcher matcher) {
+        return (info, cn) -> matches(info, cn) || matcher.matches(info, cn);
     }
 
     /**
      * Returns a new matcher with returns true if both this and {@param matcher} returns true.
      */
-    public ItemInfoMatcher and(final ItemInfoMatcher matcher) {
-        final ItemInfoMatcher that = this;
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return that.matches(info, cn) && matcher.matches(info, cn);
-            }
-        };
+    default ItemInfoMatcher and(ItemInfoMatcher matcher) {
+        return (info, cn) -> matches(info, cn) && matcher.matches(info, cn);
     }
 
     /**
      * Returns a new matcher which returns the opposite boolean value of the provided
      * {@param matcher}.
      */
-    public static ItemInfoMatcher not(final ItemInfoMatcher matcher) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return !matcher.matches(info, cn);
-            }
-        };
+    static ItemInfoMatcher not(ItemInfoMatcher matcher) {
+        return (info, cn) -> !matcher.matches(info, cn);
     }
 
-    public static ItemInfoMatcher ofUser(final UserHandle user) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return info.user.equals(user);
-            }
-        };
+    static ItemInfoMatcher ofUser(UserHandle user) {
+        return (info, cn) -> info.user.equals(user);
     }
 
-    public static ItemInfoMatcher ofComponents(
-            final HashSet<ComponentName> components, final UserHandle user) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return components.contains(cn) && info.user.equals(user);
-            }
-        };
+    static ItemInfoMatcher ofComponents(HashSet<ComponentName> components, UserHandle user) {
+        return (info, cn) -> components.contains(cn) && info.user.equals(user);
     }
 
-    public static ItemInfoMatcher ofPackages(
-            final HashSet<String> packageNames, final UserHandle user) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
-            }
-        };
+    static ItemInfoMatcher ofPackages(HashSet<String> packageNames, UserHandle user) {
+        return (info, cn) -> packageNames.contains(cn.getPackageName()) && info.user.equals(user);
     }
 
-    public static ItemInfoMatcher ofShortcutKeys(final HashSet<ShortcutKey> keys) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
+    static ItemInfoMatcher ofShortcutKeys(HashSet<ShortcutKey> keys) {
+        return  (info, cn) -> info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
                         keys.contains(ShortcutKey.fromItemInfo(info));
-            }
-        };
     }
 
-    public static ItemInfoMatcher ofItemIds(
-            final LongArrayMap<Boolean> ids, final Boolean matchDefault) {
-        return new ItemInfoMatcher() {
-            @Override
-            public boolean matches(ItemInfo info, ComponentName cn) {
-                return ids.get(info.id, matchDefault);
-            }
-        };
+    static ItemInfoMatcher ofItemIds(LongArrayMap<Boolean> ids, Boolean matchDefault) {
+        return (info, cn) -> ids.get(info.id, matchDefault);
     }
 }
diff --git a/src/com/android/launcher3/util/ListViewHighlighter.java b/src/com/android/launcher3/util/ListViewHighlighter.java
new file mode 100644
index 0000000..ecad2af
--- /dev/null
+++ b/src/com/android/launcher3/util/ListViewHighlighter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.v4.graphics.ColorUtils;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.AbsListView.RecyclerListener;
+import android.widget.ListView;
+
+import com.android.launcher3.R;
+
+/**
+ * Utility class to scroll and highlight a list view item
+ */
+public class ListViewHighlighter implements OnScrollListener, RecyclerListener,
+        OnLayoutChangeListener {
+
+    private final ListView mListView;
+    private int mPosHighlight;
+
+    private boolean mColorAnimated = false;
+
+    public ListViewHighlighter(ListView listView, int posHighlight) {
+        mListView = listView;
+        mPosHighlight = posHighlight;
+        mListView.setOnScrollListener(this);
+        mListView.setRecyclerListener(this);
+        mListView.addOnLayoutChangeListener(this);
+
+        mListView.post(this::tryHighlight);
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        mListView.post(this::tryHighlight);
+    }
+
+    private void tryHighlight() {
+        if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
+            return;
+        }
+        if (!highlightIfVisible(mListView.getFirstVisiblePosition(),
+                mListView.getLastVisiblePosition())) {
+            mListView.smoothScrollToPosition(mPosHighlight);
+        }
+    }
+
+    @Override
+    public void onScrollStateChanged(AbsListView absListView, int i) { }
+
+    @Override
+    public void onScroll(AbsListView view, int firstVisibleItem,
+            int visibleItemCount, int totalItemCount) {
+        highlightIfVisible(firstVisibleItem, firstVisibleItem + visibleItemCount);
+    }
+
+    private boolean highlightIfVisible(int start, int end) {
+        if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
+            return false;
+        }
+        if (start > mPosHighlight || mPosHighlight > end) {
+            return false;
+        }
+        highlightView(mListView.getChildAt(mPosHighlight - start));
+
+        // finish highlight
+        mListView.setOnScrollListener(null);
+        mListView.removeOnLayoutChangeListener(this);
+
+        mPosHighlight = -1;
+        return true;
+    }
+
+    @Override
+    public void onMovedToScrapHeap(View view) {
+        unhighlightView(view);
+    }
+
+    private void highlightView(View view) {
+        if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
+            // already highlighted
+        } else {
+            view.setTag(R.id.view_highlighted, true);
+            view.setTag(R.id.view_unhighlight_background, view.getBackground());
+            view.setBackground(getHighlightBackground());
+            view.postDelayed(() -> {
+                unhighlightView(view);
+            }, 15000L);
+        }
+    }
+
+    private void unhighlightView(View view) {
+        if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
+            Object background = view.getTag(R.id.view_unhighlight_background);
+            if (background instanceof Drawable) {
+                view.setBackground((Drawable) background);
+            }
+            view.setTag(R.id.view_unhighlight_background, null);
+            view.setTag(R.id.view_highlighted, false);
+        }
+    }
+
+    private ColorDrawable getHighlightBackground() {
+        int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(mListView.getContext()), 26);
+        if (mColorAnimated) {
+            return new ColorDrawable(color);
+        }
+        mColorAnimated = true;
+        ColorDrawable bg = new ColorDrawable(Color.WHITE);
+        ObjectAnimator anim = ObjectAnimator.ofInt(bg, "color", Color.WHITE, color);
+        anim.setEvaluator(new ArgbEvaluator());
+        anim.setDuration(200L);
+        anim.setRepeatMode(ValueAnimator.REVERSE);
+        anim.setRepeatCount(4);
+        anim.start();
+        return bg;
+    }
+}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
new file mode 100644
index 0000000..5747db1
--- /dev/null
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.content.Context;
+import android.os.Looper;
+
+import com.android.launcher3.MainThreadExecutor;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Utility class for defining singletons which are initiated on main thread.
+ */
+public class MainThreadInitializedObject<T> {
+
+    private final ObjectProvider<T> mProvider;
+    private T mValue;
+
+    public MainThreadInitializedObject(ObjectProvider<T> provider) {
+        mProvider = provider;
+    }
+
+    public T get(Context context) {
+        if (mValue == null) {
+            if (Looper.myLooper() == Looper.getMainLooper()) {
+                mValue = mProvider.get(context.getApplicationContext());
+            } else {
+                try {
+                    return new MainThreadExecutor().submit(() -> get(context)).get();
+                } catch (InterruptedException|ExecutionException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return mValue;
+    }
+
+    public T getNoCreate() {
+        return mValue;
+    }
+
+    public interface ObjectProvider<T> {
+
+        T get(Context context);
+    }
+}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
deleted file mode 100644
index 009aee7..0000000
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (C) 2015 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.util;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.LauncherActivityInfo;
-import android.os.Handler;
-import android.os.Process;
-import android.os.UserHandle;
-
-import com.android.launcher3.FolderInfo;
-import com.android.launcher3.InstallShortcutReceiver;
-import com.android.launcher3.ItemInfo;
-import com.android.launcher3.LauncherFiles;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.R;
-import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.ModelWriter;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Handles addition of app shortcuts for managed profiles.
- * Methods of class should only be called on {@link LauncherModel#sWorkerThread}.
- */
-public class ManagedProfileHeuristic {
-
-    private static final String USER_FOLDER_ID_PREFIX = "user_folder_";
-
-    /**
-     * Duration (in milliseconds) for which app shortcuts will be added to work folder.
-     */
-    private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000;
-
-    public static void onAllAppsLoaded(final Context context,
-            List<LauncherActivityInfo> apps, UserHandle user) {
-        if (Process.myUserHandle().equals(user)) {
-            return;
-        }
-
-        UserFolderInfo ufi = new UserFolderInfo(context, user, null);
-        // We only handle folder creation once. Later icon additions are handled using package
-        // or session events.
-        if (ufi.folderAlreadyCreated) {
-            return;
-        }
-
-        if (Utilities.ATLEAST_OREO && !SessionCommitReceiver.isEnabled(context)) {
-            // Just mark the folder id preference to avoid new folder creation later.
-            ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply();
-            return;
-        }
-
-        InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_BULK_ADD);
-        for (LauncherActivityInfo app : apps) {
-            // Queue all items which should go in the work folder.
-            if (app.getFirstInstallTime() < ufi.addIconToFolderTime) {
-                InstallShortcutReceiver.queueActivityInfo(app, context);
-            }
-        }
-        // Post the queue update on next frame, so that the loader gets finished.
-        new Handler(LauncherModel.getWorkerLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                InstallShortcutReceiver.disableAndFlushInstallQueue(
-                        InstallShortcutReceiver.FLAG_BULK_ADD, context);
-            }
-        });
-    }
-
-
-    /**
-     * Utility class to help workspace icon addition.
-     */
-    public static class UserFolderInfo {
-
-        final ArrayList<ShortcutInfo> pendingShortcuts = new ArrayList<>();
-
-        final UserHandle user;
-
-        final long userSerial;
-        // Time until which icons will be added to folder instead.
-        final long addIconToFolderTime;
-
-        final String folderIdKey;
-        final SharedPreferences prefs;
-
-        final boolean folderAlreadyCreated;
-        final FolderInfo folderInfo;
-
-        boolean folderPendingAddition;
-
-        public UserFolderInfo(Context context, UserHandle user, BgDataModel dataModel) {
-            this.user = user;
-
-            UserManagerCompat um = UserManagerCompat.getInstance(context);
-            userSerial = um.getSerialNumberForUser(user);
-            addIconToFolderTime = um.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION;
-
-            folderIdKey = USER_FOLDER_ID_PREFIX + userSerial;
-            prefs = prefs(context);
-
-            folderAlreadyCreated = prefs.contains(folderIdKey);
-            if (dataModel != null) {
-                if (folderAlreadyCreated) {
-                    long folderId = prefs.getLong(folderIdKey, ItemInfo.NO_ID);
-                    folderInfo = dataModel.folders.get(folderId);
-                } else {
-                    folderInfo = new FolderInfo();
-                    folderInfo.title = context.getText(R.string.work_folder_name);
-                    folderInfo.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
-                    folderPendingAddition = true;
-                }
-            } else {
-                folderInfo = null;
-            }
-        }
-
-        /**
-         * Returns the ItemInfo which should be added to the workspace. In case the the provided
-         * {@link ShortcutInfo} or a wrapped {@link FolderInfo} or null.
-         */
-        public ItemInfo convertToWorkspaceItem(
-                ShortcutInfo shortcut, LauncherActivityInfo activityInfo) {
-            if (activityInfo.getFirstInstallTime() >= addIconToFolderTime) {
-                return shortcut;
-            }
-
-            if (folderAlreadyCreated) {
-                if (folderInfo == null) {
-                    // Work folder was deleted by user, add icon to home screen.
-                    return shortcut;
-                } else {
-                    // Add item to work folder instead. Nothing needs to be added
-                    // on the homescreen.
-                    pendingShortcuts.add(shortcut);
-                    return null;
-                }
-            }
-
-            pendingShortcuts.add(shortcut);
-            folderInfo.add(shortcut, false);
-            if (folderPendingAddition) {
-                folderPendingAddition = false;
-                return folderInfo;
-            } else {
-                // WorkFolder already requested to be added. Nothing new needs to be added.
-                return null;
-            }
-        }
-
-        public void applyPendingState(ModelWriter writer) {
-            if (folderInfo == null) {
-                return;
-            }
-
-            int startingRank = 0;
-            if (folderAlreadyCreated) {
-                startingRank = folderInfo.contents.size();
-            }
-
-            for (ShortcutInfo info : pendingShortcuts) {
-                info.rank = startingRank++;
-                writer.addItemToDatabase(info, folderInfo.id, 0, 0, 0);
-            }
-
-            if (folderAlreadyCreated) {
-                // FolderInfo could already be bound. We need to add shortcuts on the UI thread.
-                new MainThreadExecutor().execute(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        folderInfo.prepareAutoUpdate();
-                        for (ShortcutInfo info : pendingShortcuts) {
-                            folderInfo.add(info, false);
-                        }
-                    }
-                });
-            } else {
-                prefs.edit().putLong(folderIdKey, folderInfo.id).apply();
-            }
-        }
-    }
-
-    /**
-     * Verifies that entries corresponding to {@param users} exist and removes all invalid entries.
-     */
-    public static void processAllUsers(List<UserHandle> users, Context context) {
-        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
-        HashSet<String> validKeys = new HashSet<>();
-        for (UserHandle user : users) {
-            validKeys.add(USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user));
-        }
-
-        SharedPreferences prefs = prefs(context);
-        SharedPreferences.Editor editor = prefs.edit();
-        for (String key : prefs.getAll().keySet()) {
-            if (!validKeys.contains(key)) {
-                editor.remove(key);
-            }
-        }
-        editor.apply();
-    }
-
-    /**
-     * For each user, if a work folder has not been created, mark it such that the folder will
-     * never get created.
-     */
-    public static void markExistingUsersForNoFolderCreation(Context context) {
-        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
-        UserHandle myUser = Process.myUserHandle();
-
-        SharedPreferences prefs = null;
-        for (UserHandle user : userManager.getUserProfiles()) {
-            if (myUser.equals(user)) {
-                continue;
-            }
-            if (prefs == null) {
-                prefs = prefs(context);
-            }
-            String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user);
-            if (!prefs.contains(folderIdKey)) {
-                prefs.edit().putLong(folderIdKey, ItemInfo.NO_ID).apply();
-            }
-        }
-    }
-
-    public static SharedPreferences prefs(Context context) {
-        return context.getSharedPreferences(
-                LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE);
-    }
-}
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
new file mode 100644
index 0000000..f810f48
--- /dev/null
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Utility class to handle separating a single value as a factor of multiple values
+ */
+public class MultiValueAlpha {
+
+    public static final Property<AlphaProperty, Float> VALUE =
+            new Property<AlphaProperty, Float>(Float.TYPE, "value") {
+
+                @Override
+                public Float get(AlphaProperty alphaProperty) {
+                    return alphaProperty.mValue;
+                }
+
+                @Override
+                public void set(AlphaProperty object, Float value) {
+                    object.setValue(value);
+                }
+            };
+
+    private final View mView;
+    private final AlphaProperty[] mMyProperties;
+
+    private int mValidMask;
+
+    public MultiValueAlpha(View view, int size) {
+        mView = view;
+        mMyProperties = new AlphaProperty[size];
+
+        mValidMask = 0;
+        for (int i = 0; i < size; i++) {
+            int myMask = 1 << i;
+            mValidMask |= myMask;
+            mMyProperties[i] = new AlphaProperty(myMask);
+        }
+    }
+
+    public AlphaProperty getProperty(int index) {
+        return mMyProperties[index];
+    }
+
+    public class AlphaProperty {
+
+        private final int mMyMask;
+
+        private float mValue = 1;
+        // Factor of all other alpha channels, only valid if mMyMask is present in mValidMask.
+        private float mOthers = 1;
+
+        AlphaProperty(int myMask) {
+            mMyMask = myMask;
+        }
+
+        public void setValue(float value) {
+            if (mValue == value) {
+                return;
+            }
+
+            if ((mValidMask & mMyMask) == 0) {
+                // Our cache value is not correct, recompute it.
+                mOthers = 1;
+                for (AlphaProperty prop : mMyProperties) {
+                    if (prop != this) {
+                        mOthers *= prop.mValue;
+                    }
+                }
+            }
+
+            // Since we have changed our value, all other caches except our own need to be
+            // recomputed. Change mValidMask to indicate the new valid caches (only our own).
+            mValidMask = mMyMask;
+            mValue = value;
+
+            mView.setAlpha(mOthers * mValue);
+        }
+
+        public float getValue() {
+            return mValue;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java b/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
new file mode 100644
index 0000000..05a7d27
--- /dev/null
+++ b/src/com/android/launcher3/util/NoLocaleSQLiteHelper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import static android.database.sqlite.SQLiteDatabase.NO_LOCALIZED_COLLATORS;
+
+import static com.android.launcher3.Utilities.ATLEAST_P;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.DatabaseErrorHandler;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDatabase.CursorFactory;
+import android.database.sqlite.SQLiteDatabase.OpenParams;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Extension of {@link SQLiteOpenHelper} which avoids creating default locale table by
+ * A context wrapper which creates databases without support for localized collators.
+ */
+public abstract class NoLocaleSQLiteHelper extends SQLiteOpenHelper {
+
+    public NoLocaleSQLiteHelper(Context context, String name, int version) {
+        super(ATLEAST_P ? context : new NoLocalContext(context), name, null, version);
+        if (ATLEAST_P) {
+            setOpenParams(new OpenParams.Builder().addOpenFlags(NO_LOCALIZED_COLLATORS).build());
+        }
+    }
+
+    private static class NoLocalContext extends ContextWrapper {
+        public NoLocalContext(Context base) {
+            super(base);
+        }
+
+        @Override
+        public SQLiteDatabase openOrCreateDatabase(
+                String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
+            return super.openOrCreateDatabase(
+                    name, mode | Context.MODE_NO_LOCALIZED_COLLATORS, factory, errorHandler);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/NoLocaleSqliteContext.java b/src/com/android/launcher3/util/NoLocaleSqliteContext.java
deleted file mode 100644
index c8a5ffb..0000000
--- a/src/com/android/launcher3/util/NoLocaleSqliteContext.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.android.launcher3.util;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.database.DatabaseErrorHandler;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDatabase.CursorFactory;
-
-/**
- * A context wrapper which creates databases without support for localized collators.
- */
-public class NoLocaleSqliteContext extends ContextWrapper {
-
-    public NoLocaleSqliteContext(Context context) {
-        super(context);
-    }
-
-    @Override
-    public SQLiteDatabase openOrCreateDatabase(
-            String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
-        return super.openOrCreateDatabase(
-                name, mode | Context.MODE_NO_LOCALIZED_COLLATORS, factory, errorHandler);
-    }
-}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 81df153..0b3b632 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -17,6 +17,8 @@
 package com.android.launcher3.util;
 
 import android.app.AppOpsManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -24,13 +26,23 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
 
 import com.android.launcher3.AppInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.PromiseAppInfo;
 import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.LauncherAppsCompat;
 
@@ -42,6 +54,8 @@
  */
 public class PackageManagerHelper {
 
+    private static final String TAG = "PackageManagerHelper";
+
     private final Context mContext;
     private final PackageManager mPm;
     private final LauncherAppsCompat mLauncherApps;
@@ -169,4 +183,35 @@
             throw new RuntimeException(e);
         }
     }
+
+
+    /**
+     * Starts the details activity for {@code info}
+     */
+    public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
+        if (info instanceof PromiseAppInfo) {
+            PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
+            mContext.startActivity(promiseAppInfo.getMarketIntent(mContext));
+            return;
+        }
+        ComponentName componentName = null;
+        if (info instanceof AppInfo) {
+            componentName = ((AppInfo) info).componentName;
+        } else if (info instanceof ShortcutInfo) {
+            componentName = info.getTargetComponent();
+        } else if (info instanceof PendingAddItemInfo) {
+            componentName = ((PendingAddItemInfo) info).componentName;
+        } else if (info instanceof LauncherAppWidgetInfo) {
+            componentName = ((LauncherAppWidgetInfo) info).providerName;
+        }
+        if (componentName != null) {
+            try {
+                mLauncherApps.showAppDetailsForProfile(
+                        componentName, info.user, sourceBounds, opts);
+            } catch (SecurityException | ActivityNotFoundException e) {
+                Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+                Log.e(TAG, "Unable to launch settings", e);
+            }
+        }
+    }
 }
diff --git a/src/com/android/launcher3/util/PendingAnimation.java b/src/com/android/launcher3/util/PendingAnimation.java
new file mode 100644
index 0000000..617a38b
--- /dev/null
+++ b/src/com/android/launcher3/util/PendingAnimation.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Utility class to keep track of a running animation.
+ *
+ * This class allows attaching end callbacks to an animation is intended to be used with
+ * {@link com.android.launcher3.anim.AnimatorPlaybackController}, since in that case
+ * AnimationListeners are not properly dispatched.
+ */
+@TargetApi(Build.VERSION_CODES.O)
+public class PendingAnimation {
+
+    private final ArrayList<Consumer<OnEndListener>> mEndListeners = new ArrayList<>();
+
+    public final AnimatorSet anim;
+
+    public PendingAnimation(AnimatorSet anim) {
+        this.anim = anim;
+    }
+
+    public void finish(boolean isSuccess, int logAction) {
+        for (Consumer<OnEndListener> listeners : mEndListeners) {
+            listeners.accept(new OnEndListener(isSuccess, logAction));
+        }
+        mEndListeners.clear();
+    }
+
+    public void addEndListener(Consumer<OnEndListener> listener) {
+        mEndListeners.add(listener);
+    }
+
+    public static class OnEndListener {
+        public boolean isSuccess;
+        public int logAction;
+
+        public OnEndListener(boolean isSuccess, int logAction) {
+            this.isSuccess = isSuccess;
+            this.logAction = logAction;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
index dabd40d..b8bcfed 100644
--- a/src/com/android/launcher3/util/PendingRequestArgs.java
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -57,7 +57,7 @@
 
         mArg1 = parcel.readInt();
         mObjectType = parcel.readInt();
-        mObject = parcel.readParcelable(null);
+        mObject = parcel.readParcelable(getClass().getClassLoader());
     }
 
     @Override
diff --git a/src/com/android/launcher3/util/Provider.java b/src/com/android/launcher3/util/Provider.java
index 1cdd8d6..4a54c0f 100644
--- a/src/com/android/launcher3/util/Provider.java
+++ b/src/com/android/launcher3/util/Provider.java
@@ -19,20 +19,15 @@
 /**
  * Utility class to allow lazy initialization of objects.
  */
-public abstract class Provider<T> {
+public interface Provider<T> {
 
     /**
      * Initializes and returns the object. This may contain expensive operations not suitable
      * to UI thread.
      */
-    public abstract T get();
+    T get();
 
-    public static <T> Provider<T> of (final T value) {
-        return new Provider<T>() {
-            @Override
-            public T get() {
-                return value;
-            }
-        };
+    static <T> Provider<T> of (T value) {
+        return() -> value;
     }
 }
diff --git a/src/com/android/launcher3/util/ResourceBasedOverride.java b/src/com/android/launcher3/util/ResourceBasedOverride.java
new file mode 100644
index 0000000..e2c4992
--- /dev/null
+++ b/src/com/android/launcher3/util/ResourceBasedOverride.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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.util;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An interface to indicate that a class is dynamically loaded using resource overlay, hence its
+ * class name and constructor should be preserved by proguard
+ */
+public interface ResourceBasedOverride {
+
+    class Overrides {
+
+        private static final String TAG = "Overrides";
+
+        public static <T extends ResourceBasedOverride> T getObject(
+                Class<T> clazz, Context context, int resId) {
+            String className = context.getString(resId);
+            if (!TextUtils.isEmpty(className)) {
+                try {
+                    Class<?> cls = Class.forName(className);
+                    return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
+                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+                        | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+                    Log.e(TAG, "Bad overriden class", e);
+                }
+            }
+
+            try {
+                return clazz.newInstance();
+            } catch (InstantiationException|IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/SQLiteCacheHelper.java b/src/com/android/launcher3/util/SQLiteCacheHelper.java
index 9084bfb..44c1762 100644
--- a/src/com/android/launcher3/util/SQLiteCacheHelper.java
+++ b/src/com/android/launcher3/util/SQLiteCacheHelper.java
@@ -92,10 +92,10 @@
     /**
      * A private inner class to prevent direct DB access.
      */
-    private class MySQLiteOpenHelper extends SQLiteOpenHelper {
+    private class MySQLiteOpenHelper extends NoLocaleSQLiteHelper {
 
         public MySQLiteOpenHelper(Context context, String name, int version) {
-            super(new NoLocaleSqliteContext(context), name, null, version);
+            super(context, name, version);
         }
 
         @Override
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
index edbf05a..86995b7 100644
--- a/src/com/android/launcher3/util/SystemUiController.java
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -16,11 +16,14 @@
 
 package com.android.launcher3.util;
 
+import android.text.TextUtils;
 import android.view.View;
 import android.view.Window;
 
 import com.android.launcher3.Utilities;
 
+import java.util.Arrays;
+
 /**
  * Utility class to manage various window flags to control system UI.
  */
@@ -31,6 +34,7 @@
     public static final int UI_STATE_ALL_APPS = 1;
     public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
     public static final int UI_STATE_ROOT_VIEW = 3;
+    public static final int UI_STATE_OVERVIEW = 4;
 
     public static final int FLAG_LIGHT_NAV = 1 << 0;
     public static final int FLAG_DARK_NAV = 1 << 1;
@@ -38,7 +42,7 @@
     public static final int FLAG_DARK_STATUS = 1 << 3;
 
     private final Window mWindow;
-    private final int[] mStates = new int[4];
+    private final int[] mStates = new int[5];
 
     public SystemUiController(Window window) {
         mWindow = window;
@@ -77,4 +81,9 @@
             mWindow.getDecorView().setSystemUiVisibility(newFlags);
         }
     }
+
+    @Override
+    public String toString() {
+        return "mStates=" + Arrays.toString(mStates);
+    }
 }
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 89597b9..5f965a3 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -52,6 +52,13 @@
         return value;
     }
 
+    public static int getAttrInteger(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+        int value = ta.getInteger(0, 0);
+        ta.recycle();
+        return value;
+    }
+
     /**
      * Returns the alpha corresponding to the theme attribute {@param attr}, in the range [0, 255].
      */
@@ -78,4 +85,23 @@
         target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
                 Color.blue(color) / 255f, Color.alpha(color) / 255f);
     }
+
+    /**
+     * Changes a color matrix such that, when applied to srcColor, it produces dstColor.
+     *
+     * Note that values on the last column of target ColorMatrix can be negative, and may result in
+     * negative values when applied on a color. Such negative values will be automatically shifted
+     * up to 0 by the framework.
+     *
+     * @param srcColor The color to start from
+     * @param dstColor The color to create by applying target on srcColor
+     * @param target The ColorMatrix to transform the color
+     */
+    public static void setColorChangeOnMatrix(int srcColor, int dstColor, ColorMatrix target) {
+        target.reset();
+        target.getArray()[4] = Color.red(dstColor) - Color.red(srcColor);
+        target.getArray()[9] = Color.green(dstColor) - Color.green(srcColor);
+        target.getArray()[14] = Color.blue(dstColor) - Color.blue(srcColor);
+        target.getArray()[19] = Color.alpha(dstColor) - Color.alpha(srcColor);
+    }
 }
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index bde9c0a..4aa2f37 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -15,6 +15,9 @@
  */
 package com.android.launcher3.util;
 
+import static android.util.Log.VERBOSE;
+import static android.util.Log.isLoggable;
+
 import android.os.SystemClock;
 import android.os.Trace;
 import android.util.ArrayMap;
@@ -40,7 +43,7 @@
         if (ENABLED) {
             MutableLong time = sUpTimes.get(sectionName);
             if (time == null) {
-                time = new MutableLong(Log.isLoggable(sectionName, Log.VERBOSE) ? 0 : -1);
+                time = new MutableLong(isLoggable(sectionName, VERBOSE) ? 0 : -1);
                 sUpTimes.put(sectionName, time);
             }
             if (time.value >= 0) {
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
deleted file mode 100644
index a647378..0000000
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.support.animation.SpringAnimation;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.touch.SwipeDetector.Direction;
-
-import java.util.ArrayList;
-
-/**
- * Handles vertical touch gesture on the DragLayer allowing transitioning from
- * {@link #mBaseState} to {@link LauncherState#ALL_APPS} and vice-versa.
- */
-public abstract class VerticalSwipeController extends AnimatorListenerAdapter
-        implements TouchController, SwipeDetector.Listener {
-
-    private static final String TAG = "VerticalSwipeController";
-
-    private static final float RECATCH_REJECTION_FRACTION = .0875f;
-    private static final int SINGLE_FRAME_MS = 16;
-
-    // Progress after which the transition is assumed to be a success in case user does not fling
-    private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
-    protected final Launcher mLauncher;
-    protected final SwipeDetector mDetector;
-    private final LauncherState mBaseState;
-    private final LauncherState mTargetState;
-
-    private boolean mNoIntercept;
-
-    private AnimatorPlaybackController mCurrentAnimation;
-    protected LauncherState mToState;
-
-    private float mStartProgress;
-    // Ratio of transition process [0, 1] to drag displacement (px)
-    private float mProgressMultiplier;
-
-    protected SpringAnimationHandler[] mSpringHandlers;
-
-    public VerticalSwipeController(Launcher l, LauncherState baseState) {
-        this(l, baseState, ALL_APPS, SwipeDetector.VERTICAL);
-    }
-
-    public VerticalSwipeController(
-            Launcher l, LauncherState baseState, LauncherState targetState, Direction dir) {
-        mLauncher = l;
-        mDetector = new SwipeDetector(l, this, dir);
-        mBaseState = baseState;
-        mTargetState = targetState;
-    }
-
-    private boolean canInterceptTouch(MotionEvent ev) {
-        if (mCurrentAnimation != null) {
-            // If we are already animating from a previous state, we can intercept.
-            return true;
-        }
-        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
-            return false;
-        }
-        return shouldInterceptTouch(ev);
-    }
-
-    protected abstract boolean shouldInterceptTouch(MotionEvent ev);
-
-    @Override
-    public void onAnimationCancel(Animator animation) {
-        if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
-            Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
-            mDetector.finishedScrolling();
-            mCurrentAnimation = null;
-        }
-    }
-
-    protected void initSprings() {
-        AllAppsContainerView appsView = mLauncher.getAppsView();
-
-        SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
-        if (handler == null) {
-            mSpringHandlers = new SpringAnimationHandler[0];
-            return;
-        }
-
-        ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
-        handlers.add(handler);
-
-        SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
-        if (searchSpring != null) {
-            SpringAnimationHandler searchHandler =
-                    new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
-            searchHandler.add(searchSpring, true /* setDefaultValues */);
-            handlers.add(searchHandler);
-        }
-
-        mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
-    }
-
-    @Override
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            mNoIntercept = !canInterceptTouch(ev);
-            if (mNoIntercept) {
-                return false;
-            }
-
-            // Now figure out which direction scroll events the controller will start
-            // calling the callbacks.
-            final int directionsToDetectScroll;
-            boolean ignoreSlopWhenSettling = false;
-
-            if (mCurrentAnimation != null) {
-                if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
-                } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
-                } else {
-                    directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
-                    ignoreSlopWhenSettling = true;
-                }
-            } else {
-                directionsToDetectScroll = getSwipeDirection(ev);
-            }
-
-            mDetector.setDetectableScrollConditions(
-                    directionsToDetectScroll, ignoreSlopWhenSettling);
-
-            if (mSpringHandlers == null) {
-                initSprings();
-            }
-        }
-
-        if (mNoIntercept) {
-            return false;
-        }
-
-        onControllerTouchEvent(ev);
-        return mDetector.isDraggingOrSettling();
-    }
-
-    protected abstract int getSwipeDirection(MotionEvent ev);
-
-    @Override
-    public boolean onControllerTouchEvent(MotionEvent ev) {
-        for (SpringAnimationHandler h : mSpringHandlers) {
-            h.addMovement(ev);
-        }
-        return mDetector.onTouchEvent(ev);
-    }
-
-    @Override
-    public void onDragStart(boolean start) {
-        if (mCurrentAnimation == null) {
-            float range = getShiftRange();
-            long maxAccuracy = (long) (2 * range);
-
-            // Build current animation
-            mToState = mLauncher.isInState(mTargetState) ? mBaseState : mTargetState;
-            mCurrentAnimation = mLauncher.getStateManager()
-                    .createAnimationToNewWorkspace(mToState, maxAccuracy);
-            mCurrentAnimation.getTarget().addListener(this);
-            mStartProgress = 0;
-            mProgressMultiplier =
-                    (mLauncher.isInState(mTargetState) ^ isTransitionFlipped() ? 1 : -1) / range;
-            mCurrentAnimation.dispatchOnStart();
-        } else {
-            mCurrentAnimation.pause();
-            mStartProgress = mCurrentAnimation.getProgressFraction();
-        }
-
-        for (SpringAnimationHandler h : mSpringHandlers) {
-            h.skipToEnd();
-        }
-    }
-
-    protected boolean isTransitionFlipped() {
-        return false;
-    }
-
-    protected float getShiftRange() {
-        return mLauncher.getAllAppsController().getShiftRange();
-    }
-
-    @Override
-    public boolean onDrag(float displacement, float velocity) {
-        float deltaProgress = mProgressMultiplier * displacement;
-        mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
-        return true;
-    }
-
-    @Override
-    public void onDragEnd(float velocity, boolean fling) {
-        final long animationDuration;
-        final LauncherState targetState;
-        final float progress = mCurrentAnimation.getProgressFraction();
-
-        if (fling) {
-            if (velocity < 0 ^ isTransitionFlipped()) {
-                targetState = mTargetState;
-            } else {
-                targetState = mBaseState;
-            }
-            animationDuration = SwipeDetector.calculateDuration(velocity,
-                    mToState == targetState ? (1 - progress) : progress);
-            // snap to top or bottom using the release velocity
-        } else {
-            if (progress > SUCCESS_TRANSITION_PROGRESS) {
-                targetState = mToState;
-                animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
-            } else {
-                targetState = mToState == mTargetState ? mBaseState : mTargetState;
-                animationDuration = SwipeDetector.calculateDuration(velocity, progress);
-            }
-        }
-
-        if (fling && targetState == mTargetState) {
-            for (SpringAnimationHandler h : mSpringHandlers) {
-                // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
-                h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
-            }
-        }
-
-        mCurrentAnimation.setEndAction(() -> {
-            mLauncher.getStateManager().goToState(targetState, false);
-            onTransitionComplete(fling, targetState == mToState);
-            mDetector.finishedScrolling();
-            mCurrentAnimation = null;
-        });
-
-        float nextFrameProgress = Utilities.boundToRange(
-                progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
-
-        ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
-        anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
-        anim.setDuration(animationDuration);
-        anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
-        anim.start();
-    }
-
-    protected abstract void onTransitionComplete(boolean wasFling, boolean stateChanged);
-}
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index e5c1dd1..acce308 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -34,24 +34,25 @@
         OnAttachStateChangeListener {
 
     private final ArrayList<Runnable> mTasks = new ArrayList<>();
-    private final Executor mExecutor;
 
     private Launcher mLauncher;
     private View mAttachedView;
     private boolean mCompleted;
-    private boolean mIsExecuting;
 
     private boolean mLoadAnimationCompleted;
     private boolean mFirstDrawCompleted;
 
-    public ViewOnDrawExecutor(Executor executor) {
-        mExecutor = executor;
+    public void attachTo(Launcher launcher) {
+        attachTo(launcher, launcher.getWorkspace(), true /* waitForLoadAnimation */);
     }
 
-    public void attachTo(Launcher launcher) {
+    public void attachTo(Launcher launcher, View attachedView, boolean waitForLoadAnimation) {
         mLauncher = launcher;
-        mAttachedView = launcher.getWorkspace();
+        mAttachedView = attachedView;
         mAttachedView.addOnAttachStateChangeListener(this);
+        if (!waitForLoadAnimation) {
+            mLoadAnimationCompleted = true;
+        }
 
         attachObserver();
     }
@@ -74,7 +75,7 @@
     }
 
     @Override
-    public void onViewDetachedFromWindow(View v) { }
+    public void onViewDetachedFromWindow(View v) {}
 
     @Override
     public void onDraw() {
@@ -82,13 +83,6 @@
         mAttachedView.post(this);
     }
 
-    /**
-     * Returns whether the executor is still queuing tasks and hasn't yet executed them.
-     */
-    public boolean canQueue() {
-        return !mIsExecuting && !mCompleted;
-    }
-
     public void onLoadAnimationCompleted() {
         mLoadAnimationCompleted = true;
         if (mAttachedView != null) {
@@ -100,18 +94,13 @@
     public void run() {
         // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
         if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
-            mIsExecuting = true;
-            for (final Runnable r : mTasks) {
-                mExecutor.execute(r);
-            }
-            markCompleted();
+            runAllTasks();
         }
     }
 
     public void markCompleted() {
         mTasks.clear();
         mCompleted = true;
-        mIsExecuting = false;
         if (mAttachedView != null) {
             mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
             mAttachedView.removeOnAttachStateChangeListener(this);
@@ -121,4 +110,15 @@
         }
         LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_DEFAULT);
     }
+
+    protected boolean isCompleted() {
+        return mCompleted;
+    }
+
+    protected void runAllTasks() {
+        for (final Runnable r : mTasks) {
+            r.run();
+        }
+        markCompleted();
+    }
 }
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 7c4529d..c8d1457 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -81,6 +81,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mSwipeDetector.finishedScrolling();
+                announceAccessibilityChanges();
             }
         });
     }
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
new file mode 100644
index 0000000..04100af
--- /dev/null
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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 android.content.Context;
+import android.content.ContextWrapper;
+import android.view.ContextThemeWrapper;
+
+/**
+ * An interface to be used along with a context. This allows a generic class to depend on Context
+ * subclass instead of an Activity.
+ */
+public interface ActivityContext {
+
+    default boolean finishAutoCancelActionMode() {
+        return false;
+    }
+
+    BaseDragLayer getDragLayer();
+
+    static ActivityContext lookupContext(Context context) {
+        if (context instanceof ActivityContext) {
+            return (ActivityContext) context;
+        } else if (context instanceof ContextThemeWrapper) {
+            return lookupContext(((ContextWrapper) context).getBaseContext());
+        } else {
+            throw new IllegalArgumentException("Cannot find ActivityContext in parent tree");
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java
deleted file mode 100644
index 0ef9c8f..0000000
--- a/src/com/android/launcher3/views/AllAppsScrim.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.views;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
-import android.util.Property;
-import android.view.View;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.dynamicui.WallpaperColorInfo.OnChangeListener;
-import com.android.launcher3.graphics.NinePatchDrawHelper;
-import com.android.launcher3.graphics.ShadowGenerator;
-import com.android.launcher3.util.Themes;
-
-import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX;
-
-public class AllAppsScrim extends View implements OnChangeListener, Insettable {
-
-    private static final int MAX_ALPHA = 235;
-    private static final int MIN_ALPHA_PORTRAIT = 100;
-    private static final int MIN_ALPHA_LANDSCAPE = MAX_ALPHA;
-
-    protected final WallpaperColorInfo mWallpaperColorInfo;
-    private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-    private final Rect mDrawRect = new Rect();
-    private final Rect mPadding = new Rect();
-    private final Rect mInsets = new Rect();
-
-    private final float mRadius;
-    private final int mScrimColor;
-
-    private int mMinAlpha;
-    private int mAlphaRange;
-
-    private final float mShadowBlur;
-    private final Bitmap mShadowBitmap;
-
-    private final NinePatchDrawHelper mShadowHelper = new NinePatchDrawHelper();
-
-    private int mFillAlpha;
-
-    private float mDrawHeight;
-    private float mDrawOffsetY;
-
-    public AllAppsScrim(Context context) {
-        this(context, null);
-    }
-
-    public AllAppsScrim(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public AllAppsScrim(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mWallpaperColorInfo = WallpaperColorInfo.getInstance(context);
-        mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        mRadius = getResources().getDimension(R.dimen.all_apps_scrim_radius);
-        mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur);
-
-        initDefaults();
-        mFillAlpha = mMinAlpha;
-        mShadowBitmap = generateShadowBitmap();
-
-        updateColors(mWallpaperColorInfo);
-    }
-
-    private DeviceProfile initDefaults() {
-        DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
-        mMinAlpha = grid.isVerticalBarLayout()
-                ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT;
-        mAlphaRange = MAX_ALPHA - mMinAlpha;
-        return grid;
-    }
-
-    private Bitmap generateShadowBitmap() {
-        float curveBot = mRadius + mShadowBlur;
-
-        ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT);
-        builder.radius = mRadius;
-        builder.shadowBlur = mShadowBlur;
-
-        // Create the bitmap such that only the top half is drawn in the bitmap.
-        int bitmapWidth = 2 * Math.round(curveBot) + EXTENSION_PX;
-        int bitmapHeight = bitmapWidth / 2;
-        Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
-
-        float fullSize = 2 * curveBot + EXTENSION_PX - mShadowBlur;
-        builder.bounds.set(mShadowBlur, mShadowBlur, fullSize, fullSize);
-        builder.drawShadow(new Canvas(result));
-        return result;
-    }
-
-    public Bitmap getShadowBitmap() {
-        return mShadowBitmap;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperColorInfo.addOnChangeListener(this);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mWallpaperColorInfo.removeOnChangeListener(this);
-    }
-
-    @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo info) {
-        updateColors(info);
-        invalidate();
-    }
-
-    private void updateColors(WallpaperColorInfo info) {
-        mFillPaint.setColor(ColorUtils.compositeColors(mScrimColor,
-                ColorUtils.compositeColors(mScrimColor, info.getMainColor())));
-        mFillPaint.setAlpha(mFillAlpha);
-        invalidate();
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        float edgeTop = getHeight() + mDrawOffsetY - mDrawHeight + mPadding.top;
-        float edgeRight = getWidth() - mPadding.right;
-
-        if (mPadding.left > 0 || mPadding.right > 0) {
-            mShadowHelper.drawVerticallyStretched(mShadowBitmap, canvas,
-                    mPadding.left - mShadowBlur,
-                    edgeTop - mShadowBlur,
-                    edgeRight + mShadowBlur,
-                    getHeight());
-        } else {
-            mShadowHelper.draw(mShadowBitmap, canvas, mPadding.left - mShadowBlur,
-                    edgeTop - mShadowBlur, edgeRight + mShadowBlur);
-        }
-        canvas.drawRoundRect(mPadding.left, edgeTop, edgeRight,
-                getHeight() + mRadius, mRadius, mRadius, mFillPaint);
-    }
-
-    public void setProgress(float translateY, float alpha) {
-        int newAlpha = Math.round(alpha * mAlphaRange + mMinAlpha);
-        // Negative translation means the scrim is moving up. For negative translation, we change
-        // draw offset as it requires redraw (since more area of the scrim needs to be shown). For
-        // position translation, we simply translate the scrim down as it avoids invalidate and
-        // hence could be optimized by the platform.
-        float drawOffsetY = Math.min(translateY, 0);
-
-        if (newAlpha != mFillAlpha || drawOffsetY != mDrawOffsetY) {
-            invalidateDrawRect();
-
-            mFillAlpha = newAlpha;
-            mFillPaint.setAlpha(mFillAlpha);
-            mDrawOffsetY = drawOffsetY;
-            invalidateDrawRect();
-        }
-
-        setTranslationY(Math.max(translateY, 0));
-    }
-
-    private void invalidateDrawRect() {
-        mDrawRect.top = (int) (getHeight()
-                + mDrawOffsetY - mDrawHeight + mPadding.top - mShadowBlur - 0.5f);
-        invalidate(mDrawRect);
-    }
-
-    public void setDrawRegion(float height) {
-        mDrawHeight = height;
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        DeviceProfile grid = initDefaults();
-        if (grid.isVerticalBarLayout()) {
-            mPadding.set(grid.workspacePadding);
-            mPadding.bottom = 0;
-            mPadding.left += mInsets.left;
-            mPadding.top = mInsets.top;
-            mPadding.right += mInsets.right;
-            setDrawRegion(0);
-        } else {
-            mPadding.setEmpty();
-            float scrimMargin = getResources().getDimension(R.dimen.all_apps_scrim_margin);
-            setDrawRegion(grid.hotseatBarSizePx + insets.bottom + scrimMargin);
-        }
-        updateDrawRect(grid);
-        invalidate();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        updateDrawRect(Launcher.getLauncher(getContext()).getDeviceProfile());
-    }
-
-    private void updateDrawRect(DeviceProfile grid) {
-        mDrawRect.bottom = getHeight();
-        if (grid.isVerticalBarLayout()) {
-            mDrawRect.left = (int) (mPadding.left - mShadowBlur - 0.5f);
-            mDrawRect.right = (int) (getWidth() - mPadding.right + 0.5f);
-        } else {
-            mDrawRect.left = 0;
-            mDrawRect.right = getWidth();
-        }
-    }
-}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
new file mode 100644
index 0000000..e8a879f
--- /dev/null
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2018 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.Utilities.SINGLE_FRAME_MS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.launcher3.util.TouchController;
+
+import java.util.ArrayList;
+
+/**
+ * A viewgroup with utility methods for drag-n-drop and touch interception
+ */
+public abstract class BaseDragLayer<T extends Context & ActivityContext>
+        extends InsettableFrameLayout {
+
+    protected final int[] mTmpXY = new int[2];
+    protected final Rect mHitRect = new Rect();
+
+    protected final T mActivity;
+    private final MultiValueAlpha mMultiValueAlpha;
+
+    protected TouchController[] mControllers;
+    protected TouchController mActiveController;
+    private TouchCompleteListener mTouchCompleteListener;
+
+    public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
+        super(context, attrs);
+        mActivity = (T) ActivityContext.lookupContext(context);
+        mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
+    }
+
+    public boolean isEventOverView(View view, MotionEvent ev) {
+        getDescendantRectRelativeToSelf(view, mHitRect);
+        return mHitRect.contains((int) ev.getX(), (int) ev.getY());
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        int action = ev.getAction();
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            if (mTouchCompleteListener != null) {
+                mTouchCompleteListener.onTouchComplete();
+            }
+            mTouchCompleteListener = null;
+        } else if (action == MotionEvent.ACTION_DOWN) {
+            mActivity.finishAutoCancelActionMode();
+        }
+        return findActiveController(ev);
+    }
+
+    protected boolean findActiveController(MotionEvent ev) {
+        mActiveController = null;
+
+        AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+        if (topView != null && topView.onControllerInterceptTouchEvent(ev)) {
+            mActiveController = topView;
+            return true;
+        }
+
+        for (TouchController controller : mControllers) {
+            if (controller.onControllerInterceptTouchEvent(ev)) {
+                mActiveController = controller;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        // Shortcuts can appear above folder
+        View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+                AbstractFloatingView.TYPE_ACCESSIBLE);
+        if (topView != null) {
+            if (child == topView) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
+            // Skip propagating onRequestSendAccessibilityEvent for all other children
+            // which are not topView
+            return false;
+        }
+        return super.onRequestSendAccessibilityEvent(child, event);
+    }
+
+    @Override
+    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
+        View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+                AbstractFloatingView.TYPE_ACCESSIBLE);
+        if (topView != null) {
+            // Only add the top view as a child for accessibility when it is open
+            addAccessibleChildToList(topView, childrenForAccessibility);
+        } else {
+            super.addChildrenForAccessibility(childrenForAccessibility);
+        }
+    }
+
+    protected void addAccessibleChildToList(View child, ArrayList<View> outList) {
+        if (child.isImportantForAccessibility()) {
+            outList.add(child);
+        } else {
+            child.addChildrenForAccessibility(outList);
+        }
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+        if (child instanceof AbstractFloatingView) {
+            // Handles the case where the view is removed without being properly closed.
+            // This can happen if something goes wrong during a state change/transition.
+            postDelayed(() -> {
+                AbstractFloatingView floatingView = (AbstractFloatingView) child;
+                if (floatingView.isOpen()) {
+                    floatingView.close(false);
+                }
+            }, SINGLE_FRAME_MS);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        int action = ev.getAction();
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            if (mTouchCompleteListener != null) {
+                mTouchCompleteListener.onTouchComplete();
+            }
+            mTouchCompleteListener = null;
+        }
+
+        if (mActiveController != null) {
+            return mActiveController.onControllerTouchEvent(ev);
+        } else {
+            // In case no child view handled the touch event, we may not get onIntercept anymore
+            return findActiveController(ev);
+        }
+    }
+
+    /**
+     * Determine the rect of the descendant in this DragLayer's coordinates
+     *
+     * @param descendant The descendant whose coordinates we want to find.
+     * @param r The rect into which to place the results.
+     * @return The factor by which this descendant is scaled relative to this DragLayer.
+     */
+    public float getDescendantRectRelativeToSelf(View descendant, Rect r) {
+        mTmpXY[0] = 0;
+        mTmpXY[1] = 0;
+        float scale = getDescendantCoordRelativeToSelf(descendant, mTmpXY);
+
+        r.set(mTmpXY[0], mTmpXY[1],
+                (int) (mTmpXY[0] + scale * descendant.getMeasuredWidth()),
+                (int) (mTmpXY[1] + scale * descendant.getMeasuredHeight()));
+        return scale;
+    }
+
+    public float getLocationInDragLayer(View child, int[] loc) {
+        loc[0] = 0;
+        loc[1] = 0;
+        return getDescendantCoordRelativeToSelf(child, loc);
+    }
+
+    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord) {
+        return getDescendantCoordRelativeToSelf(descendant, coord, false);
+    }
+
+    /**
+     * Given a coordinate relative to the descendant, find the coordinate in this DragLayer's
+     * coordinates.
+     *
+     * @param descendant The descendant to which the passed coordinate is relative.
+     * @param coord The coordinate that we want mapped.
+     * @param includeRootScroll Whether or not to account for the scroll of the root descendant:
+     *          sometimes this is relevant as in a child's coordinates within the root descendant.
+     * @return The factor by which this descendant is scaled relative to this DragLayer. Caution
+     *         this scale factor is assumed to be equal in X and Y, and so if at any point this
+     *         assumption fails, we will need to return a pair of scale factors.
+     */
+    public float getDescendantCoordRelativeToSelf(View descendant, int[] coord,
+            boolean includeRootScroll) {
+        return Utilities.getDescendantCoordRelativeToAncestor(descendant, this,
+                coord, includeRootScroll);
+    }
+
+    /**
+     * Inverse of {@link #getDescendantCoordRelativeToSelf(View, int[])}.
+     */
+    public void mapCoordInSelfToDescendant(View descendant, int[] coord) {
+        Utilities.mapCoordInSelfToDescendant(descendant, this, coord);
+    }
+
+    public void getViewRectRelativeToSelf(View v, Rect r) {
+        int[] loc = new int[2];
+        getLocationInWindow(loc);
+        int x = loc[0];
+        int y = loc[1];
+
+        v.getLocationInWindow(loc);
+        int vX = loc[0];
+        int vY = loc[1];
+
+        int left = vX - x;
+        int top = vY - y;
+        r.set(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
+    }
+
+    @Override
+    public boolean dispatchUnhandledMove(View focused, int direction) {
+        // Consume the unhandled move if a container is open, to avoid switching pages underneath.
+        return AbstractFloatingView.getTopOpenView(mActivity) != null;
+    }
+
+    @Override
+    protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+        View topView = AbstractFloatingView.getTopOpenView(mActivity);
+        if (topView != null) {
+            return topView.requestFocus(direction, previouslyFocusedRect);
+        } else {
+            return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
+        }
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        View topView = AbstractFloatingView.getTopOpenView(mActivity);
+        if (topView != null) {
+            topView.addFocusables(views, direction);
+        } else {
+            super.addFocusables(views, direction, focusableMode);
+        }
+    }
+
+    public void setTouchCompleteListener(TouchCompleteListener listener) {
+        mTouchCompleteListener = listener;
+    }
+
+    public interface TouchCompleteListener {
+        void onTouchComplete();
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    // Override to allow type-checking of LayoutParams.
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new LayoutParams(p);
+    }
+
+    public AlphaProperty getAlphaProperty(int index) {
+        return mMultiValueAlpha.getProperty(index);
+    }
+
+    public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
+        public int x, y;
+        public boolean customPosition = false;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams lp) {
+            super(lp);
+        }
+
+        public void setWidth(int width) {
+            this.width = width;
+        }
+
+        public int getWidth() {
+            return width;
+        }
+
+        public void setHeight(int height) {
+            this.height = height;
+        }
+
+        public int getHeight() {
+            return height;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setY(int y) {
+            this.y = y;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = getChildAt(i);
+            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
+            if (flp instanceof LayoutParams) {
+                final LayoutParams lp = (LayoutParams) flp;
+                if (lp.customPosition) {
+                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+                }
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/BottomUserEducationView.java b/src/com/android/launcher3/views/BottomUserEducationView.java
index ba78cf6..a291fc6 100644
--- a/src/com/android/launcher3/views/BottomUserEducationView.java
+++ b/src/com/android/launcher3/views/BottomUserEducationView.java
@@ -22,11 +22,15 @@
 import android.view.LayoutInflater;
 import android.view.TouchDelegate;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.Interpolators;
 
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
 public class BottomUserEducationView extends AbstractSlideInView implements Insettable {
 
     private static final String KEY_SHOWED_BOTTOM_USER_EDUCATION = "showed_bottom_user_education";
@@ -90,6 +94,10 @@
             // close action.
             mLauncher.getSharedPrefs().edit()
                     .putBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, true).apply();
+            sendCustomAccessibilityEvent(
+                    BottomUserEducationView.this,
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                    getContext().getString(R.string.bottom_work_tab_user_education_closed));
         }
     }
 
diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
index c8203f7..a11a8c5 100644
--- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
+++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java
@@ -20,7 +20,6 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.Region;
 import android.support.v4.graphics.ColorUtils;
 import android.util.AttributeSet;
 import android.widget.TextView;
@@ -63,10 +62,10 @@
                 ColorUtils.setAlphaComponent(mShadowInfo.ambientShadowColor, alpha));
 
         drawWithoutBadge(canvas);
-        canvas.save(Canvas.CLIP_SAVE_FLAG);
+        canvas.save();
         canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(),
                 getScrollX() + getWidth(),
-                getScrollY() + getHeight(), Region.Op.INTERSECT);
+                getScrollY() + getHeight());
 
         getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f, mShadowInfo.keyShadowOffset,
                 ColorUtils.setAlphaComponent(mShadowInfo.keyShadowColor, alpha));
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
new file mode 100644
index 0000000..dc6d2ff
--- /dev/null
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2018 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.BaseDraggingActivity.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION;
+import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.widget.Toast;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.popup.ArrowPopup;
+import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.widget.WidgetsFullSheet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Popup shown on long pressing an empty space in launcher
+ */
+public class OptionsPopupView extends ArrowPopup
+        implements OnClickListener, OnLongClickListener {
+
+    private final ArrayMap<View, OptionItem> mItemMap = new ArrayMap<>();
+    private RectF mTargetRect;
+
+    public OptionsPopupView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public void onClick(View view) {
+        handleViewClick(view, Action.Touch.TAP);
+    }
+
+    @Override
+    public boolean onLongClick(View view) {
+        return handleViewClick(view, Action.Touch.LONGPRESS);
+    }
+
+    private boolean handleViewClick(View view, int action) {
+        OptionItem item = mItemMap.get(view);
+        if (item == null) {
+            return false;
+        }
+        if (item.mControlTypeForLog > 0) {
+            logTap(action, item.mControlTypeForLog);
+        }
+        if (item.mClickListener.onLongClick(view)) {
+            close(true);
+            return true;
+        }
+        return false;
+    }
+
+    private void logTap(int action, int controlType) {
+        mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
+    }
+
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() != MotionEvent.ACTION_DOWN) {
+            return false;
+        }
+        if (getPopupContainer().isEventOverView(this, ev)) {
+            return false;
+        }
+        close(true);
+        return true;
+    }
+
+    @Override
+    public void logActionCommand(int command) {
+        // TODO:
+    }
+
+    @Override
+    protected boolean isOfType(int type) {
+        return (type & TYPE_OPTIONS_POPUP) != 0;
+    }
+
+    @Override
+    protected void getTargetObjectLocation(Rect outPos) {
+        mTargetRect.roundOut(outPos);
+    }
+
+    public static void show(Launcher launcher, RectF targetRect, List<OptionItem> items) {
+        OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
+                .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
+        popup.mTargetRect = targetRect;
+
+        for (OptionItem item : items) {
+            DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup);
+            view.getIconView().setBackgroundResource(item.mIconRes);
+            view.getBubbleText().setText(item.mLabelRes);
+            view.setDividerVisibility(View.INVISIBLE);
+            view.setOnClickListener(popup);
+            view.setOnLongClickListener(popup);
+            popup.mItemMap.put(view, item);
+        }
+        popup.reorderAndShow(popup.getChildCount());
+    }
+
+    @VisibleForTesting
+    public static OptionsPopupView getOptionsPopup(Launcher launcher) {
+        return launcher.findViewById(R.id.deep_shortcuts_container);
+    }
+
+    public static void showDefaultOptions(Launcher launcher, float x, float y) {
+        float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
+        if (x < 0 || y < 0) {
+            x = launcher.getDragLayer().getWidth() / 2;
+            y = launcher.getDragLayer().getHeight() / 2;
+        }
+        RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
+
+        ArrayList<OptionItem> options = new ArrayList<>();
+        options.add(new OptionItem(R.string.wallpaper_button_text, R.drawable.ic_wallpaper,
+                ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
+        options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+                ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
+        options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
+                ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings));
+
+        show(launcher, target, options);
+    }
+
+    public static boolean onWidgetsClicked(View view) {
+        return openWidgets(Launcher.getLauncher(view.getContext()));
+    }
+
+    public static boolean openWidgets(Launcher launcher) {
+        if (launcher.getPackageManager().isSafeMode()) {
+            Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+            return false;
+        } else {
+            WidgetsFullSheet.show(launcher, true /* animated */);
+            return true;
+        }
+    }
+
+    public static boolean startSettings(View view) {
+        Launcher launcher = Launcher.getLauncher(view.getContext());
+        launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
+                .setPackage(launcher.getPackageName())
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        return true;
+    }
+
+    /**
+     * Event handler for the wallpaper picker button that appears after a long press
+     * on the home screen.
+     */
+    public static boolean startWallpaperPicker(View v) {
+        Launcher launcher = Launcher.getLauncher(v.getContext());
+        if (!Utilities.isWallpaperAllowed(launcher)) {
+            Toast.makeText(launcher, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
+            return false;
+        }
+        Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
+                .putExtra(EXTRA_WALLPAPER_OFFSET,
+                        launcher.getWorkspace().getWallpaperOffsetForCenterPage());
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+        String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
+        if (!TextUtils.isEmpty(pickerPackage)) {
+            intent.setPackage(pickerPackage);
+        } else {
+            // If there is no target package, use the default intent chooser animation
+            intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
+        }
+        return launcher.startActivitySafely(v, intent, null);
+    }
+
+    public static class OptionItem {
+
+        private final int mLabelRes;
+        private final int mIconRes;
+        private final int mControlTypeForLog;
+        private final OnLongClickListener mClickListener;
+
+        public OptionItem(int labelRes, int iconRes, int controlTypeForLog,
+                OnLongClickListener clickListener) {
+            mLabelRes = labelRes;
+            mIconRes = iconRes;
+            mControlTypeForLog = controlTypeForLog;
+            mClickListener = clickListener;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index fc121d3..05bab8b 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -22,6 +22,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.util.Property;
@@ -43,6 +45,7 @@
 public class RecyclerViewFastScroller extends View {
 
     private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
+    private static final Rect sTempRect = new Rect();
 
     private static final Property<RecyclerViewFastScroller, Integer> TRACK_WIDTH =
             new Property<RecyclerViewFastScroller, Integer>(Integer.class, "width") {
@@ -204,9 +207,9 @@
      * Handles the touch event and determines whether to show the fast scroller (or updates it if
      * it is already showing).
      */
-    public boolean handleTouchEvent(MotionEvent ev) {
-        int x = (int) ev.getX();
-        int y = (int) ev.getY();
+    public boolean handleTouchEvent(MotionEvent ev, Point offset) {
+        int x = (int) ev.getX() - offset.x;
+        int y = (int) ev.getY() - offset.y;
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // Keep track of the down positions
@@ -260,7 +263,6 @@
     }
 
     private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
-        mRv.getParent().requestDisallowInterceptTouchEvent(true);
         mIsDragging = true;
         if (mCanThumbDetach) {
             mIsThumbDetached = true;
@@ -289,7 +291,7 @@
         if (mThumbOffsetY < 0) {
             return;
         }
-        int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+        int saveCount = canvas.save();
         canvas.translate(getWidth() / 2, mRv.getScrollBarTop());
         // Draw the track
         float halfW = mWidth / 2;
@@ -358,4 +360,23 @@
                 mMaxWidth, mRv.getScrollbarTrackHeight() - mMaxWidth - height);
         mPopupView.setTranslationY(top);
     }
+
+    public boolean isHitInParent(float x, float y, Point outOffset) {
+        if (mThumbOffsetY < 0) {
+            return false;
+        }
+        getHitRect(sTempRect);
+        sTempRect.top += mRv.getScrollBarTop();
+        if (outOffset != null) {
+            outOffset.set(sTempRect.left, sTempRect.top);
+        }
+        return sTempRect.contains((int) x, (int) y);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        // There is actually some overlap between the track and the thumb. But since the track
+        // alpha is so low, it does not matter.
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
new file mode 100644
index 0000000..7066980
--- /dev/null
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2018 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 android.content.Context.ACCESSIBILITY_SERVICE;
+import static android.support.v4.graphics.ColorUtils.compositeColors;
+import static android.support.v4.graphics.ColorUtils.setAlphaComponent;
+import static android.view.MotionEvent.ACTION_DOWN;
+
+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.DEACCEL;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager;
+import com.android.launcher3.LauncherStateManager.StateListener;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.uioverrides.WallpaperColorInfo;
+import com.android.launcher3.uioverrides.WallpaperColorInfo.OnChangeListener;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.util.Themes;
+
+import java.util.List;
+
+/**
+ * Simple scrim which draws a flat color
+ */
+public class ScrimView extends View implements Insettable, OnChangeListener,
+        AccessibilityStateChangeListener, StateListener {
+
+    public static final Property<ScrimView, Integer> DRAG_HANDLE_ALPHA =
+            new Property<ScrimView, Integer>(Integer.TYPE, "dragHandleAlpha") {
+
+                @Override
+                public Integer get(ScrimView scrimView) {
+                    return scrimView.mDragHandleAlpha;
+                }
+
+                @Override
+                public void set(ScrimView scrimView, Integer value) {
+                    scrimView.setDragHandleAlpha(value);
+                }
+            };
+    private static final int WALLPAPERS = R.string.wallpaper_button_text;
+    private static final int WIDGETS = R.string.widget_button_text;
+    private static final int SETTINGS = R.string.settings_button_text;
+
+    private final Rect mTempRect = new Rect();
+    private final int[] mTempPos = new int[2];
+
+    protected final Launcher mLauncher;
+    private final WallpaperColorInfo mWallpaperColorInfo;
+    private final AccessibilityManager mAM;
+    protected final int mEndScrim;
+
+    protected float mMaxScrimAlpha;
+
+    protected float mProgress = 1;
+    protected int mScrimColor;
+
+    protected int mCurrentFlatColor;
+    protected int mEndFlatColor;
+    protected int mEndFlatColorAlpha;
+
+    protected final int mDragHandleSize;
+    protected float mDragHandleOffset;
+    private final Rect mDragHandleBounds;
+    private final RectF mHitRect = new RectF();
+
+    private final AccessibilityHelper mAccessibilityHelper;
+    @Nullable
+    protected Drawable mDragHandle;
+
+    private int mDragHandleAlpha = 255;
+
+    public ScrimView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLauncher = Launcher.getLauncher(context);
+        mWallpaperColorInfo = WallpaperColorInfo.getInstance(context);
+        mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
+
+        mMaxScrimAlpha = 0.7f;
+
+        mDragHandleSize = context.getResources()
+                .getDimensionPixelSize(R.dimen.vertical_drag_handle_size);
+        mDragHandleBounds = new Rect(0, 0, mDragHandleSize, mDragHandleSize);
+
+        mAccessibilityHelper = createAccessibilityHelper();
+        ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
+
+        mAM = (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE);
+        setFocusable(false);
+    }
+
+    @NonNull
+    protected AccessibilityHelper createAccessibilityHelper() {
+        return new AccessibilityHelper();
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        updateDragHandleBounds();
+        updateDragHandleVisibility(null);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        updateDragHandleBounds();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mWallpaperColorInfo.addOnChangeListener(this);
+        onExtractedColorsChanged(mWallpaperColorInfo);
+
+        mAM.addAccessibilityStateChangeListener(this);
+        onAccessibilityStateChanged(mAM.isEnabled());
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mWallpaperColorInfo.removeOnChangeListener(this);
+        mAM.removeAccessibilityStateChangeListener(this);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+        mScrimColor = wallpaperColorInfo.getMainColor();
+        mEndFlatColor = compositeColors(mEndScrim, setAlphaComponent(
+                mScrimColor, Math.round(mMaxScrimAlpha * 255)));
+        mEndFlatColorAlpha = Color.alpha(mEndFlatColor);
+        updateColors();
+        invalidate();
+    }
+
+    public void setProgress(float progress) {
+        if (mProgress != progress) {
+            mProgress = progress;
+            updateColors();
+            updateDragHandleAlpha();
+            invalidate();
+        }
+    }
+
+    public void reInitUi() { }
+
+    protected void updateColors() {
+        mCurrentFlatColor = mProgress >= 1 ? 0 : setAlphaComponent(
+                mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha));
+    }
+
+    protected void updateDragHandleAlpha() {
+        if (mDragHandle != null) {
+            mDragHandle.setAlpha(mDragHandleAlpha);
+        }
+    }
+
+    private void setDragHandleAlpha(int alpha) {
+        if (alpha != mDragHandleAlpha) {
+            mDragHandleAlpha = alpha;
+            if (mDragHandle != null) {
+                mDragHandle.setAlpha(mDragHandleAlpha);
+                invalidate();
+            }
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mCurrentFlatColor != 0) {
+            canvas.drawColor(mCurrentFlatColor);
+        }
+        drawDragHandle(canvas);
+    }
+
+    protected void drawDragHandle(Canvas canvas) {
+        if (mDragHandle != null) {
+            canvas.translate(0, -mDragHandleOffset);
+            mDragHandle.draw(canvas);
+            canvas.translate(0, mDragHandleOffset);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        boolean value = super.onTouchEvent(event);
+        if (!value && mDragHandle != null && event.getAction() == ACTION_DOWN
+                && mDragHandle.getAlpha() == 255
+                && mHitRect.contains(event.getX(), event.getY())) {
+
+            final Drawable drawable = mDragHandle;
+            mDragHandle = null;
+
+            Rect bounds = new Rect(mDragHandleBounds);
+            bounds.offset(0, -(int) mDragHandleOffset);
+            drawable.setBounds(bounds);
+
+            Rect topBounds = new Rect(bounds);
+            topBounds.offset(0, -bounds.height() / 2);
+
+            Rect invalidateRegion = new Rect(bounds);
+            invalidateRegion.top = topBounds.top;
+
+            Keyframe frameTop = Keyframe.ofObject(0.6f, topBounds);
+            frameTop.setInterpolator(DEACCEL);
+            Keyframe frameBot = Keyframe.ofObject(1, bounds);
+            frameBot.setInterpolator(ACCEL);
+            PropertyValuesHolder holder = PropertyValuesHolder .ofKeyframe("bounds",
+                    Keyframe.ofObject(0, bounds), frameTop, frameBot);
+            holder.setEvaluator(new RectEvaluator());
+
+            ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(drawable, holder);
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    getOverlay().remove(drawable);
+                    updateDragHandleVisibility(drawable);
+                }
+            });
+            anim.addUpdateListener((v) -> invalidate(invalidateRegion));
+            getOverlay().add(drawable);
+            anim.start();
+        }
+        return value;
+    }
+
+    protected void updateDragHandleBounds() {
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        final int left;
+        final int width = getMeasuredWidth();
+        final int top = getMeasuredHeight() - mDragHandleSize - grid.getInsets().bottom;
+        final int topMargin;
+
+        if (grid.isVerticalBarLayout()) {
+            topMargin = grid.workspacePadding.bottom;
+            if (grid.isSeascape()) {
+                left = width - grid.getInsets().right - mDragHandleSize;
+            } else {
+                left = mDragHandleSize + grid.getInsets().left;
+            }
+        } else {
+            left = (width - mDragHandleSize) / 2;
+            topMargin = grid.hotseatBarSizePx;
+        }
+        mDragHandleBounds.offsetTo(left, top - topMargin);
+        mHitRect.set(mDragHandleBounds);
+        float inset = -mDragHandleSize / 2;
+        mHitRect.inset(inset, inset);
+
+        if (mDragHandle != null) {
+            mDragHandle.setBounds(mDragHandleBounds);
+        }
+    }
+
+    @Override
+    public void onAccessibilityStateChanged(boolean enabled) {
+        LauncherStateManager stateManager = mLauncher.getStateManager();
+        stateManager.removeStateListener(this);
+
+        if (enabled) {
+            stateManager.addStateListener(this);
+            onStateSetImmediately(mLauncher.getStateManager().getState());
+        } else {
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+        }
+        updateDragHandleVisibility(null);
+    }
+
+    private void updateDragHandleVisibility(Drawable recycle) {
+        boolean visible = mLauncher.getDeviceProfile().isVerticalBarLayout() || mAM.isEnabled();
+        boolean wasVisible = mDragHandle != null;
+        if (visible != wasVisible) {
+            if (visible) {
+                mDragHandle = recycle != null ? recycle :
+                        mLauncher.getDrawable(R.drawable.drag_handle_indicator);
+                mDragHandle.setBounds(mDragHandleBounds);
+
+                updateDragHandleAlpha();
+            } else {
+                mDragHandle = null;
+            }
+            invalidate();
+        }
+    }
+
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        return mAccessibilityHelper.dispatchHoverEvent(event) || super.dispatchHoverEvent(event);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return mAccessibilityHelper.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public void onFocusChanged(boolean gainFocus, int direction,
+            Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        mAccessibilityHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+    }
+
+    @Override
+    public void onStateTransitionStart(LauncherState toState) {}
+
+    @Override
+    public void onStateTransitionComplete(LauncherState finalState) {
+        onStateSetImmediately(finalState);
+    }
+
+    @Override
+    public void onStateSetImmediately(LauncherState state) {
+        setImportantForAccessibility(state == ALL_APPS
+                ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+    }
+
+    protected class AccessibilityHelper extends ExploreByTouchHelper {
+
+        private static final int DRAG_HANDLE_ID = 1;
+
+        public AccessibilityHelper() {
+            super(ScrimView.this);
+        }
+
+        @Override
+        protected int getVirtualViewAt(float x, float y) {
+            return  mDragHandleBounds.contains((int) x, (int) y)
+                    ? DRAG_HANDLE_ID : INVALID_ID;
+        }
+
+        @Override
+        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+            virtualViewIds.add(DRAG_HANDLE_ID);
+        }
+
+        @Override
+        protected void onPopulateNodeForVirtualView(int virtualViewId,
+                AccessibilityNodeInfoCompat node) {
+            node.setContentDescription(getContext().getString(R.string.all_apps_button_label));
+            node.setBoundsInParent(mDragHandleBounds);
+
+            getLocationOnScreen(mTempPos);
+            mTempRect.set(mDragHandleBounds);
+            mTempRect.offset(mTempPos[0], mTempPos[1]);
+            node.setBoundsInScreen(mTempRect);
+
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+            node.setClickable(true);
+            node.setFocusable(true);
+
+            if (mLauncher.isInState(NORMAL)) {
+                Context context = getContext();
+                if (Utilities.isWallpaperAllowed(context)) {
+                    node.addAction(
+                            new AccessibilityActionCompat(WALLPAPERS, context.getText(WALLPAPERS)));
+                }
+                node.addAction(new AccessibilityActionCompat(WIDGETS, context.getText(WIDGETS)));
+                node.addAction(new AccessibilityActionCompat(SETTINGS, context.getText(SETTINGS)));
+            }
+        }
+
+        @Override
+        protected boolean onPerformActionForVirtualView(
+                int virtualViewId, int action, Bundle arguments) {
+            if (action == AccessibilityNodeInfoCompat.ACTION_CLICK) {
+                mLauncher.getUserEventDispatcher().logActionOnControl(
+                        Action.Touch.TAP, ControlType.ALL_APPS_BUTTON,
+                        mLauncher.getStateManager().getState().containerType);
+                mLauncher.getStateManager().goToState(ALL_APPS);
+                return true;
+            } else if (action == WALLPAPERS) {
+                return OptionsPopupView.startWallpaperPicker(ScrimView.this);
+            } else if (action == WIDGETS) {
+                return OptionsPopupView.onWidgetsClicked(ScrimView.this);
+            } else if (action == SETTINGS) {
+                return OptionsPopupView.startSettings(ScrimView.this);
+            }
+
+            return false;
+        }
+    }
+
+    public int getDragHandleSize() {
+        return mDragHandleSize;
+    }
+}
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
new file mode 100644
index 0000000..b0313ce
--- /dev/null
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2018 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 android.content.Context;
+import android.graphics.Canvas;
+import android.support.animation.DynamicAnimation;
+import android.support.animation.FloatPropertyCompat;
+import android.support.animation.SpringAnimation;
+import android.support.animation.SpringForce;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.EdgeEffectFactory;
+import android.util.AttributeSet;
+import android.util.SparseBooleanArray;
+import android.view.View;
+import android.widget.EdgeEffect;
+import android.widget.RelativeLayout;
+
+import static android.support.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
+import static android.support.animation.SpringForce.STIFFNESS_LOW;
+import static android.support.animation.SpringForce.STIFFNESS_MEDIUM;
+
+public class SpringRelativeLayout extends RelativeLayout {
+
+    private static final float STIFFNESS = (STIFFNESS_MEDIUM + STIFFNESS_LOW) / 2;
+    private static final float DAMPING_RATIO = DAMPING_RATIO_MEDIUM_BOUNCY;
+    private static final float VELOCITY_MULTIPLIER = 0.3f;
+
+    private static final FloatPropertyCompat<SpringRelativeLayout> DAMPED_SCROLL =
+            new FloatPropertyCompat<SpringRelativeLayout>("value") {
+
+                @Override
+                public float getValue(SpringRelativeLayout object) {
+                    return object.mDampedScrollShift;
+                }
+
+                @Override
+                public void setValue(SpringRelativeLayout object, float value) {
+                    object.setDampedScrollShift(value);
+                }
+            };
+
+    protected final SparseBooleanArray mSpringViews = new SparseBooleanArray();
+    private final SpringAnimation mSpring;
+
+    private float mDampedScrollShift = 0;
+    private SpringEdgeEffect mActiveEdge;
+
+    public SpringRelativeLayout(Context context) {
+        this(context, null);
+    }
+
+    public SpringRelativeLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mSpring = new SpringAnimation(this, DAMPED_SCROLL, 0);
+        mSpring.setSpring(new SpringForce(0)
+                .setStiffness(STIFFNESS)
+                .setDampingRatio(DAMPING_RATIO));
+    }
+
+    public void addSpringView(int id) {
+        mSpringViews.put(id, true);
+    }
+
+    public void removeSpringView(int id) {
+        mSpringViews.delete(id);
+        invalidate();
+    }
+
+    /**
+     * Used to clip the canvas when drawing child views during overscroll.
+     */
+    public int getCanvasClipTopForOverscroll() {
+        return 0;
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        if (mDampedScrollShift != 0 && mSpringViews.get(child.getId())) {
+            int saveCount = canvas.save();
+
+            canvas.clipRect(0, getCanvasClipTopForOverscroll(), getWidth(), getHeight());
+            canvas.translate(0, mDampedScrollShift);
+            boolean result = super.drawChild(canvas, child, drawingTime);
+
+            canvas.restoreToCount(saveCount);
+
+            return result;
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    private void setActiveEdge(SpringEdgeEffect edge) {
+        if (mActiveEdge != edge && mActiveEdge != null) {
+            mActiveEdge.mDistance = 0;
+        }
+        mActiveEdge = edge;
+    }
+
+    protected void setDampedScrollShift(float shift) {
+        if (shift != mDampedScrollShift) {
+            mDampedScrollShift = shift;
+            invalidate();
+        }
+    }
+
+    private void finishScrollWithVelocity(float velocity) {
+        mSpring.setStartVelocity(velocity);
+        mSpring.setStartValue(mDampedScrollShift);
+        mSpring.start();
+    }
+
+    protected void finishWithShiftAndVelocity(float shift, float velocity,
+            DynamicAnimation.OnAnimationEndListener listener) {
+        setDampedScrollShift(shift);
+        mSpring.addEndListener(listener);
+        finishScrollWithVelocity(velocity);
+    }
+
+    public EdgeEffectFactory createEdgeEffectFactory() {
+        return new SpringEdgeEffectFactory();
+    }
+
+    private class SpringEdgeEffectFactory extends EdgeEffectFactory {
+
+        @NonNull @Override
+        protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
+            switch (direction) {
+                case DIRECTION_TOP:
+                    return new SpringEdgeEffect(getContext(), +VELOCITY_MULTIPLIER);
+                case DIRECTION_BOTTOM:
+                    return new SpringEdgeEffect(getContext(), -VELOCITY_MULTIPLIER);
+            }
+            return super.createEdgeEffect(view, direction);
+        }
+    }
+
+    private class SpringEdgeEffect extends EdgeEffect {
+
+        private final float mVelocityMultiplier;
+
+        private float mDistance;
+
+        public SpringEdgeEffect(Context context, float velocityMultiplier) {
+            super(context);
+            mVelocityMultiplier = velocityMultiplier;
+        }
+
+        @Override
+        public boolean draw(Canvas canvas) {
+            return false;
+        }
+
+        @Override
+        public void onAbsorb(int velocity) {
+            finishScrollWithVelocity(velocity * mVelocityMultiplier);
+        }
+
+        @Override
+        public void onPull(float deltaDistance, float displacement) {
+            setActiveEdge(this);
+            mDistance += deltaDistance * (mVelocityMultiplier / 3f);
+            setDampedScrollShift(mDistance * getHeight());
+        }
+
+        @Override
+        public void onRelease() {
+            mDistance = 0;
+            finishScrollWithVelocity(0);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/views/TopRoundedCornerView.java b/src/com/android/launcher3/views/TopRoundedCornerView.java
new file mode 100644
index 0000000..7888b08
--- /dev/null
+++ b/src/com/android/launcher3/views/TopRoundedCornerView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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 android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+
+/**
+ * View with top rounded corners.
+ */
+public class TopRoundedCornerView extends SpringRelativeLayout {
+
+    private final RectF mRect = new RectF();
+    private final Path mClipPath = new Path();
+    private float[] mRadii;
+
+    private final Paint mNavBarScrimPaint;
+    private int mNavBarScrimHeight = 0;
+
+    public TopRoundedCornerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        int radius = getResources().getDimensionPixelSize(R.dimen.bg_round_rect_radius);
+        mRadii = new float[] {radius, radius, radius, radius, 0, 0, 0, 0};
+
+        mNavBarScrimPaint = new Paint();
+        mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
+    }
+
+    public TopRoundedCornerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public void setNavBarScrimHeight(int height) {
+        if (mNavBarScrimHeight != height) {
+            mNavBarScrimHeight = height;
+            invalidate();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.save();
+        canvas.clipPath(mClipPath);
+        super.draw(canvas);
+        canvas.restore();
+
+        if (mNavBarScrimHeight > 0) {
+            canvas.drawRect(0, getHeight() - mNavBarScrimHeight, getWidth(), getHeight(),
+                    mNavBarScrimPaint);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+        mClipPath.reset();
+        mClipPath.addRoundRect(mRect, mRadii, Path.Direction.CW);
+    }
+}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index b22509c..10708d6 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -31,7 +31,8 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.graphics.GradientView;
+import com.android.launcher3.graphics.ColorScrim;
+import com.android.launcher3.touch.ItemLongClickListener;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
 import com.android.launcher3.util.SystemUiController;
@@ -48,10 +49,11 @@
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
 
-    protected GradientView mGradientView;
+    protected final ColorScrim mColorScrim;
 
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mColorScrim = ColorScrim.createExtractedColorScrim(this);
     }
 
     @Override
@@ -70,7 +72,7 @@
 
     @Override
     public final boolean onLongClick(View v) {
-        if (!mLauncher.isDraggingEnabled()) return false;
+        if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
 
         if (v instanceof WidgetCell) {
             return beginDraggingWidget((WidgetCell) v);
@@ -80,7 +82,7 @@
 
     protected void setTranslationShift(float translationShift) {
         super.setTranslationShift(translationShift);
-        mGradientView.setAlpha(1 - mTranslationShift);
+        mColorScrim.setProgress(1 - mTranslationShift);
     }
 
     private boolean beginDraggingWidget(WidgetCell v) {
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
index 37e5efcb..3a24c3d 100644
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -44,7 +44,8 @@
         mPaint = new TextPaint();
         mPaint.setColor(Color.WHITE);
         mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+                mLauncher.getDeviceProfile().getFullScreenProfile().iconTextSizePx,
+                getResources().getDisplayMetrics()));
         setBackgroundResource(R.drawable.bg_deferred_app_widget);
     }
 
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 0b1474a..12859c7 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -47,7 +47,7 @@
 import com.android.launcher3.StylusEventHelper;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
+import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
 
 import java.util.ArrayList;
 
@@ -488,13 +488,14 @@
         // Only reinflate when the final configuration is same as the required configuration
         if (mReinflateOnConfigChange && isSameOrientation()) {
             mReinflateOnConfigChange = false;
-            if (isAttachedToWindow()) {
-                reInflate();
-            }
+            reInflate();
         }
     }
 
     public void reInflate() {
+        if (!isAttachedToWindow()) {
+            return;
+        }
         LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
         // Remove and rebind the current widget (which was inflated in the wrong
         // orientation), but don't delete it from the database
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 6970833..961799d 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.graphics.DrawableFactory;
 import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 
@@ -83,7 +84,7 @@
 
         setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
         updateAppWidget(null);
-        setOnClickListener(mLauncher);
+        setOnClickListener(ItemClickHandler.INSTANCE);
 
         if (info.pendingItemInfo == null) {
             info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName());
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index aa5b785..74ab14f 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -149,7 +149,7 @@
 
         // Start the drag
         launcher.getDragController().startDrag(preview, dragLayerX, dragLayerY, source, mAddInfo,
-                dragOffset, dragRegion, scale, options);
+                dragOffset, dragRegion, scale, scale, options);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 6a9013d..5ce7e04 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -32,7 +33,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.util.PackageUserKey;
 
@@ -55,10 +55,6 @@
         super(context, attrs, defStyleAttr);
         setWillNotDraw(false);
         mInsets = new Rect();
-
-        mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate(
-                R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false);
-        mGradientView.setProgress(1, false);
         mContent = this;
     }
 
@@ -75,10 +71,9 @@
 
         onWidgetsBound();
 
-        mLauncher.getDragLayer().addView(mGradientView);
         mLauncher.getDragLayer().addView(this);
         mIsOpen = false;
-        open(true);
+        animateOpen();
     }
 
     @Override
@@ -135,20 +130,16 @@
         return widget;
     }
 
-    private void open(boolean animate) {
+    private void animateOpen() {
         if (mIsOpen || mOpenCloseAnimator.isRunning()) {
             return;
         }
         mIsOpen = true;
         setupNavBarColor();
-        if (animate) {
-            mOpenCloseAnimator.setValues(
-                    PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
-            mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-            mOpenCloseAnimator.start();
-        } else {
-            setTranslationShift(TRANSLATION_SHIFT_OPENED);
-        }
+        mOpenCloseAnimator.setValues(
+                PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+        mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mOpenCloseAnimator.start();
     }
 
     @Override
@@ -157,12 +148,6 @@
     }
 
     @Override
-    protected void onCloseComplete() {
-        super.onCloseComplete();
-        mLauncher.getDragLayer().removeView(mGradientView);
-    }
-
-    @Override
     protected boolean isOfType(@FloatingViewType int type) {
         return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;
     }
@@ -182,4 +167,10 @@
     protected int getElementsRowCount() {
         return 1;
     }
+
+    @Override
+    protected Pair<View, String> getAccessibilityTarget() {
+        return Pair.create(findViewById(R.id.title),  getContext().getString(
+                mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index d62a909..b493228 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -20,7 +20,9 @@
 import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.graphics.Rect;
+import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -31,6 +33,8 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.R;
+import com.android.launcher3.views.RecyclerViewFastScroller;
+import com.android.launcher3.views.TopRoundedCornerView;
 
 /**
  * Popup for showing the full list of available widgets
@@ -46,7 +50,6 @@
 
     private final WidgetsListAdapter mAdapter;
 
-    private View mNavBarScrim;
     private WidgetsRecyclerView mRecyclerView;
 
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -55,6 +58,7 @@
         mAdapter = new WidgetsListAdapter(context,
                 LayoutInflater.from(context), apps.getWidgetCache(), apps.getIconCache(),
                 this, this);
+
     }
 
     public WidgetsFullSheet(Context context, AttributeSet attrs) {
@@ -65,19 +69,24 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContent = findViewById(R.id.container);
-        mNavBarScrim = findViewById(R.id.nav_bar_bg);
 
         mRecyclerView = findViewById(R.id.widgets_list_view);
         mRecyclerView.setAdapter(mAdapter);
         mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
 
-        mGradientView = findViewById(R.id.gradient_bg);
-        mGradientView.setProgress(1, false);
-
+        TopRoundedCornerView springLayout = (TopRoundedCornerView) mContent;
+        springLayout.addSpringView(R.id.widgets_list_view);
+        mRecyclerView.setEdgeEffectFactory(springLayout.createEdgeEffectFactory());
         onWidgetsBound();
     }
 
     @Override
+    protected Pair<View, String> getAccessibilityTarget() {
+        return Pair.create(mRecyclerView, getContext().getString(
+                mIsOpen ? R.string.widgets_list : R.string.widgets_list_closed));
+    }
+
+    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mLauncher.getAppWidgetHost().addProviderChangeListener(this);
@@ -94,7 +103,6 @@
     public void setInsets(Rect insets) {
         mInsets.set(insets);
 
-        mNavBarScrim.getLayoutParams().height = insets.bottom;
         mRecyclerView.setPadding(
                 mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
                 mRecyclerView.getPaddingRight(), insets.bottom);
@@ -103,6 +111,8 @@
         } else {
             clearNavBarColor();
         }
+
+        ((TopRoundedCornerView) mContent).setNavBarScrimHeight(mInsets.bottom);
         requestLayout();
     }
 
@@ -110,9 +120,6 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int widthUsed;
         if (mInsets.bottom > 0) {
-            // If we have bottom insets, we do not show the scrim as it would overlap
-            // with the navbar scrim
-            mGradientView.setVisibility(View.INVISIBLE);
             widthUsed = 0;
         } else {
             Rect padding = mLauncher.getDeviceProfile().workspacePadding;
@@ -123,15 +130,14 @@
         int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx;
         measureChildWithMargins(mContent, widthMeasureSpec,
                 widthUsed, heightMeasureSpec, heightUsed);
-        measureChild(mGradientView, widthMeasureSpec, heightMeasureSpec);
-        setMeasuredDimension(mGradientView.getMeasuredWidth(), mGradientView.getMeasuredHeight());
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
+                MeasureSpec.getSize(heightMeasureSpec));
     }
 
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int width = r - l;
         int height = b - t;
-        mGradientView.layout(0, 0, width, height);
 
         // Content is laid out as center bottom aligned
         int contentWidth = mContent.getMeasuredWidth();
@@ -153,10 +159,6 @@
     }
 
     private void open(boolean animate) {
-        if (mIsOpen) {
-            return;
-        }
-        mIsOpen = true;
         if (animate) {
             if (mLauncher.getDragLayer().getInsets().bottom > 0) {
                 mContent.setAlpha(0);
@@ -176,17 +178,15 @@
                     mOpenCloseAnimator.removeListener(this);
                 }
             });
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.setLayoutFrozen(true);
-                    mOpenCloseAnimator.start();
-                    mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
-                }
+            post(() -> {
+                mRecyclerView.setLayoutFrozen(true);
+                mOpenCloseAnimator.start();
+                mContent.animate().alpha(1).setDuration(FADE_IN_DURATION);
             });
         } else {
             setTranslationShift(TRANSLATION_SHIFT_OPENED);
             mAdapter.setApplyBitmapDeferred(false, mRecyclerView);
+            post(this::announceAccessibilityChanges);
         }
     }
 
@@ -205,7 +205,11 @@
         // Disable swipe down when recycler view is scrolling
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mNoIntercept = false;
-            if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+            RecyclerViewFastScroller scroller = mRecyclerView.getScrollbar();
+            if (scroller.getThumbOffsetY() >= 0 &&
+                    mLauncher.getDragLayer().isEventOverView(scroller, ev)) {
+                mNoIntercept = true;
+            } else if (mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
                 mNoIntercept = !mRecyclerView.shouldContainerScroll(ev, mLauncher.getDragLayer());
             }
         }
@@ -215,11 +219,17 @@
     public static WidgetsFullSheet show(Launcher launcher, boolean animate) {
         WidgetsFullSheet sheet = (WidgetsFullSheet) launcher.getLayoutInflater()
                 .inflate(R.layout.widgets_full_sheet, launcher.getDragLayer(), false);
+        sheet.mIsOpen = true;
         launcher.getDragLayer().addView(sheet);
         sheet.open(animate);
         return sheet;
     }
 
+    @VisibleForTesting
+    public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
+        return launcher.findViewById(R.id.widgets_list_view);
+    }
+
     @Override
     protected int getElementsRowCount() {
         return mAdapter.getItemCount();
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
index 89c88a4..124058e 100644
--- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -17,8 +17,12 @@
 package com.android.launcher3.widget;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.OnItemTouchListener;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.launcher3.BaseRecyclerView;
@@ -27,13 +31,15 @@
 /**
  * The widgets recycler view.
  */
-public class WidgetsRecyclerView extends BaseRecyclerView {
+public class WidgetsRecyclerView extends BaseRecyclerView implements OnItemTouchListener {
 
-    private static final String TAG = "WidgetsRecyclerView";
     private WidgetsListAdapter mAdapter;
 
     private final int mScrollbarTop;
 
+    private final Point mFastScrollerOffset = new Point();
+    private boolean mTouchDownOnScroller;
+
     public WidgetsRecyclerView(Context context) {
         this(context, null);
     }
@@ -46,6 +52,7 @@
         // API 21 and below only support 3 parameter ctor.
         super(context, attrs, defStyleAttr);
         mScrollbarTop = getResources().getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+        addOnItemTouchListener(this);
     }
 
     public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
@@ -56,7 +63,6 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        addOnItemTouchListener(this);
         // create a layout manager with Launcher's context so that scroll position
         // can be preserved during screen rotation.
         setLayoutManager(new LinearLayoutManager(getContext()));
@@ -145,4 +151,26 @@
     public int getScrollBarTop() {
         return mScrollbarTop;
     }
+
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (e.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchDownOnScroller =
+                    mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+        }
+        if (mTouchDownOnScroller) {
+            return mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+        }
+        return false;
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        if (mTouchDownOnScroller) {
+            mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
+        }
+    }
+
+    @Override
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { }
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
index bc85db6..8f269a6 100644
--- a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -29,7 +29,8 @@
     public WidgetsRowViewHolder(ViewGroup v) {
         super(v);
 
-        cellContainer = (ViewGroup) v.findViewById(R.id.widgets_cell_list);
-        title = (BubbleTextView) v.findViewById(R.id.section);
+        cellContainer = v.findViewById(R.id.widgets_cell_list);
+        title = v.findViewById(R.id.section);
+        title.setAccessibilityDelegate(null);
     }
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index fd33ee1..f7bb254 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -16,16 +16,13 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
-import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
+import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
 
-import android.view.View;
-
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 /**
@@ -33,6 +30,8 @@
  */
 public class AllAppsState extends LauncherState {
 
+    private static final float PARALLAX_COEFFICIENT = .125f;
+
     private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
 
     private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) {
@@ -48,8 +47,8 @@
 
     @Override
     public void onStateEnabled(Launcher launcher) {
-        if (!launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)) {
-            launcher.getSharedPrefs().edit().putBoolean(APPS_VIEW_SHOWN, true).apply();
+        if (!launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)) {
+            launcher.getSharedPrefs().edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
         }
 
         AbstractFloatingView.closeAllOpenViews(launcher);
@@ -62,20 +61,14 @@
     }
 
     @Override
-    public float getHoseatAlpha(Launcher launcher) {
-        return 0;
-    }
-
-    @Override
-    public View getFinalFocus(Launcher launcher) {
-        return launcher.getAppsView();
+    public int getVisibleElements(Launcher launcher) {
+        return ALL_APPS_HEADER | ALL_APPS_CONTENT;
     }
 
     @Override
     public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
         return new float[] { 1f, 0,
-                -launcher.getAllAppsController().getShiftRange()
-                        * AllAppsTransitionController.PARALLAX_COEFFICIENT};
+                -launcher.getAllAppsController().getShiftRange() * PARALLAX_COEFFICIENT};
     }
 
     @Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
index 76b7e0d..e9dc800 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -21,31 +5,41 @@
 
 import android.view.MotionEvent;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.LauncherStateManager.AnimationComponents;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.util.VerticalSwipeController;
 
 /**
- * Extension of {@link VerticalSwipeController} to switch between NORMAL and ALL_APPS state.
+ * TouchController to switch between NORMAL and ALL_APPS state.
  */
-public class AllAppsSwipeController extends VerticalSwipeController {
+public class AllAppsSwipeController extends AbstractStateChangeTouchController {
 
-    private int mStartContainerType;
+    private MotionEvent mTouchDownEvent;
 
     public AllAppsSwipeController(Launcher l) {
-        super(l, NORMAL);
+        super(l, SwipeDetector.VERTICAL);
     }
 
     @Override
-    protected boolean shouldInterceptTouch(MotionEvent ev) {
+    protected boolean canInterceptTouch(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchDownEvent = ev;
+        }
+        if (mCurrentAnimation != null) {
+            // If we are already animating from a previous state, we can intercept.
+            return true;
+        }
+        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+            return false;
+        }
         if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(ALL_APPS)) {
             // Don't listen for the swipe gesture if we are already in some other state.
             return false;
         }
-
         if (mLauncher.isInState(ALL_APPS) && !mLauncher.getAppsView().shouldContainerScroll(ev)) {
             return false;
         }
@@ -53,26 +47,30 @@
     }
 
     @Override
-    protected int getSwipeDirection(MotionEvent ev) {
-        if (mLauncher.isInState(ALL_APPS)) {
-            mStartContainerType = ContainerType.ALLAPPS;
-            return SwipeDetector.DIRECTION_NEGATIVE;
-        } else {
-            mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
-                    ContainerType.HOTSEAT : ContainerType.WORKSPACE;
-            return SwipeDetector.DIRECTION_POSITIVE;
+    protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+        if (fromState == NORMAL && isDragTowardPositive) {
+            return ALL_APPS;
+        } else if (fromState == ALL_APPS && !isDragTowardPositive) {
+            return NORMAL;
         }
+        return fromState;
     }
 
     @Override
-    protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
-        if (stateChanged) {
-            // Transition complete. log the action
-            mLauncher.getUserEventDispatcher().logActionOnContainer(
-                    wasFling ? Touch.FLING : Touch.SWIPE,
-                    mLauncher.isInState(ALL_APPS) ? Direction.UP : Direction.DOWN,
-                    mStartContainerType,
-                    mLauncher.getWorkspace().getCurrentPage());
-        }
+    protected int getLogContainerTypeForNormalState() {
+        return mLauncher.getDragLayer().isEventOverView(mLauncher.getHotseat(), mTouchDownEvent) ?
+                ContainerType.HOTSEAT : ContainerType.WORKSPACE;
+    }
+
+    @Override
+    protected float initCurrentAnimation(@AnimationComponents int animComponents) {
+        float range = getShiftRange();
+        long maxAccuracy = (long) (2 * range);
+        mCurrentAnimation = mLauncher.getStateManager()
+                .createAnimationToNewWorkspace(mToState, maxAccuracy, animComponents);
+        float startVerticalShift = mFromState.getVerticalProgress(mLauncher) * range;
+        float endVerticalShift = mToState.getVerticalProgress(mLauncher) * range;
+        float totalShift = endVerticalShift - startVerticalShift;
+        return 1 / totalShift;
     }
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/DisplayRotationListener.java b/src_ui_overrides/com/android/launcher3/uioverrides/DisplayRotationListener.java
new file mode 100644
index 0000000..b1a67e9
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/DisplayRotationListener.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+import android.content.Context;
+import android.view.OrientationEventListener;
+
+/**
+ * Utility class for listening for rotation changes
+ */
+public class DisplayRotationListener extends OrientationEventListener {
+
+    private final Runnable mCallback;
+
+    public DisplayRotationListener(Context context, Runnable callback) {
+        super(context);
+        mCallback = callback;
+    }
+
+    @Override
+    public void onOrientationChanged(int i) {
+        mCallback.run();
+    }
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/FastOverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/FastOverviewState.java
new file mode 100644
index 0000000..147d194
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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.uioverrides;
+
+/**
+ * A dummy overview state
+ */
+public class FastOverviewState extends OverviewState {
+
+    public FastOverviewState(int id) {
+        super(id);
+    }
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
deleted file mode 100644
index 88a1e10..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 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.uioverrides;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-
-/**
- * Accessibility delegate with actions pointing to various Overview entry points.
- */
-public class OverviewAccessibilityDelegate extends AccessibilityDelegate {
-
-    private static final int OVERVIEW = R.string.accessibility_action_overview;
-    private static final int WALLPAPERS = R.string.wallpaper_button_text;
-    private static final int WIDGETS = R.string.widget_button_text;
-    private static final int SETTINGS = R.string.settings_button_text;
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(host, info);
-
-        Context context = host.getContext();
-        info.addAction(new AccessibilityAction(OVERVIEW, context.getText(OVERVIEW)));
-
-        if (Utilities.isWallpaperAllowed(context)) {
-            info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
-        }
-        info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS)));
-        info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS)));
-    }
-
-    @Override
-    public boolean performAccessibilityAction(View host, int action, Bundle args) {
-        Launcher launcher = Launcher.getLauncher(host.getContext());
-        OverviewPanel overviewPanel = launcher.findViewById(R.id.overview_panel);
-        if (action == OVERVIEW) {
-            launcher.getStateManager().goToState(LauncherState.OVERVIEW);
-            return true;
-        } else if (action == WALLPAPERS) {
-            launcher.onClickWallpaperPicker(host);
-            return true;
-        } else if (action == WIDGETS) {
-            overviewPanel.onClickAddWidgetButton();
-            return true;
-        } else if (action == SETTINGS) {
-            overviewPanel.onClickSettingsButton(host);
-            return true;
-        }
-        return super.performAccessibilityAction(host, action, args);
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
deleted file mode 100644
index 2d39505..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.android.launcher3.Insettable;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherStateManager;
-import com.android.launcher3.LauncherStateManager.AnimationConfig;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
-import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
-import com.android.launcher3.widget.WidgetsFullSheet;
-
-public class OverviewPanel extends LinearLayout implements Insettable, View.OnClickListener,
-        View.OnLongClickListener, LauncherStateManager.StateHandler {
-
-    // Out of 100, the percent of space the overview bar should try and take vertically.
-    private static final float OVERVIEW_ICON_ZONE_RATIO = 0.22f;
-
-    private final Launcher mLauncher;
-
-    public OverviewPanel(Context context) {
-        this(context, null);
-    }
-
-    public OverviewPanel(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public OverviewPanel(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        mLauncher = Launcher.getLauncher(context);
-        setAlpha(0);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        int visibleChildCount = 3;
-        // Attach buttons.
-        attachListeners(findViewById(R.id.wallpaper_button));
-        attachListeners(findViewById(R.id.widget_button));
-
-        View settingsButton = findViewById(R.id.settings_button);
-        if (mLauncher.hasSettings()) {
-            attachListeners(settingsButton);
-        } else {
-            settingsButton.setVisibility(GONE);
-            visibleChildCount--;
-        }
-
-        // Init UI
-        Resources res = getResources();
-        int itemWidthPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_item_width);
-        int spacerWidthPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_spacer_width);
-
-        int totalItemWidth = visibleChildCount * itemWidthPx;
-        int maxWidth = totalItemWidth + (visibleChildCount - 1) * spacerWidthPx;
-
-        getLayoutParams().width = Math.min(mLauncher.getDeviceProfile().availableWidthPx, maxWidth);
-        getLayoutParams().height = getButtonBarHeight(mLauncher);
-    }
-
-    private void attachListeners(View view) {
-        view.setOnClickListener(this);
-        view.setOnLongClickListener(this);
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        ((FrameLayout.LayoutParams) getLayoutParams()).bottomMargin = insets.bottom;
-    }
-
-    @Override
-    public void onClick(View view) {
-        handleViewClick(view, Action.Touch.TAP);
-    }
-
-    @Override
-    public boolean onLongClick(View view) {
-        return handleViewClick(view, Action.Touch.LONGPRESS);
-    }
-
-    private boolean handleViewClick(View view, int action) {
-        if (mLauncher.getWorkspace().isSwitchingState()) {
-            return false;
-        }
-
-        final int controlType;
-        if (view.getId() == R.id.wallpaper_button) {
-            mLauncher.onClickWallpaperPicker(view);
-            controlType = ControlType.WALLPAPER_BUTTON;
-        } else if (view.getId() == R.id.widget_button) {
-            onClickAddWidgetButton();
-            controlType = ControlType.WIDGETS_BUTTON;
-        } else if (view.getId() == R.id.settings_button) {
-            onClickSettingsButton(view);
-            controlType = ControlType.SETTINGS_BUTTON;
-        } else {
-            return false;
-        }
-
-        mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType);
-        return true;
-    }
-
-    /**
-     * Event handler for the (Add) Widgets button that appears after a long press
-     * on the home screen.
-     */
-    public void onClickAddWidgetButton() {
-        if (getContext().getPackageManager().isSafeMode()) {
-            Toast.makeText(mLauncher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
-        } else {
-            WidgetsFullSheet.show(mLauncher, true /* animated */);
-        }
-    }
-
-    /**
-     * Event handler for a click on the settings button that appears after a long press
-     * on the home screen.
-     */
-    public void onClickSettingsButton(View v) {
-        Intent intent = new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
-                .setPackage(getContext().getPackageName());
-        intent.setSourceBounds(mLauncher.getViewBounds(v));
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getContext().startActivity(intent, mLauncher.getActivityLaunchOptions(v, false));
-    }
-
-    @Override
-    public void setState(LauncherState state) {
-        setState(state, NO_ANIM_PROPERTY_SETTER);
-    }
-
-    @Override
-    public void setStateWithAnimation(LauncherState toState,
-            AnimatorSetBuilder builder, AnimationConfig config) {
-        setState(toState, new AnimatedPropertySetter(config.duration, builder));
-    }
-
-    private void setState(LauncherState state, PropertySetter setter) {
-        setter.setViewAlpha(this, 1f - state.getHoseatAlpha(mLauncher), Interpolators.ACCEL);
-    }
-
-    public static int getButtonBarHeight(Launcher launcher) {
-        int zoneHeight = (int) (OVERVIEW_ICON_ZONE_RATIO *
-                launcher.getDeviceProfile().availableHeightPx);
-        Resources res = launcher.getResources();
-        int overviewModeMinIconZoneHeightPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
-        int overviewModeMaxIconZoneHeightPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_max_icon_zone_height);
-        return Utilities.boundToRange(zoneHeight,
-                overviewModeMinIconZoneHeightPx,
-                overviewModeMaxIconZoneHeightPx);
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index d18901d..8def0d3 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,16 +16,8 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
 
-import android.graphics.Rect;
-import android.view.View;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 /**
@@ -33,56 +25,7 @@
  */
 public class OverviewState extends LauncherState {
 
-    // The percent to shrink the workspace during overview mode
-    private static final float SCALE_FACTOR = 0.7f;
-
-    private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
-            FLAG_DISABLE_PAGE_CLIPPING;
-
     public OverviewState(int id) {
-        super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
-    }
-
-    @Override
-    public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
-        DeviceProfile grid = launcher.getDeviceProfile();
-        Workspace ws = launcher.getWorkspace();
-        Rect insets = launcher.getDragLayer().getInsets();
-
-        int overviewButtonBarHeight = OverviewPanel.getButtonBarHeight(launcher);
-        int scaledHeight = (int) (SCALE_FACTOR * ws.getNormalChildHeight());
-        int workspaceTop = insets.top + grid.workspacePadding.top;
-        int workspaceBottom = ws.getHeight() - insets.bottom - grid.workspacePadding.bottom;
-        int overviewTop = insets.top;
-        int overviewBottom = ws.getHeight() - insets.bottom - overviewButtonBarHeight;
-        int workspaceOffsetTopEdge =
-                workspaceTop + ((workspaceBottom - workspaceTop) - scaledHeight) / 2;
-        int overviewOffsetTopEdge = overviewTop + (overviewBottom - overviewTop - scaledHeight) / 2;
-        return new float[] {SCALE_FACTOR, 0, -workspaceOffsetTopEdge + overviewOffsetTopEdge };
-    }
-
-    @Override
-    public float getHoseatAlpha(Launcher launcher) {
-        return 0;
-    }
-
-    @Override
-    public void onStateEnabled(Launcher launcher) {
-        launcher.getWorkspace().setPageRearrangeEnabled(true);
-
-        if (isAccessibilityEnabled(launcher)) {
-            launcher.getOverviewPanel().getChildAt(0).performAccessibilityAction(
-                    AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
-        }
-    }
-
-    @Override
-    public void onStateDisabled(Launcher launcher) {
-        launcher.getWorkspace().setPageRearrangeEnabled(false);
-    }
-
-    @Override
-    public View getFinalFocus(Launcher launcher) {
-        return launcher.getOverviewPanel();
+        super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, FLAG_DISABLE_RESTORE);
     }
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java b/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
deleted file mode 100644
index a7c8cee..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/PinchToOverviewListener.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2016 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.uioverrides;
-
-import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.ScaleGestureDetector.OnScaleGestureListener;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Workspace;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.util.TouchController;
-
-/**
- * Detects pinches and animates the Workspace to/from overview mode.
- */
-public class PinchToOverviewListener extends AnimatorListenerAdapter
-        implements TouchController, OnScaleGestureListener {
-
-    private static final float ACCEPT_THRESHOLD = 0.65f;
-    /**
-     * The velocity threshold at which a pinch will be completed instead of canceled,
-     * even if the first threshold has not been passed. Measured in scale / millisecond
-     */
-    private static final float FLING_VELOCITY = 0.001f;
-
-    private final ScaleGestureDetector mPinchDetector;
-    private Launcher mLauncher;
-    private Workspace mWorkspace = null;
-    private boolean mPinchStarted = false;
-
-    private AnimatorPlaybackController mCurrentAnimation;
-    private float mCurrentScale;
-    private boolean mShouldGoToFinalState;
-
-    private LauncherState mToState;
-
-    public PinchToOverviewListener(Launcher launcher) {
-        mLauncher = launcher;
-        mPinchDetector = new ScaleGestureDetector(mLauncher, this);
-    }
-
-    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        mPinchDetector.onTouchEvent(ev);
-        return mPinchStarted;
-    }
-
-    public boolean onControllerTouchEvent(MotionEvent ev) {
-        return mPinchDetector.onTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onScaleBegin(ScaleGestureDetector detector) {
-        if (isAccessibilityEnabled(mLauncher)) {
-            return false;
-        }
-        if (!mLauncher.isInState(NORMAL) && !mLauncher.isInState(OVERVIEW)) {
-            // Don't listen for the pinch gesture if on all apps, widget picker, -1, etc.
-            return false;
-        }
-        if (mCurrentAnimation != null) {
-            // Don't listen for the pinch gesture if we are already animating from a previous one.
-            return false;
-        }
-        if (mLauncher.isWorkspaceLocked()) {
-            // Don't listen for the pinch gesture if the workspace isn't ready.
-            return false;
-        }
-        if (mWorkspace == null) {
-            mWorkspace = mLauncher.getWorkspace();
-        }
-        if (mWorkspace.isSwitchingState()) {
-            // Don't listen for the pinch gesture while switching state, as it will cause a jump
-            // once the state switching animation is complete.
-            return false;
-        }
-        if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
-            // Don't listen for the pinch gesture if a floating view is open.
-            return false;
-        }
-
-        if (mLauncher.getDragController().isDragging()) {
-            mLauncher.getDragController().cancelDrag();
-        }
-
-        mToState = mLauncher.isInState(OVERVIEW) ? NORMAL : OVERVIEW;
-        mCurrentAnimation = mLauncher.getStateManager()
-                .createAnimationToNewWorkspace(mToState, OVERVIEW_TRANSITION_MS);
-        mCurrentAnimation.getTarget().addListener(this);
-        mPinchStarted = true;
-        mCurrentScale = 1;
-        mShouldGoToFinalState = false;
-
-        mCurrentAnimation.dispatchOnStart();
-        return true;
-    }
-
-    @Override
-    public void onAnimationEnd(Animator animation) {
-        mCurrentAnimation = null;
-        mPinchStarted = false;
-    }
-
-    @Override
-    public void onScaleEnd(ScaleGestureDetector detector) {
-        if (mShouldGoToFinalState) {
-            mCurrentAnimation.start();
-        } else {
-            mCurrentAnimation.setEndAction(new Runnable() {
-                @Override
-                public void run() {
-                    mLauncher.getStateManager().goToState(
-                            mToState == OVERVIEW ? NORMAL : OVERVIEW, false);
-                }
-            });
-            mCurrentAnimation.reverse();
-        }
-    }
-
-    @Override
-    public boolean onScale(ScaleGestureDetector detector) {
-        mCurrentScale = detector.getScaleFactor() * mCurrentScale;
-
-        // If we are zooming out, inverse the mCurrentScale so that animationFraction = [0, 1]
-        // 0 => Animation complete
-        // 1=> Animation started
-        float animationFraction = mToState == OVERVIEW ? mCurrentScale : (1 / mCurrentScale);
-
-        float velocity = (1 - detector.getScaleFactor()) / detector.getTimeDelta();
-        if (Math.abs(velocity) >= FLING_VELOCITY) {
-            LauncherState toState = velocity > 0 ? OVERVIEW : NORMAL;
-            mShouldGoToFinalState = toState == mToState;
-        } else {
-            mShouldGoToFinalState = animationFraction <= ACCEPT_THRESHOLD;
-        }
-
-        // Move the transition animation to that duration.
-        mCurrentAnimation.setPlayFraction(1 - animationFraction);
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 64a29ea..0d727fd 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,52 +16,52 @@
 
 package com.android.launcher3.uioverrides;
 
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PointF;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
+import android.app.Activity;
+import android.content.Context;
+import android.os.CancellationSignal;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.TouchController;
 
+import java.io.PrintWriter;
+
 public class UiFactory {
 
-    public static final boolean USE_HARDWARE_BITMAP = false;
-
     public static TouchController[] createTouchControllers(Launcher launcher) {
         return new TouchController[] {
-                new AllAppsSwipeController(launcher), new PinchToOverviewListener(launcher)};
+                launcher.getDragController(), new AllAppsSwipeController(launcher)};
     }
 
-    public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
-        return new OverviewAccessibilityDelegate();
-    }
+    public static void setOnTouchControllersChangedListener(Context context, Runnable listener) { }
 
     public static StateHandler[] getStateHandler(Launcher launcher) {
         return new StateHandler[] {
-                (OverviewPanel) launcher.getOverviewPanel(),
                 launcher.getAllAppsController(), launcher.getWorkspace() };
     }
 
-    public static void onWorkspaceLongPress(Launcher launcher, PointF touchPoint) {
-        launcher.getStateManager().goToState(OVERVIEW);
-    }
-
-    public static Bitmap createFromRenderer(int width, int height, boolean forceSoftwareRenderer,
-            BitmapRenderer renderer) {
-        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        renderer.render(new Canvas(result));
-        return result;
-    }
-
     public static void resetOverview(Launcher launcher) { }
 
     public static void onLauncherStateOrFocusChanged(Launcher launcher) { }
+
+    public static void onCreate(Launcher launcher) { }
+
+    public static void onStart(Launcher launcher) { }
+
+    public static void onEnterAnimationComplete(Context context) {}
+
+    public static void onLauncherStateOrResumeChanged(Launcher launcher) { }
+
+    public static void onTrimMemory(Launcher launcher, int level) { }
+
+    public static void useFadeOutAnimationForLauncherStart(Launcher launcher,
+            CancellationSignal cancellationSignal) { }
+
+    public static boolean dumpActivity(Activity activity, PrintWriter writer) {
+        return false;
+    }
+
+    public static void prepareToShowOverview(Launcher launcher) { }
+
+    public static void setBackButtonAlpha(Launcher launcher, float alpha, boolean animate) { }
 }
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
similarity index 61%
rename from src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
index 80a89e3..56e3260 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/WallpaperColorInfo.java
@@ -1,12 +1,28 @@
-package com.android.launcher3.dynamicui;
+/*
+ * Copyright (C) 2018 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.uioverrides;
 
 import android.content.Context;
 import android.graphics.Color;
-import android.support.v4.graphics.ColorUtils;
 import android.util.Pair;
 
-import com.android.launcher3.compat.WallpaperColorsCompat;
-import com.android.launcher3.compat.WallpaperManagerCompat;
+import com.android.launcher3.uioverrides.dynamicui.WallpaperColorsCompat;
+import com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompat;
+import com.android.launcher3.uioverrides.dynamicui.ColorExtractionAlgorithm;
 
 import java.util.ArrayList;
 
@@ -34,12 +50,13 @@
     private int mSecondaryColor;
     private boolean mIsDark;
     private boolean mSupportsDarkText;
-    private OnThemeChangeListener mOnThemeChangeListener;
+
+    private OnChangeListener[] mTempListeners;
 
     private WallpaperColorInfo(Context context) {
         mWallpaperManager = WallpaperManagerCompat.getInstance(context);
         mWallpaperManager.addOnColorsChangedListener(this);
-        mExtractionType = ColorExtractionAlgorithm.newInstance(context);
+        mExtractionType = new ColorExtractionAlgorithm();
         update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
     }
 
@@ -62,10 +79,8 @@
     @Override
     public void onColorsChanged(WallpaperColorsCompat colors, int which) {
         if ((which & FLAG_SYSTEM) != 0) {
-            boolean wasDarkTheme = mIsDark;
-            boolean didSupportDarkText = mSupportsDarkText;
             update(colors);
-            notifyChange(wasDarkTheme != mIsDark || didSupportDarkText != mSupportsDarkText);
+            notifyChange();
         }
     }
 
@@ -80,14 +95,10 @@
         }
         mSupportsDarkText = wallpaperColors != null
                 ? (wallpaperColors.getColorHints()
-                    & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) > 0 : false;
+                & WallpaperColorsCompat.HINT_SUPPORTS_DARK_TEXT) > 0 : false;
         mIsDark = wallpaperColors != null
                 ? (wallpaperColors.getColorHints()
-                    & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
-    }
-
-    public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) {
-        this.mOnThemeChangeListener = onThemeChangeListener;
+                & WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
     }
 
     public void addOnChangeListener(OnChangeListener listener) {
@@ -98,23 +109,19 @@
         mListeners.remove(listener);
     }
 
-    public void notifyChange(boolean themeChanged) {
-        if (themeChanged) {
-            if (mOnThemeChangeListener != null) {
-                mOnThemeChangeListener.onThemeChanged();
-            }
-        } else {
-            for (OnChangeListener listener : mListeners) {
-                listener.onExtractedColorsChanged(this);
-            }
+    private void notifyChange() {
+        OnChangeListener[] copy =
+                mTempListeners != null && mTempListeners.length == mListeners.size() ?
+                        mTempListeners : new OnChangeListener[mListeners.size()];
+
+        // Create a new array to avoid concurrent modification when the activity destroys itself.
+        mTempListeners = mListeners.toArray(copy);
+        for (OnChangeListener listener : mTempListeners) {
+            listener.onExtractedColorsChanged(this);
         }
     }
 
     public interface OnChangeListener {
         void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
     }
-
-    public interface OnThemeChangeListener {
-        void onThemeChanged();
-    }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
similarity index 98%
rename from src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
index baedf90..21b324f 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionAlgorithm.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/ColorExtractionAlgorithm.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.dynamicui;
+package com.android.launcher3.uioverrides.dynamicui;
 
-import android.content.Context;
 import android.graphics.Color;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
@@ -25,9 +24,7 @@
 import android.util.Pair;
 import android.util.Range;
 
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.WallpaperColorsCompat;
 
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -38,11 +35,6 @@
  **/
 public class ColorExtractionAlgorithm {
 
-    public static ColorExtractionAlgorithm newInstance(Context context) {
-        return Utilities.getOverrideObject(ColorExtractionAlgorithm.class,
-                context.getApplicationContext(), R.string.color_extraction_impl_class);
-    }
-
     private static final String TAG = "Tonal";
 
     // Used for tonal palette fitting
diff --git a/src/com/android/launcher3/compat/WallpaperColorsCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java
similarity index 96%
rename from src/com/android/launcher3/compat/WallpaperColorsCompat.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java
index e25b9d9..d984a84 100644
--- a/src/com/android/launcher3/compat/WallpaperColorsCompat.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperColorsCompat.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.compat;
+package com.android.launcher3.uioverrides.dynamicui;
 
 /**
  * A compatibility layer around platform implementation of WallpaperColors
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompat.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
similarity index 94%
rename from src/com/android/launcher3/compat/WallpaperManagerCompat.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
index 00258c7..5c533ff 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompat.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompat.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.compat;
+package com.android.launcher3.uioverrides.dynamicui;
 
 import android.content.Context;
 import android.support.annotation.Nullable;
@@ -31,7 +31,7 @@
             if (sInstance == null) {
                 context = context.getApplicationContext();
 
-                if (Utilities.ATLEAST_OREO) {
+                if (Utilities.ATLEAST_OREO_MR1) {
                     try {
                         sInstance = new WallpaperManagerCompatVOMR1(context);
                     } catch (Throwable e) {
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
similarity index 98%
rename from src/com/android/launcher3/compat/WallpaperManagerCompatVL.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
index 299f090..4a8bbbd 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompatVL.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVL.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.compat;
+package com.android.launcher3.uioverrides.dynamicui;
 
 import static android.app.WallpaperManager.FLAG_SYSTEM;
 
@@ -58,7 +58,7 @@
     private static final String VERSION_PREFIX = "1,";
     private static final String KEY_COLORS = "wallpaper_parsed_colors";
     private static final String ACTION_EXTRACTION_COMPLETE =
-            "com.android.launcher3.compat.WallpaperManagerCompatVL.EXTRACTION_COMPLETE";
+            "com.android.launcher3.uioverrides.dynamicui.WallpaperManagerCompatVL.EXTRACTION_COMPLETE";
 
     private final ArrayList<OnColorsChangedListenerCompat> mListeners = new ArrayList<>();
 
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
similarity index 97%
rename from src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
rename to src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
index 524f266..4509e05 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/dynamicui/WallpaperManagerCompatVOMR1.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.compat;
+package com.android.launcher3.uioverrides.dynamicui;
 
 import android.annotation.TargetApi;
 import android.app.WallpaperColors;
@@ -26,7 +26,6 @@
 
 import java.lang.reflect.Method;
 
-
 @TargetApi(27)
 public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
 
diff --git a/tests/Android.mk b/tests/Android.mk
index e8797a7..8ca84f8 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -22,7 +22,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
 
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := 28
 LOCAL_MIN_SDK_VERSION := 21
 
 LOCAL_PACKAGE_NAME := Launcher3Tests
@@ -30,3 +30,16 @@
 LOCAL_INSTRUMENTATION_FOR := Launcher3
 
 include $(BUILD_PACKAGE)
+
+#
+# Build rule for Tapl library.
+#
+include $(CLEAR_VARS)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator
+
+LOCAL_SRC_FILES := $(call all-java-files-under, tapl)
+
+LOCAL_SDK_VERSION := current
+LOCAL_MODULE := ub-launcher-tapl
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 0a29147..89ca7f3 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -18,8 +18,6 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3.tests">
 
-    <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"/>
-
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
 
@@ -34,6 +32,16 @@
         </receiver>
 
         <receiver
+            android:name="com.android.launcher3.testcomponent.AppWdigetHidden"
+            android:label="Hidden widget">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.appwidget.provider"
+                android:resource="@xml/appwidget_hidden" />
+        </receiver>
+
+        <receiver
             android:name="com.android.launcher3.testcomponent.AppWidgetWithConfig"
             android:label="With Config">
             <intent-filter>
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 43030ae..ec89f9c 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -18,8 +18,8 @@
     xmlns:tools="http://schemas.android.com/tools"
     package="com.android.launcher3.tests">
 
-    <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"/>
-    <uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>
+    <uses-sdk android:targetSdkVersion="25" android:minSdkVersion="21"
+              tools:overrideLibrary="android.support.test.uiautomator.v18"/>
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/tests/res/xml/appwidget_hidden.xml b/tests/res/xml/appwidget_hidden.xml
new file mode 100644
index 0000000..6f0e006
--- /dev/null
+++ b/tests/res/xml/appwidget_hidden.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<appwidget-provider
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="180dp"
+    android:minHeight="110dp"
+    android:updatePeriodMillis="86400000"
+    android:initialLayout="@layout/test_layout_appwidget_blue"
+    android:resizeMode="horizontal|vertical"
+    android:widgetFeatures="hide_from_picker"
+    android:widgetCategory="home_screen">
+</appwidget-provider>
\ No newline at end of file
diff --git a/tests/res/xml/appwidget_with_config.xml b/tests/res/xml/appwidget_with_config.xml
index 3e96c6f..8403689 100644
--- a/tests/res/xml/appwidget_with_config.xml
+++ b/tests/res/xml/appwidget_with_config.xml
@@ -7,5 +7,6 @@
     android:initialLayout="@layout/test_layout_appwidget_blue"
     android:configure="com.android.launcher3.testcomponent.WidgetConfigActivity"
     android:resizeMode="horizontal|vertical"
+    android:widgetFeatures="reconfigurable"
     android:widgetCategory="home_screen">
 </appwidget-provider>
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index cf90afd..b217847 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -1,5 +1,11 @@
 package com.android.launcher3.model;
 
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -24,8 +30,8 @@
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherProvider;
 import com.android.launcher3.graphics.BitmapInfo;
 import com.android.launcher3.util.ComponentKey;
@@ -43,12 +49,6 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 /**
  * Base class for writing tests for Model update tasks.
  */
@@ -82,7 +82,7 @@
         modelWriter = mock(ModelWriter.class);
 
         when(appState.getModel()).thenReturn(model);
-        when(model.getWriter(anyBoolean())).thenReturn(modelWriter);
+        when(model.getWriter(anyBoolean(), anyBoolean())).thenReturn(modelWriter);
         when(model.getCallback()).thenReturn(callbacks);
 
         myUser = Process.myUserHandle();
diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java b/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java
new file mode 100644
index 0000000..83492bf
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 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.testcomponent;
+
+import android.appwidget.AppWidgetProvider;
+
+/**
+ * A simple app widget without any configuration screen and is hidden in picker.
+ */
+public class AppWidgetHidden extends AppWidgetProvider { }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 1be33d2..f16f514 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -33,6 +33,7 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
+import android.util.Log;
 import android.view.MotionEvent;
 
 import com.android.launcher3.LauncherAppState;
@@ -40,13 +41,11 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.testcomponent.AppWidgetNoConfig;
 import com.android.launcher3.testcomponent.AppWidgetWithConfig;
-import com.android.launcher3.util.ManagedProfileHeuristic;
 
 import org.junit.Before;
 
@@ -66,7 +65,9 @@
     public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
     public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
 
+    public static final long SHORT_UI_TIMEOUT= 300;
     public static final long DEFAULT_UI_TIMEOUT = 3000;
+    public static final long LARGE_UI_TIMEOUT = 10000;
     public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
 
     protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
@@ -74,6 +75,8 @@
     protected Context mTargetContext;
     protected String mTargetPackage;
 
+    private static final String TAG = "AbstractLauncherUiTest";
+
     @Before
     public void setUp() throws Exception {
         mDevice = UiDevice.getInstance(getInstrumentation());
@@ -82,11 +85,6 @@
     }
 
     protected void lockRotation(boolean naturalOrientation) throws RemoteException {
-        Utilities.getPrefs(mTargetContext)
-                .edit()
-                .putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, !naturalOrientation)
-                .commit();
-
         if (naturalOrientation) {
             mDevice.setOrientationNatural();
         } else {
@@ -104,8 +102,13 @@
     protected UiObject2 openAllApps() {
         mDevice.waitForIdle();
         if (FeatureFlags.NO_ALL_APPS_ICON) {
-            // clicking on the page indicator brings up all apps tray on non tablets.
-            findViewById(R.id.page_indicator).click();
+            UiObject2 hotseat = mDevice.wait(
+                    Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
+            Point start = hotseat.getVisibleCenter();
+            int endY = (int) (mDevice.getDisplayHeight() * 0.1f);
+            // 100 px/step
+            mDevice.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
+
         } else {
             mDevice.wait(Until.findObject(
                     By.desc(mTargetContext.getString(R.string.all_apps_button_label))),
@@ -120,8 +123,7 @@
     protected UiObject2 openWidgetsTray() {
         mDevice.pressMenu(); // Enter overview mode.
         mDevice.wait(Until.findObject(
-                By.text(mTargetContext.getString(R.string.widget_button_text)
-                        .toUpperCase(Locale.getDefault()))), DEFAULT_UI_TIMEOUT).click();
+                By.text(mTargetContext.getString(R.string.widget_button_text))), DEFAULT_UI_TIMEOUT).click();
         return findViewById(R.id.widgets_list_view);
     }
 
@@ -131,6 +133,8 @@
      */
     protected UiObject2 scrollAndFind(UiObject2 container, BySelector condition) {
         do {
+            // findObject can only execute after spring settles.
+            mDevice.wait(Until.findObject(condition), SHORT_UI_TIMEOUT);
             UiObject2 widget = container.findObject(condition);
             if (widget != null) {
                 return widget;
@@ -141,6 +145,7 @@
 
     /**
      * Drags an icon to the center of homescreen.
+     * @param icon  object that is either app icon or shortcut icon
      */
     protected void dragToWorkspace(UiObject2 icon, boolean expectedToShowShortcuts) {
         Point center = icon.getVisibleCenter();
@@ -221,7 +226,6 @@
             mMainThreadExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
-                    ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
                     LauncherAppState.getInstance(mTargetContext).getModel().forceReload();
                 }
             });
@@ -252,6 +256,7 @@
             public LauncherAppWidgetProviderInfo call() throws Exception {
                 ComponentName cn = new ComponentName(getInstrumentation().getContext(),
                         hasConfigureScreen ? AppWidgetWithConfig.class : AppWidgetNoConfig.class);
+                Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
                 return AppWidgetManagerCompat.getInstance(mTargetContext)
                         .findProvider(cn, Process.myUserHandle());
             }
@@ -273,7 +278,13 @@
 
     protected LauncherActivityInfo getSettingsApp() {
         return LauncherAppsCompat.getInstance(mTargetContext)
-                .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
+                .getActivityList("com.android.settings",
+                        Process.myUserHandle()).get(0);
+    }
+
+    protected LauncherActivityInfo getChromeApp() {
+        return LauncherAppsCompat.getInstance(mTargetContext)
+                .getActivityList("com.android.chrome", Process.myUserHandle()).get(0);
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
index 46343a3..b95a850 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
@@ -41,15 +41,15 @@
     private void performTest() throws Exception {
         mActivityMonitor.startLauncher();
 
-        LauncherActivityInfo settingsApp = getSettingsApp();
+        LauncherActivityInfo testApp = getChromeApp();
 
         // Open all apps and wait for load complete
         final UiObject2 appsContainer = openAllApps();
         assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
 
-        // Open settings app and verify app launched
-        scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString())).click();
+        // Open app and verify app launched
+        scrollAndFind(appsContainer, By.text(testApp.getLabel().toString())).click();
         assertTrue(mDevice.wait(Until.hasObject(By.pkg(
-                settingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+                testApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index a40ad7f..69f6c87 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -46,14 +46,15 @@
 
     private void performTest() throws Exception {
         mActivityMonitor.startLauncher();
-        LauncherActivityInfo settingsApp = getSettingsApp();
+        LauncherActivityInfo testApp = getSettingsApp();
 
         // Open all apps and wait for load complete
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
+                DEFAULT_UI_TIMEOUT));
 
         // Find settings app and verify shortcuts appear when long pressed
-        UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
+        UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
         // Press icon center until shortcuts appear
         Point iconCenter = icon.getVisibleCenter();
         sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
@@ -63,11 +64,13 @@
 
         // Verify that launching a shortcut opens a page with the same text
         assertTrue(deepShortcutsContainer.getChildCount() > 0);
-        UiObject2 shortcut = deepShortcutsContainer.getChildren().get(0)
+
+        // Pick second children as it starts showing shortcuts.
+        UiObject2 shortcut = deepShortcutsContainer.getChildren().get(1)
                 .findObject(getSelectorForId(R.id.bubble_text));
         shortcut.click();
         assertTrue(mDevice.wait(Until.hasObject(By.pkg(
-                settingsApp.getComponentName().getPackageName())
+                testApp.getComponentName().getPackageName())
                 .text(shortcut.getText())), DEFAULT_UI_TIMEOUT));
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index 434311d..fad06a6 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -48,14 +48,15 @@
         clearHomescreen();
         mActivityMonitor.startLauncher();
 
-        LauncherActivityInfo settingsApp  = getSettingsApp();
+        LauncherActivityInfo testApp  = getSettingsApp();
 
         // Open all apps and wait for load complete.
         final UiObject2 appsContainer = openAllApps();
-        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
+                DEFAULT_UI_TIMEOUT));
 
         // Find the app and long press it to show shortcuts.
-        UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
+        UiObject2 icon = scrollAndFind(appsContainer, By.text(testApp.getLabel().toString()));
         // Press icon center until shortcuts appear
         Point iconCenter = icon.getVisibleCenter();
         sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
@@ -65,7 +66,7 @@
 
         // Drag the first shortcut to the home screen.
         assertTrue(deepShortcutsContainer.getChildCount() > 0);
-        UiObject2 shortcut = deepShortcutsContainer.getChildren().get(0)
+        UiObject2 shortcut = deepShortcutsContainer.getChildren().get(1)
                 .findObject(getSelectorForId(R.id.bubble_text));
         String shortcutName = shortcut.getText();
         dragToWorkspace(shortcut, false);
@@ -74,7 +75,7 @@
         // (the app opens and has the same text as the shortcut).
         mDevice.findObject(By.text(shortcutName)).click();
         assertTrue(mDevice.wait(Until.hasObject(By.pkg(
-                settingsApp.getComponentName().getPackageName())
+                testApp.getComponentName().getPackageName())
                 .text(shortcutName)), DEFAULT_UI_TIMEOUT));
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
new file mode 100644
index 0000000..6244434
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018, 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.ui;
+
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class WorkTabTest extends AbstractLauncherUiTest {
+    @Rule
+    public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+    @Rule
+    public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+
+    private int mProfileUserId;
+
+    @Before
+    public void createWorkProfile() throws Exception {
+        String output =
+                mDevice.executeShellCommand(
+                        "pm create-user --profileOf 0 --managed TestProfile");
+        assertTrue("Failed to create work profile", output.startsWith("Success"));
+
+        String[] tokens = output.split("\\s+");
+        mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
+
+        mDevice.executeShellCommand("am start-user " + mProfileUserId);
+    }
+
+    @After
+    public void removeWorkProfile() throws Exception {
+        mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
+    }
+
+    @Test
+    public void workTabExists() {
+        mActivityMonitor.startLauncher();
+
+        // Open all apps and wait for load complete
+        final UiObject2 appsContainer = openAllApps();
+        assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2),
+                LARGE_UI_TIMEOUT));
+
+        /*
+        assertTrue("Personal tab is missing",
+                mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_personal)),
+                        LARGE_UI_TIMEOUT));
+        assertTrue("Work tab is missing",
+                mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_work)), LARGE_UI_TIMEOUT));
+        */
+    }
+}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 32f90a6..b557119 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -49,6 +49,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -122,7 +123,7 @@
         setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
     }
 
-    @Test
+    @Test @Ignore
     public void testUnboundWidget_removed() throws Exception {
         LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
         LauncherAppWidgetInfo item = createWidgetInfo(info, false);
@@ -177,7 +178,7 @@
                         LauncherSettings.Favorites.APPWIDGET_ID))));
     }
 
-    @Test
+    @Test @Ignore
     public void testPendingWidget_notRestored_removed() throws Exception {
         LauncherAppWidgetInfo item = getInvalidWidgetInfo();
         item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index bd21315..dcb564a 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.widget.WidgetCell;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -79,6 +80,9 @@
     }
 
     @Test
+    public void testEmpty() throws Throwable { /* needed while the broken tests are being fixed */ }
+
+    @Test @Ignore
     public void testPinWidgetNoConfig() throws Throwable {
         runTest("pinWidgetNoConfig", true, new ItemOperator() {
             @Override
@@ -91,7 +95,7 @@
         });
     }
 
-    @Test
+    @Test @Ignore
     public void testPinWidgetNoConfig_customPreview() throws Throwable {
         // Command to set custom preview
         Intent command =  RequestPinItemActivity.getCommandIntent(
@@ -109,7 +113,7 @@
         }, command);
     }
 
-    @Test
+    @Test @Ignore
     public void testPinWidgetWithConfig() throws Throwable {
         runTest("pinWidgetWithConfig", true, new ItemOperator() {
             @Override
@@ -122,7 +126,7 @@
         });
     }
 
-    @Test
+    @Test @Ignore
     public void testPinShortcut() throws Throwable {
         // Command to set the shortcut id
         Intent command = RequestPinItemActivity.getCommandIntent(
diff --git a/tests/src/com/android/launcher3/util/FocusLogicTest.java b/tests/src/com/android/launcher3/util/FocusLogicTest.java
deleted file mode 100644
index 691d9bc..0000000
--- a/tests/src/com/android/launcher3/util/FocusLogicTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2015 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.util;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.KeyEvent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * Tests the {@link FocusLogic} class that handles key event based focus handling.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class FocusLogicTest {
-
-    @Test
-    public void testShouldConsume() {
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_LEFT));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_RIGHT));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_UP));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_DOWN));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_MOVE_HOME));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_MOVE_END));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_UP));
-         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_DOWN));
-    }
-
-    @Test
-    public void testCreateSparseMatrix() {
-         // Either, 1) create a helper method to generate/instantiate all possible cell layout that
-         // may get created in real world to test this method. OR 2) Move all the matrix
-         // management routine to celllayout and write tests for them.
-    }
-
-    @Test
-    public void testMoveFromBottomRightToBottomLeft() {
-        int[][] map = transpose(new int[][] {
-                {-1, 0, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {100, 1, -1, -1, -1, -1},
-        });
-        int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 100, 1, 2, false);
-        assertEquals(1, i);
-    }
-
-    @Test
-    public void testMoveFromBottomRightToTopLeft() {
-        int[][] map = transpose(new int[][] {
-                {-1, 0, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1, -1},
-                {100, -1, -1, -1, -1, -1},
-        });
-        int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 100, 1, 2, false);
-        assertEquals(FocusLogic.NEXT_PAGE_FIRST_ITEM, i);
-    }
-
-    @Test
-    public void testMoveIntoHotseatWithEqualHotseatAndWorkspaceColumns() {
-        // Test going from an icon right above the All Apps button to the All Apps button.
-        int[][] map = transpose(new int[][] {
-                {-1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1},
-                {-1, -1,  0, -1, -1},
-                { 2,  3,  1,  4,  5},
-        });
-        int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test going from an icon above and to the right of the All Apps
-        // button to an icon to the right of the All Apps button.
-        map = transpose(new int[][] {
-                {-1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1},
-                {-1, -1, -1, -1, -1},
-                {-1, -1, -1,  0, -1},
-                { 2,  3,  1,  4,  5},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(4, i);
-    }
-
-    @Test
-    public void testMoveIntoHotseatWithExtraColumnForAllApps() {
-        // Test going from an icon above and to the left
-        // of the All Apps button to the All Apps button.
-        int[][] map = transpose(new int[][] {
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1,  0,-11, -1, -1, -1},
-                {-1, -1, -1,  1,  1, -1, -1},
-        });
-        int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test going from an icon above and to the right
-        // of the All Apps button to the All Apps button.
-        map = transpose(new int[][] {
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11,  0, -1, -1},
-                {-1, -1, -1,  1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test going from the All Apps button to an icon
-        // above and to the right of the All Apps button.
-        map = transpose(new int[][] {
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11,  0, -1, -1},
-                {-1, -1, -1,  1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_UP, map, 1, 1, 1, true);
-        assertEquals(0, i);
-        // Test going from an icon above and to the left of the
-        // All Apps button in landscape to the All Apps button.
-        map = transpose(new int[][] {
-                { -1, -1, -1, -1, -1},
-                { -1, -1, -1,  0, -1},
-                {-11,-11,-11,-11,  1},
-                { -1, -1, -1, -1, -1},
-                { -1, -1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test going from the All Apps button in landscape to
-        // an icon above and to the left of the All Apps button.
-        map = transpose(new int[][] {
-                { -1, -1, -1, -1, -1},
-                { -1, -1, -1,  0, -1},
-                {-11,-11,-11,-11,  1},
-                { -1, -1, -1, -1, -1},
-                { -1, -1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT, map, 1, 1, 1, true);
-        assertEquals(0, i);
-        // Test that going to the hotseat always goes to the same row as the original icon.
-        map = transpose(new int[][]{
-                { 0,  1,  2,-11,  3,  4,  5},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                {-1, -1, -1,-11, -1, -1, -1},
-                { 7,  8,  9,  6, 10, 11, 12},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(7, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 1, 1, 1, true);
-        assertEquals(8, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 2, 1, 1, true);
-        assertEquals(9, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 3, 1, 1, true);
-        assertEquals(10, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 4, 1, 1, true);
-        assertEquals(11, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 5, 1, 1, true);
-        assertEquals(12, i);
-    }
-
-    @Test
-    public void testCrossingAllAppsColumn() {
-        // Test crossing from left to right in portrait.
-        int[][] map = transpose(new int[][] {
-                {-1, -1,-11, -1, -1},
-                {-1,  0,-11, -1, -1},
-                {-1, -1,-11,  1, -1},
-                {-1, -1,-11, -1, -1},
-                {-1, -1,  2, -1, -1},
-        });
-        int i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test crossing from right to left in portrait.
-        map = transpose(new int[][] {
-                {-1, -1,-11, -1, -1},
-                {-1, -1,-11,  0, -1},
-                {-1,  1,-11, -1, -1},
-                {-1, -1,-11, -1, -1},
-                {-1, -1,  2, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test crossing from left to right in landscape.
-        map = transpose(new int[][] {
-                { -1, -1, -1, -1, -1},
-                { -1, -1, -1,  0, -1},
-                {-11,-11,-11,-11,  2},
-                { -1,  1, -1, -1, -1},
-                { -1, -1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test crossing from right to left in landscape.
-        map = transpose(new int[][] {
-                { -1, -1, -1, -1, -1},
-                { -1,  0, -1, -1, -1},
-                {-11,-11,-11,-11,  2},
-                { -1, -1,  1, -1, -1},
-                { -1, -1, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 0, 1, 1, true);
-        assertEquals(1, i);
-        // Test NOT crossing it, if the All Apps button is the only suitable candidate.
-        map = transpose(new int[][]{
-                {-1, 0, -1, -1, -1},
-                {-1, 1, -1, -1, -1},
-                {-11, -11, -11, -11, 4},
-                {-1, 2, -1, -1, -1},
-                {-1, 3, -1, -1, -1},
-        });
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 1, 1, 1, true);
-        assertEquals(4, i);
-        i = FocusLogic.handleKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT, map, 2, 1, 1, true);
-        assertEquals(4, i);
-    }
-
-    /** Transposes the matrix so that we can write it in human-readable format in the tests. */
-    private int[][] transpose(int[][] m) {
-        int[][] t = new int[m[0].length][m.length];
-        for (int i = 0; i < m.length; i++) {
-            for (int j = 0; j < m[0].length; j++) {
-                t[j][i] = m[i][j];
-            }
-        }
-        return t;
-    }
-}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
new file mode 100644
index 0000000..d849e2d
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static org.junit.Assert.assertTrue;
+
+import android.support.annotation.NonNull;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+
+/**
+ * Operations on AllApps opened from Home. Also a parent for All Apps opened from Overview.
+ */
+public class AllApps extends LauncherInstrumentation.VisibleContainer {
+    private static final int MAX_SCROLL_ATTEMPTS = 40;
+    private static final int MIN_INTERACT_SIZE = 100;
+    private static final int FLING_SPEED = 12000;
+
+    private final int mHeight;
+
+    AllApps(LauncherInstrumentation launcher) {
+        super(launcher);
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        mHeight = allAppsContainer.getVisibleBounds().height();
+    }
+
+    @Override
+    protected LauncherInstrumentation.ContainerType getContainerType() {
+        return LauncherInstrumentation.ContainerType.ALL_APPS;
+    }
+
+    /**
+     * Finds an icon. Fails if the icon doesn't exist. Scrolls the app list when needed to make
+     * sure the icon is visible.
+     *
+     * @param appName name of the app.
+     * @return The app.
+     */
+    @NonNull
+    public AppIcon getAppIcon(String appName) {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        final BySelector appIconSelector = AppIcon.getAppIconSelector(appName);
+        if (!allAppsContainer.hasObject(appIconSelector)) {
+            scrollBackToBeginning();
+            int attempts = 0;
+            while (!allAppsContainer.hasObject(appIconSelector) &&
+                    allAppsContainer.scroll(Direction.DOWN, 0.8f)) {
+                assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+                        ++attempts <= MAX_SCROLL_ATTEMPTS);
+                verifyActiveContainer();
+            }
+        }
+        verifyActiveContainer();
+
+        final UiObject2 appIcon = mLauncher.getObjectInContainer(allAppsContainer, appIconSelector);
+        ensureIconVisible(appIcon, allAppsContainer);
+        return new AppIcon(mLauncher, appIcon);
+    }
+
+    protected int getBottomMarginForSwipeUp() {
+        return 5;
+    }
+
+    private void scrollBackToBeginning() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+
+        int attempts = 0;
+        allAppsContainer.setGestureMargins(5, 600, 5, getBottomMarginForSwipeUp());
+
+        while (allAppsContainer.scroll(Direction.UP, 0.5f)) {
+            mLauncher.waitForIdle();
+            verifyActiveContainer();
+
+            assertTrue("Exceeded max scroll attempts: " + MAX_SCROLL_ATTEMPTS,
+                    ++attempts <= MAX_SCROLL_ATTEMPTS);
+        }
+
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    private void ensureIconVisible(UiObject2 appIcon, UiObject2 allAppsContainer) {
+        final int appHeight = appIcon.getVisibleBounds().height();
+        if (appHeight < MIN_INTERACT_SIZE) {
+            // Try to figure out how much percentage of the container needs to be scrolled in order
+            // to reveal the app icon to have the MIN_INTERACT_SIZE
+            final float pct = Math.max(((float) (MIN_INTERACT_SIZE - appHeight)) / mHeight, 0.2f);
+            allAppsContainer.scroll(Direction.DOWN, pct);
+            mLauncher.waitForIdle();
+            verifyActiveContainer();
+        }
+    }
+
+    /**
+     * Flings forward (down) and waits the fling's end.
+     */
+    public void flingForward() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        // Start the gesture in the center to avoid starting at elements near the top.
+        allAppsContainer.setGestureMargins(0, 0, 0, mHeight / 2);
+        allAppsContainer.fling(Direction.DOWN, FLING_SPEED);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings backward (up) and waits the fling's end.
+     */
+    public void flingBackward() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        // Start the gesture in the center, for symmetry with forward.
+        allAppsContainer.setGestureMargins(0, mHeight / 2, 0, 0);
+        allAppsContainer.fling(Direction.UP, FLING_SPEED);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Gets the UI object for AllApps.
+     * Used by NexusLauncherStrategy.openAllApps(). No one else should use it.
+     *
+     * @return container object.
+     */
+    @Deprecated
+    @NonNull
+    public UiObject2 getObjectDeprecated() {
+        return verifyActiveContainer();
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
new file mode 100644
index 0000000..bc0dfc6
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AllAppsFromOverview.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import android.graphics.Point;
+import android.support.annotation.NonNull;
+import android.support.test.uiautomator.UiObject2;
+
+/**
+ * Operations on AllApps opened from Overview.
+ */
+public final class AllAppsFromOverview extends AllApps {
+
+    AllAppsFromOverview(LauncherInstrumentation launcher) {
+        super(launcher);
+        verifyActiveContainer();
+    }
+
+    @Override
+    protected int getBottomMarginForSwipeUp() {
+        return 600;
+    }
+
+    /**
+     * Swipes down to switch back to Overview whence we came from.
+     *
+     * @return the overview panel.
+     */
+    @NonNull
+    public Overview switchBackToOverview() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        // Swipe from the search box to the bottom.
+        final UiObject2 qsb = mLauncher.waitForObjectInContainer(
+                allAppsContainer, "search_container_all_apps");
+        final Point start = qsb.getVisibleCenter();
+        final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.6);
+        mLauncher.swipe(start.x, start.y, start.x, endY);
+
+        return new Overview(mLauncher);
+    }
+
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
new file mode 100644
index 0000000..721f7a8
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.widget.TextView;
+
+/**
+ * App icon, whether in all apps or in workspace/
+ */
+public final class AppIcon {
+    private final LauncherInstrumentation mLauncher;
+    private final UiObject2 mIcon;
+
+    AppIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+        mLauncher = launcher;
+        mIcon = icon;
+    }
+
+    static BySelector getAppIconSelector(String appName) {
+        return By.clazz(TextView.class).text(appName).pkg(LauncherInstrumentation.LAUNCHER_PKG);
+    }
+
+    /**
+     * Clicks the icon to launch its app.
+     */
+    public Background launch() {
+        assertTrue("Launching an app didn't open a new window: " + mIcon.getText(),
+                mIcon.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+        return new Background(mLauncher);
+    }
+
+    UiObject2 getIcon() {
+        return mIcon;
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
new file mode 100644
index 0000000..1aef979
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+/**
+ * Operations on a state when Launcher is inactive because some other app is active.
+ */
+public final class Background extends Home {
+
+    Background(LauncherInstrumentation launcher) {
+        super(launcher);
+    }
+
+    @Override
+    protected LauncherInstrumentation.ContainerType getContainerType() {
+        return LauncherInstrumentation.ContainerType.BACKGROUND;
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Home.java b/tests/tapl/com/android/launcher3/tapl/Home.java
new file mode 100644
index 0000000..436e5ff
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Home.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import android.support.annotation.NonNull;
+import android.support.test.uiautomator.UiObject2;
+
+/**
+ * Operations on the home screen.
+ *
+ * Launcher can be invoked both when its activity is in the foreground and when it is in the
+ * background. This class is a parent of the two classes {@link Background} and {@link Workspace}
+ * that essentially represents these two activity states. Any gestures (e.g., switchToOverview) that
+ * can be performed in both of these states can be defined here.
+ */
+public abstract class Home extends LauncherInstrumentation.VisibleContainer {
+
+    protected Home(LauncherInstrumentation launcher) {
+        super(launcher);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Swipes up or presses the square button to switch to Overview.
+     *
+     * @return the Overview panel object.
+     */
+    @NonNull
+    public Overview switchToOverview() {
+        verifyActiveContainer();
+        if (mLauncher.isSwipeUpEnabled()) {
+            final int height = mLauncher.getDevice().getDisplayHeight();
+            final UiObject2 navBar = mLauncher.getSystemUiObject("navigation_bar_frame");
+
+            mLauncher.swipe(
+                    navBar.getVisibleBounds().centerX(), navBar.getVisibleBounds().centerY(),
+                    navBar.getVisibleBounds().centerX(), height - 300
+            );
+        } else {
+            mLauncher.getSystemUiObject("recent_apps").click();
+        }
+
+        return new Overview(mLauncher);
+    }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
new file mode 100644
index 0000000..fc32fed
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+import org.junit.Assert;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * The main tapl object. The only object that can be explicitly constructed by the using code. It
+ * produces all other objects.
+ */
+public final class LauncherInstrumentation {
+
+    // Types for launcher containers that the user is interacting with. "Background" is a
+    // pseudo-container corresponding to inactive launcher covered by another app.
+    enum ContainerType {
+        WORKSPACE, ALL_APPS, OVERVIEW, WIDGETS, BACKGROUND
+    }
+
+    // Base class for launcher containers.
+    static abstract class VisibleContainer {
+        protected final LauncherInstrumentation mLauncher;
+
+        protected VisibleContainer(LauncherInstrumentation launcher) {
+            mLauncher = launcher;
+            launcher.setActiveContainer(this);
+        }
+
+        protected abstract ContainerType getContainerType();
+
+        /**
+         * Asserts that the launcher is in the mode matching 'this' object.
+         *
+         * @return UI object for the container.
+         */
+        final UiObject2 verifyActiveContainer() {
+            assertTrue("Attempt to use a stale container", this == sActiveContainer.get());
+            return mLauncher.verifyContainerType(getContainerType());
+        }
+    }
+
+    private static final String WORKSPACE_RES_ID = "workspace";
+    private static final String APPS_RES_ID = "apps_view";
+    private static final String OVERVIEW_RES_ID = "overview_panel";
+    private static final String WIDGETS_RES_ID = "widgets_list_view";
+    static final String LAUNCHER_PKG = "com.google.android.apps.nexuslauncher";
+    static final int WAIT_TIME_MS = 10000;
+    private static final String SWIPE_UP_SETTING_AVAILABLE_RES_NAME =
+            "config_swipe_up_gesture_setting_available";
+    private static final String SWIPE_UP_ENABLED_DEFAULT_RES_NAME =
+            "config_swipe_up_gesture_default";
+    private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+
+    private static WeakReference<VisibleContainer> sActiveContainer = new WeakReference<>(null);
+
+    private final UiDevice mDevice;
+    private final boolean mSwipeUpEnabled;
+
+    /**
+     * Constructs the root of TAPL hierarchy. You get all other objects from it.
+     */
+    public LauncherInstrumentation(UiDevice device) {
+        mDevice = device;
+        final boolean swipeUpEnabledDefault =
+                !getSystemBooleanRes(SWIPE_UP_SETTING_AVAILABLE_RES_NAME) ||
+                        getSystemBooleanRes(SWIPE_UP_ENABLED_DEFAULT_RES_NAME);
+        mSwipeUpEnabled = Settings.Secure.getInt(
+                InstrumentationRegistry.getTargetContext().getContentResolver(),
+                "swipe_up_to_switch_apps_enabled",
+                swipeUpEnabledDefault ? 1 : 0) == 1;
+        assertTrue("Device must run in a test harness", ActivityManager.isRunningInTestHarness());
+    }
+
+    private boolean getSystemBooleanRes(String resName) {
+        final Resources res = Resources.getSystem();
+        final int resId = res.getIdentifier(resName, "bool", "android");
+        assertTrue("Resource not found: " + resName, resId != 0);
+        return res.getBoolean(resId);
+    }
+
+    void setActiveContainer(VisibleContainer container) {
+        sActiveContainer = new WeakReference<>(container);
+    }
+
+    boolean isSwipeUpEnabled() {
+        return mSwipeUpEnabled;
+    }
+
+    private UiObject2 verifyContainerType(ContainerType containerType) {
+        switch (containerType) {
+            case WORKSPACE: {
+                waitUntilGone(APPS_RES_ID);
+                waitUntilGone(OVERVIEW_RES_ID);
+                waitUntilGone(WIDGETS_RES_ID);
+                return waitForLauncherObject(WORKSPACE_RES_ID);
+            }
+            case WIDGETS: {
+                waitUntilGone(WORKSPACE_RES_ID);
+                waitUntilGone(APPS_RES_ID);
+                waitUntilGone(OVERVIEW_RES_ID);
+                return waitForLauncherObject(WIDGETS_RES_ID);
+            }
+            case ALL_APPS: {
+                waitUntilGone(OVERVIEW_RES_ID);
+                waitUntilGone(WIDGETS_RES_ID);
+                return waitForLauncherObject(APPS_RES_ID);
+            }
+            case OVERVIEW: {
+                waitForLauncherObject(APPS_RES_ID);
+                waitUntilGone(WIDGETS_RES_ID);
+                return waitForLauncherObject(OVERVIEW_RES_ID);
+            }
+            case BACKGROUND: {
+                waitUntilGone(WORKSPACE_RES_ID);
+                waitUntilGone(APPS_RES_ID);
+                waitUntilGone(OVERVIEW_RES_ID);
+                waitUntilGone(WIDGETS_RES_ID);
+                return null;
+            }
+            default:
+                fail("Invalid state: " + containerType);
+                return null;
+        }
+    }
+
+    private void executeAndWaitForEvent(Runnable command,
+            UiAutomation.AccessibilityEventFilter eventFilter, String message) {
+        try {
+            assertNotNull("executeAndWaitForEvent returned null (this can't happen)",
+                    InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                            .executeAndWaitForEvent(
+                                    command, eventFilter, WAIT_TIME_MS));
+        } catch (TimeoutException e) {
+            fail(message);
+        }
+    }
+
+    /**
+     * Presses nav bar home button.
+     *
+     * @return the Workspace object.
+     */
+    public Workspace pressHome() {
+        // Click home, then wait for any accessibility event, then wait until accessibility events
+        // stop.
+        // We need waiting for any accessibility event generated after pressing Home because
+        // otherwise waitForIdle may return immediately in case when there was a big enough pause in
+        // accessibility events prior to pressing Home.
+        executeAndWaitForEvent(
+                () -> getSystemUiObject("home").click(),
+                event -> true,
+                "Pressing Home didn't produce any events");
+        mDevice.waitForIdle();
+        return getWorkspace();
+    }
+
+    /**
+     * Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the
+     * launcher is not in that state.
+     *
+     * @return Workspace object.
+     */
+    @NonNull
+    public Workspace getWorkspace() {
+        return new Workspace(this);
+    }
+
+    /**
+     * Gets the Workspace object if the current state is "background home", i.e. some other app is
+     * active. Fails if the launcher is not in that state.
+     *
+     * @return Background object.
+     */
+    @NonNull
+    public Background getBackground() {
+        return new Background(this);
+    }
+
+    /**
+     * Gets the Widgets object if the current state is showing all widgets. Fails if the launcher is
+     * not in that state.
+     *
+     * @return Widgets object.
+     */
+    @NonNull
+    public Widgets getAllWidgets() {
+        return new Widgets(this);
+    }
+
+    /**
+     * Gets the Overview object if the current state is showing the overview panel. Fails if the
+     * launcher is not in that state.
+     *
+     * @return Overview object.
+     */
+    @NonNull
+    public Overview getOverview() {
+        return new Overview(this);
+    }
+
+    /**
+     * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+     * from workspace. Fails if the launcher is not in that state. Please don't call this method if
+     * App Apps was opened by swiping up from Overview, as it won't fail and will return an
+     * incorrect object.
+     *
+     * @return All Aps object.
+     */
+    @NonNull
+    public AllApps getAllApps() {
+        return new AllApps(this);
+    }
+
+    /**
+     * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+     * from overview. Fails if the launcher is not in that state. Please don't call this method if
+     * App Apps was opened by swiping up from home, as it won't fail and will return an
+     * incorrect object.
+     *
+     * @return All Aps object.
+     */
+    @NonNull
+    public AllAppsFromOverview getAllAppsFromOverview() {
+        return new AllAppsFromOverview(this);
+    }
+
+    /**
+     * Gets the All Apps object if the current state is showing the all apps panel opened by swiping
+     * from workspace. Returns null if launcher is not in that state. Please don't call this method
+     * if App Apps was opened by swiping up from Overview, as it won't fail and will return an
+     * incorrect object.
+     *
+     * @return All Aps object or null.
+     */
+    @Nullable
+    public AllApps tryGetAllApps() {
+        return tryGetLauncherObject(APPS_RES_ID) != null ? getAllApps() : null;
+    }
+
+    private void waitUntilGone(String resId) {
+        assertTrue("Unexpected launcher object visible: " + resId,
+                mDevice.wait(Until.gone(getLauncherObjectSelector(resId)),
+                        WAIT_TIME_MS));
+    }
+
+    @NonNull
+    UiObject2 getSystemUiObject(String resId) {
+        final UiObject2 object = mDevice.findObject(By.res(SYSTEMUI_PACKAGE, resId));
+        assertNotNull("Can't find a systemui object with id: " + resId, object);
+        return object;
+    }
+
+    @NonNull
+    UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) {
+        final UiObject2 object = container.findObject(selector);
+        assertNotNull("Can't find an object with selector: " + selector, object);
+        return object;
+    }
+
+    @Nullable
+    private UiObject2 tryGetLauncherObject(String resName) {
+        return mDevice.findObject(getLauncherObjectSelector(resName));
+    }
+
+    @NonNull
+    UiObject2 waitForObjectInContainer(UiObject2 container, String resName) {
+        final UiObject2 object = container.wait(
+                Until.findObject(getLauncherObjectSelector(resName)),
+                WAIT_TIME_MS);
+        assertNotNull("Can't find a launcher object id: " + resName + " in container: " +
+                container.getResourceName(), object);
+        return object;
+    }
+
+    @NonNull
+    UiObject2 waitForLauncherObject(String resName) {
+        final UiObject2 object = mDevice.wait(Until.findObject(getLauncherObjectSelector(resName)),
+                WAIT_TIME_MS);
+        assertNotNull("Can't find a launcher object; id: " + resName, object);
+        return object;
+    }
+
+    static BySelector getLauncherObjectSelector(String resName) {
+        return By.res(LAUNCHER_PKG, resName);
+    }
+
+    @NonNull
+    UiDevice getDevice() {
+        return mDevice;
+    }
+
+    void swipe(int startX, int startY, int endX, int endY) {
+        executeAndWaitForEvent(
+                () -> mDevice.swipe(startX, startY, endX, endY, 60),
+                event -> "TAPL_WENT_TO_STATE".equals(event.getClassName()),
+                "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY
+                        + ", " + endX + ", " + endY);
+    }
+
+    void waitForIdle() {
+        mDevice.waitForIdle();
+    }
+}
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/Overview.java b/tests/tapl/com/android/launcher3/tapl/Overview.java
new file mode 100644
index 0000000..3d504c4
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Overview.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static org.junit.Assert.assertNotEquals;
+
+import android.graphics.Point;
+import android.support.annotation.NonNull;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Overview pane.
+ */
+public final class Overview extends LauncherInstrumentation.VisibleContainer {
+    private static final int DEFAULT_FLING_SPEED = 15000;
+
+    Overview(LauncherInstrumentation launcher) {
+        super(launcher);
+        verifyActiveContainer();
+    }
+
+    @Override
+    protected LauncherInstrumentation.ContainerType getContainerType() {
+        return LauncherInstrumentation.ContainerType.OVERVIEW;
+    }
+
+    /**
+     * Flings forward (left) and waits the fling's end.
+     */
+    public void flingForward() {
+        final UiObject2 overview = verifyActiveContainer();
+        overview.fling(Direction.LEFT, DEFAULT_FLING_SPEED);
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings backward (right) and waits the fling's end.
+     */
+    public void flingBackward() {
+        final UiObject2 overview = verifyActiveContainer();
+        overview.fling(Direction.RIGHT, DEFAULT_FLING_SPEED);
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    /**
+     * Gets the current task in the carousel, or fails if the carousel is empty.
+     *
+     * @return the task in the middle of the visible tasks list.
+     */
+    @NonNull
+    public OverviewTask getCurrentTask() {
+        verifyActiveContainer();
+        final List<UiObject2> taskViews = mLauncher.getDevice().findObjects(
+                LauncherInstrumentation.getLauncherObjectSelector("snapshot"));
+        assertNotEquals("Unable to find a task", 0, taskViews.size());
+
+        // taskViews contains up to 3 task views: the 'main' (having the widest visible
+        // part) one in the center, and parts of its right and left siblings. Find the
+        // main task view by its width.
+        final UiObject2 widestTask = Collections.max(taskViews,
+                (t1, t2) -> Integer.compare(t1.getVisibleBounds().width(),
+                        t2.getVisibleBounds().width()));
+
+        return new OverviewTask(mLauncher, widestTask, this);
+    }
+
+    /**
+     * Swipes up to All Apps.
+     *
+     * @return the App Apps object.
+     */
+    @NonNull
+    public AllAppsFromOverview switchToAllApps() {
+        verifyActiveContainer();
+
+        // Swipe from the hotseat to near the top, e.g. 10% of the screen.
+        final UiObject2 predictionRow = mLauncher.waitForLauncherObject(
+                "prediction_row");
+        final Point start = predictionRow.getVisibleCenter();
+        final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
+        mLauncher.swipe(
+                start.x, start.y, start.x, endY);
+
+        return new AllAppsFromOverview(mLauncher);
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
new file mode 100644
index 0000000..0b3a264
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * A recent task in the overview panel carousel.
+ */
+public final class OverviewTask {
+    private final LauncherInstrumentation mLauncher;
+    private final UiObject2 mTask;
+    private final Overview mOverview;
+
+    OverviewTask(LauncherInstrumentation launcher, UiObject2 task, Overview overview) {
+        mLauncher = launcher;
+        mTask = task;
+        mOverview = overview;
+        verifyActiveContainer();
+    }
+
+    private void verifyActiveContainer() {
+        mOverview.verifyActiveContainer();
+    }
+
+    /**
+     * Swipes the task up.
+     */
+    public void dismiss() {
+        verifyActiveContainer();
+        // Dismiss the task via flinging it up.
+        mTask.fling(Direction.DOWN);
+        mLauncher.waitForIdle();
+    }
+
+    /**
+     * Clicks at the task.
+     */
+    public Background open() {
+        verifyActiveContainer();
+        assertTrue("Launching task didn't open a new window: " +
+                        mTask.getParent().getContentDescription(),
+                mTask.clickAndWait(Until.newWindow(), LauncherInstrumentation.WAIT_TIME_MS));
+        return new Background(mLauncher);
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
new file mode 100644
index 0000000..f67ef4c
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+
+/**
+ * All widgets container.
+ */
+public final class Widgets extends LauncherInstrumentation.VisibleContainer {
+    private static final int FLING_SPEED = 12000;
+
+    Widgets(LauncherInstrumentation launcher) {
+        super(launcher);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings forward (down) and waits the fling's end.
+     */
+    public void flingForward() {
+        final UiObject2 widgetsContainer = verifyActiveContainer();
+        widgetsContainer.setGestureMargin(100);
+        widgetsContainer.fling(Direction.DOWN, FLING_SPEED);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings backward (up) and waits the fling's end.
+     */
+    public void flingBackward() {
+        final UiObject2 widgetsContainer = verifyActiveContainer();
+        widgetsContainer.setGestureMargin(100);
+        widgetsContainer.fling(Direction.UP, FLING_SPEED);
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    @Override
+    protected LauncherInstrumentation.ContainerType getContainerType() {
+        return LauncherInstrumentation.ContainerType.WIDGETS;
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
new file mode 100644
index 0000000..045ab5f
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2018 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.tapl;
+
+import static junit.framework.TestCase.assertTrue;
+
+import android.graphics.Point;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.uiautomator.Direction;
+import android.support.test.uiautomator.UiObject2;
+import android.view.KeyEvent;
+
+/**
+ * Operations on the workspace screen.
+ */
+public final class Workspace extends Home {
+    private final UiObject2 mHotseat;
+    private final int ICON_DRAG_SPEED = 2000;
+
+    Workspace(LauncherInstrumentation launcher) {
+        super(launcher);
+        mHotseat = launcher.waitForLauncherObject("hotseat");
+    }
+
+    @Override
+    protected LauncherInstrumentation.ContainerType getContainerType() {
+        return LauncherInstrumentation.ContainerType.WORKSPACE;
+    }
+
+    /**
+     * Swipes up to All Apps.
+     *
+     * @return the App Apps object.
+     */
+    @NonNull
+    public AllApps switchToAllApps() {
+        verifyActiveContainer();
+        if (mLauncher.isSwipeUpEnabled()) {
+            int midX = mLauncher.getDevice().getDisplayWidth() / 2;
+            int height = mLauncher.getDevice().getDisplayHeight();
+            // Swipe from 6/7ths down the screen to 1/7th down the screen.
+            mLauncher.swipe(
+                    midX,
+                    height * 6 / 7,
+                    midX,
+                    height / 7
+            );
+        } else {
+            // Swipe from the hotseat to near the top, e.g. 10% of the screen.
+            final UiObject2 hotseat = mHotseat;
+            final Point start = hotseat.getVisibleCenter();
+            final int endY = (int) (mLauncher.getDevice().getDisplayHeight() * 0.1f);
+            mLauncher.swipe(
+                    start.x,
+                    start.y,
+                    start.x,
+                    endY
+            );
+        }
+
+        return new AllApps(mLauncher);
+    }
+
+    /**
+     * Returns an icon for the app, if currently visible.
+     *
+     * @param appName name of the app
+     * @return app icon, if found, null otherwise.
+     */
+    @Nullable
+    public AppIcon tryGetWorkspaceAppIcon(String appName) {
+        final UiObject2 workspace = verifyActiveContainer();
+        final UiObject2 icon = workspace.findObject(AppIcon.getAppIconSelector(appName));
+        return icon != null ? new AppIcon(mLauncher, icon) : null;
+    }
+
+    /**
+     * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
+     * second screen.
+     */
+    public void ensureWorkspaceIsScrollable() {
+        final UiObject2 workspace = verifyActiveContainer();
+        if (!isWorkspaceScrollable(workspace)) {
+            dragIconToNextScreen(getHotseatAppIcon("Messages"), workspace);
+        }
+        assertTrue("Home screen workspace didn't become scrollable",
+                isWorkspaceScrollable(workspace));
+    }
+
+    private boolean isWorkspaceScrollable(UiObject2 workspace) {
+        return workspace.isScrollable();
+    }
+
+    @NonNull
+    private AppIcon getHotseatAppIcon(String appName) {
+        return new AppIcon(mLauncher, mLauncher.getObjectInContainer(
+                mHotseat, AppIcon.getAppIconSelector(appName)));
+    }
+
+    private void dragIconToNextScreen(AppIcon app, UiObject2 workspace) {
+        final Point dest = new Point(
+                mLauncher.getDevice().getDisplayWidth(), workspace.getVisibleBounds().centerY());
+        app.getIcon().drag(dest, ICON_DRAG_SPEED);
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings to get to screens on the right. Waits for scrolling and a possible overscroll
+     * recoil to complete.
+     */
+    public void flingForward() {
+        final UiObject2 workspace = verifyActiveContainer();
+        workspace.fling(Direction.RIGHT);
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    /**
+     * Flings to get to screens on the left.  Waits for scrolling and a possible overscroll
+     * recoil to complete.
+     */
+    public void flingBackward() {
+        final UiObject2 workspace = verifyActiveContainer();
+        workspace.fling(Direction.LEFT);
+        mLauncher.waitForIdle();
+        verifyActiveContainer();
+    }
+
+    /**
+     * Opens widgets container by pressing Ctrl+W.
+     *
+     * @return the widgets container.
+     */
+    @NonNull
+    public Widgets openAllWidgets() {
+        verifyActiveContainer();
+        mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
+        return new Widgets(mLauncher);
+    }
+}
\ No newline at end of file