Merge "Update widget full sheet / bottom sheet to have top rounded corners." into ub-launcher3-master
diff --git a/Android.mk b/Android.mk
index 256d95d..a1cba4a2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,9 +20,13 @@
 # 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.
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index de74fce..3b983d2 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -68,6 +68,7 @@
   SEARCHBOX = 6;
   EDITTEXT = 7;
   NOTIFICATION = 8;
+  TASK = 9;         // Each page of Recents UI (QuickStep)
 }
 
 // Used to define what type of container a Target would represent.
@@ -78,11 +79,14 @@
   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)
 }
 
 // Used to define what type of control a Target would represent.
@@ -100,6 +104,7 @@
   HOME_INTENT = 10; // Deprecated, use enum Command instead
   BACK_BUTTON = 11; // Deprecated, use enum Command instead
   // GO_TO_PLAYSTORE
+  QUICK_SCRUB_BUTTON = 12;
 }
 
 // Used to define the action component of the LauncherEvent.
@@ -141,6 +146,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 +156,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;
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 74d3cba..d5859a7 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
new file mode 100644
index 0000000..b4c735b
--- /dev/null
+++ b/quickstep/res/values-af/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
new file mode 100644
index 0000000..62d54db
--- /dev/null
+++ b/quickstep/res/values-am/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ"</string>
+</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
new file mode 100644
index 0000000..de210b7
--- /dev/null
+++ b/quickstep/res/values-ar/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات"</string>
+</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
new file mode 100644
index 0000000..91c5179
--- /dev/null
+++ b/quickstep/res/values-az/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..a4eb3e8
--- /dev/null
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
new file mode 100644
index 0000000..f798802
--- /dev/null
+++ b/quickstep/res/values-be/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Для пераключэння праграм правядзіце па экране пальцам знізу ўверх"</string>
+</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
new file mode 100644
index 0000000..de88634
--- /dev/null
+++ b/quickstep/res/values-bg/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Прекарайте пръст нагоре от долната част, за да превключите между приложенията"</string>
+</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
new file mode 100644
index 0000000..028a475
--- /dev/null
+++ b/quickstep/res/values-bn/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"অ্যাপগুলির মধ্যে সুইচ করতে উপর থেকে নিচের দিকে সোয়াইপ করুন"</string>
+</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
new file mode 100644
index 0000000..16b72ea
--- /dev/null
+++ b/quickstep/res/values-bs/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
new file mode 100644
index 0000000..6d65fd7
--- /dev/null
+++ b/quickstep/res/values-ca/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
new file mode 100644
index 0000000..b6894c0
--- /dev/null
+++ b/quickstep/res/values-cs/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
new file mode 100644
index 0000000..ff2d25d
--- /dev/null
+++ b/quickstep/res/values-da/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
new file mode 100644
index 0000000..e5242c7
--- /dev/null
+++ b/quickstep/res/values-de/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
new file mode 100644
index 0000000..9d7023d
--- /dev/null
+++ b/quickstep/res/values-el/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών"</string>
+</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..694e73a
--- /dev/null
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..694e73a
--- /dev/null
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..694e73a
--- /dev/null
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..37a3168
--- /dev/null
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
new file mode 100644
index 0000000..60c87d3
--- /dev/null
+++ b/quickstep/res/values-es/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
new file mode 100644
index 0000000..33d1cba
--- /dev/null
+++ b/quickstep/res/values-et/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
new file mode 100644
index 0000000..d0e86c2
--- /dev/null
+++ b/quickstep/res/values-eu/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
new file mode 100644
index 0000000..198f33d
--- /dev/null
+++ b/quickstep/res/values-fa/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"برای تغییر برنامه‌ها،‌ از پایین تند به بالا بکشید"</string>
+</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
new file mode 100644
index 0000000..f244586
--- /dev/null
+++ b/quickstep/res/values-fi/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..d9b2a51
--- /dev/null
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -0,0 +1,25 @@
+<?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">"É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>
+</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
new file mode 100644
index 0000000..8c1a5d2
--- /dev/null
+++ b/quickstep/res/values-fr/strings.xml
@@ -0,0 +1,25 @@
+<?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">"É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>
+</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
new file mode 100644
index 0000000..d6f26ac
--- /dev/null
+++ b/quickstep/res/values-gl/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
new file mode 100644
index 0000000..8c779d6
--- /dev/null
+++ b/quickstep/res/values-gu/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ઍપને સ્વિચ કરવા માટે નીચેથી ઉપર સ્વાઇપ કરો"</string>
+</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
new file mode 100644
index 0000000..65507a9
--- /dev/null
+++ b/quickstep/res/values-hi/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ऐप्लिकेशन स्विच करने के लिए सबसे नीचे से ऊपर की ओर स्वाइप करें"</string>
+</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
new file mode 100644
index 0000000..eaa4416
--- /dev/null
+++ b/quickstep/res/values-hr/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
new file mode 100644
index 0000000..b72c760
--- /dev/null
+++ b/quickstep/res/values-hu/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
new file mode 100644
index 0000000..632ea3e
--- /dev/null
+++ b/quickstep/res/values-hy/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Սահեցրեք ներքևից վերև՝ մյուս հավելվածին անցնելու համար"</string>
+</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
new file mode 100644
index 0000000..d731bce
--- /dev/null
+++ b/quickstep/res/values-in/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
new file mode 100644
index 0000000..d4d54d3
--- /dev/null
+++ b/quickstep/res/values-is/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
new file mode 100644
index 0000000..6223ddb
--- /dev/null
+++ b/quickstep/res/values-it/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
new file mode 100644
index 0000000..1da258a
--- /dev/null
+++ b/quickstep/res/values-iw/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"יש להחליק כלפי מעלה מהחלק התחתון כדי לעבור בין אפליקציות"</string>
+</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
new file mode 100644
index 0000000..bee863f
--- /dev/null
+++ b/quickstep/res/values-ja/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"アプリを切り替えるには、下から上にスワイプします"</string>
+</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
new file mode 100644
index 0000000..4488cf8
--- /dev/null
+++ b/quickstep/res/values-ka/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"აპების გადასართავად გადაფურცლეთ ქვედა კიდედან ზემოთ"</string>
+</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
new file mode 100644
index 0000000..8c82ef1
--- /dev/null
+++ b/quickstep/res/values-kk/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Қолданбалар арасында ауысу үшін төменнен жоғары қарай саусақпен сырғытыңыз"</string>
+</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
new file mode 100644
index 0000000..64136c9
--- /dev/null
+++ b/quickstep/res/values-km/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"អូស​ពី​ក្រោម​ឡើង​លើ ដើម្បី​ប្ដូរ​កម្មវិធី"</string>
+</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
new file mode 100644
index 0000000..7f12dee
--- /dev/null
+++ b/quickstep/res/values-kn/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
new file mode 100644
index 0000000..39fdf33
--- /dev/null
+++ b/quickstep/res/values-ko/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"아래에서 위로 스와이프하여 앱을 전환합니다."</string>
+</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
new file mode 100644
index 0000000..2602b51
--- /dev/null
+++ b/quickstep/res/values-ky/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Колдонмолорду которуштуруу үчүн экранды төмөндөн жогору карай сүрүңүз"</string>
+</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
new file mode 100644
index 0000000..7ba29d2
--- /dev/null
+++ b/quickstep/res/values-lo/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ປັດຂຶ້ນຈາກລຸ່ມສຸດເພື່ອສະຫຼັບແອັບ"</string>
+</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
new file mode 100644
index 0000000..2252381
--- /dev/null
+++ b/quickstep/res/values-lt/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
new file mode 100644
index 0000000..d5f5e9c
--- /dev/null
+++ b/quickstep/res/values-lv/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
new file mode 100644
index 0000000..6458aa0
--- /dev/null
+++ b/quickstep/res/values-mk/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Повлечете нагоре од дното за да ги смените апликациите"</string>
+</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
new file mode 100644
index 0000000..4d2745a
--- /dev/null
+++ b/quickstep/res/values-ml/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"</string>
+</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
new file mode 100644
index 0000000..4aec257
--- /dev/null
+++ b/quickstep/res/values-mn/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Аппыг сэлгэхийн тулд доороос дээш шударна уу"</string>
+</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
new file mode 100644
index 0000000..3f85d77
--- /dev/null
+++ b/quickstep/res/values-mr/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"अ‍ॅप्स स्विच करण्यासाठी तळापासून वर स्वाइप करा"</string>
+</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
new file mode 100644
index 0000000..80e942c
--- /dev/null
+++ b/quickstep/res/values-ms/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
new file mode 100644
index 0000000..b6b0300
--- /dev/null
+++ b/quickstep/res/values-my/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ"</string>
+</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
new file mode 100644
index 0000000..4dc144c
--- /dev/null
+++ b/quickstep/res/values-nb/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
new file mode 100644
index 0000000..a171b73
--- /dev/null
+++ b/quickstep/res/values-ne/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्"</string>
+</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
new file mode 100644
index 0000000..4acddc5
--- /dev/null
+++ b/quickstep/res/values-nl/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
new file mode 100644
index 0000000..6bc1876
--- /dev/null
+++ b/quickstep/res/values-pa/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ਐਪਾਂ ਵਿੱਚ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
new file mode 100644
index 0000000..174a96a
--- /dev/null
+++ b/quickstep/res/values-pl/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..c3df4f2
--- /dev/null
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
new file mode 100644
index 0000000..9730b98
--- /dev/null
+++ b/quickstep/res/values-pt/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
new file mode 100644
index 0000000..46671e8
--- /dev/null
+++ b/quickstep/res/values-ro/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
new file mode 100644
index 0000000..c2edf75
--- /dev/null
+++ b/quickstep/res/values-ru/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Чтобы переключить приложение, проведите по экрану снизу вверх"</string>
+</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
new file mode 100644
index 0000000..7702543
--- /dev/null
+++ b/quickstep/res/values-si/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න"</string>
+</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
new file mode 100644
index 0000000..84e7793
--- /dev/null
+++ b/quickstep/res/values-sk/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
new file mode 100644
index 0000000..c01fcd4
--- /dev/null
+++ b/quickstep/res/values-sl/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
new file mode 100644
index 0000000..ae6e6bc
--- /dev/null
+++ b/quickstep/res/values-sq/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
new file mode 100644
index 0000000..84debfd
--- /dev/null
+++ b/quickstep/res/values-sr/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Превуците нагоре да бисте прешли на другу апликацију"</string>
+</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
new file mode 100644
index 0000000..495bca7
--- /dev/null
+++ b/quickstep/res/values-sv/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
new file mode 100644
index 0000000..63594f2
--- /dev/null
+++ b/quickstep/res/values-sw/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
new file mode 100644
index 0000000..2d740ca
--- /dev/null
+++ b/quickstep/res/values-ta/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்க"</string>
+</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
new file mode 100644
index 0000000..36e5e3e
--- /dev/null
+++ b/quickstep/res/values-te/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"యాప్‌లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి"</string>
+</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
new file mode 100644
index 0000000..882b096
--- /dev/null
+++ b/quickstep/res/values-th/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป"</string>
+</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
new file mode 100644
index 0000000..dbd03b1
--- /dev/null
+++ b/quickstep/res/values-tl/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
new file mode 100644
index 0000000..57cb349
--- /dev/null
+++ b/quickstep/res/values-tr/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
new file mode 100644
index 0000000..8c2c6f6
--- /dev/null
+++ b/quickstep/res/values-uk/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"Щоб переходити між додатками, проводьте пальцем знизу вгору"</string>
+</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
new file mode 100644
index 0000000..ab5b38f
--- /dev/null
+++ b/quickstep/res/values-ur/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"ایپس کو سوئچ کرنے کیلئے نیچے سے اوپر سوائپ کریں"</string>
+</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
new file mode 100644
index 0000000..280bd88
--- /dev/null
+++ b/quickstep/res/values-uz/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
new file mode 100644
index 0000000..2aca3b8
--- /dev/null
+++ b/quickstep/res/values-vi/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..165f141
--- /dev/null
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"从屏幕底部向上滑动即可切换应用"</string>
+</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..6ba0244
--- /dev/null
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"從螢幕底部向上快速滑動,即可切換應用程式"</string>
+</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..9834038
--- /dev/null
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -0,0 +1,25 @@
+<?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="recents_swipe_up_onboarding" msgid="1025535041275136564">"從畫面底部向上滑動以切換應用程式"</string>
+</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
new file mode 100644
index 0000000..a4ba48c
--- /dev/null
+++ b/quickstep/res/values-zu/strings.xml
@@ -0,0 +1,25 @@
+<?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">"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>
+</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index d8504f1..0956048 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -37,4 +37,7 @@
     <!-- Launcher app transition -->
     <dimen name="content_trans_y">25dp</dimen>
     <dimen name="workspace_trans_y">80dp</dimen>
+    <dimen name="recents_adjacent_trans_x">120dp</dimen>
+    <dimen name="recents_adjacent_trans_y">80dp</dimen>
+    <fraction name="recents_adjacent_scale">150%</fraction>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 2f0cd78..0fe29e3 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -16,10 +16,13 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
 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.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -27,13 +30,13 @@
 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.os.Build;
-import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
 import android.view.Surface;
@@ -45,6 +48,7 @@
 import com.android.launcher3.InsettableFrameLayout.LayoutParams;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.graphics.DrawableFactory;
 import com.android.quickstep.RecentsAnimationInterpolator;
@@ -79,8 +83,8 @@
     private static final int CLOSING_TRANSITION_DURATION_MS = 350;
 
     // 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;
+    private static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
+    private static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f;
 
     private final DragLayer mDragLayer;
     private final Launcher mLauncher;
@@ -88,6 +92,9 @@
 
     private final float mContentTransY;
     private final float mWorkspaceTransY;
+    private final float mRecentsTransX;
+    private final float mRecentsTransY;
+    private final float mRecentsScale;
 
     private View mFloatingView;
     private boolean mIsRtl;
@@ -104,6 +111,9 @@
         Resources res = mLauncher.getResources();
         mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
         mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
+        mRecentsTransX = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_x);
+        mRecentsTransY = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_y);
+        mRecentsScale = res.getFraction(R.fraction.recents_adjacent_scale, 1, 1);
 
         mLauncher.addOnDeviceProfileChangeListener(this);
         registerRemoteAnimations();
@@ -115,7 +125,7 @@
     }
 
     private void setCurrentAnimator(LauncherTransitionAnimator animator) {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+        if (isAnimating()) {
             mCurrentAnimator.cancel();
         }
         mCurrentAnimator = animator;
@@ -123,18 +133,23 @@
 
     @Override
     public void finishLauncherAnimation() {
-        if (mCurrentAnimator != null && mCurrentAnimator.isRunning()) {
+        if (isAnimating()) {
             mCurrentAnimator.finishLauncherAnimation();
         }
         mCurrentAnimator = null;
     }
 
+    @Override
+    public boolean isAnimating() {
+        return mCurrentAnimator != null && mCurrentAnimator.isRunning();
+    }
+
     /**
-     * @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) {
@@ -187,7 +202,7 @@
                 };
 
                 return ActivityOptionsCompat.makeRemoteAnimation(
-                        new RemoteAnimationAdapterCompat(runner, 500, 380)).toBundle();
+                        new RemoteAnimationAdapterCompat(runner, 500, 380));
             } catch (NoClassDefFoundError e) {
                 // Gracefully fall back to default launch options if the user's platform doesn't
                 // have the latest changes.
@@ -229,7 +244,93 @@
         }
 
         // Found a visible recents task that matches the opening app, lets launch the app from there
-        return new LauncherTransitionAnimator(null, getRecentsWindowAnimator(taskView, targets));
+        return new LauncherTransitionAnimator(getRecentsLauncherAnimator(recentsView, taskView),
+                getRecentsWindowAnimator(taskView, targets));
+    }
+
+    /**
+     * Animate adjacent tasks off screen while scaling up, and translate hotseat off screen as well.
+     *
+     * If launching one of the adjacent tasks, parallax the center task and other adjacent task
+     * to the right.
+     */
+    private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v) {
+        AnimatorSet launcherAnimator = new AnimatorSet();
+
+        int launchedTaskIndex = recentsView.indexOfChild(v);
+        int centerTaskIndex = recentsView.getCurrentPage();
+        boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
+        if (launchingCenterTask) {
+            if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
+                TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
+                ObjectAnimator adjacentTask1ScaleAndTranslate =
+                        LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
+                                new PropertyListBuilder()
+                                        .scale(adjacentPage1.getScaleX() * mRecentsScale)
+                                        .translationY(mRecentsTransY)
+                                        .translationX(mIsRtl ? mRecentsTransX : -mRecentsTransX)
+                                        .build());
+                launcherAnimator.play(adjacentTask1ScaleAndTranslate);
+            }
+            if (launchedTaskIndex + 1 < recentsView.getPageCount()) {
+                TaskView adjacentTask2 = (TaskView) recentsView.getPageAt(launchedTaskIndex + 1);
+                ObjectAnimator adjacentTask2ScaleAndTranslate =
+                        LauncherAnimUtils.ofPropertyValuesHolder(adjacentTask2,
+                                new PropertyListBuilder()
+                                        .scale(adjacentTask2.getScaleX() * mRecentsScale)
+                                        .translationY(mRecentsTransY)
+                                        .translationX(mIsRtl ? -mRecentsTransX : mRecentsTransX)
+                                        .build());
+                launcherAnimator.play(adjacentTask2ScaleAndTranslate);
+            }
+        } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
+            // We are launching an adjacent task, so parallax the center and other adjacent task.
+            TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
+            float translationX = Math.abs(v.getTranslationX());
+            ObjectAnimator centerTaskParallaxToRight =
+                    LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
+                            new PropertyListBuilder()
+                                    .scale(v.getScaleX())
+                                    .translationX(mIsRtl ? -translationX : translationX)
+                                    .build());
+            launcherAnimator.play(centerTaskParallaxToRight);
+            int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
+            if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
+                    && otherAdjacentTaskIndex < recentsView.getPageCount()) {
+                TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
+                        otherAdjacentTaskIndex);
+                ObjectAnimator otherAdjacentTaskParallaxToRight =
+                        LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
+                                new PropertyListBuilder()
+                                        .translationX(otherAdjacentTask.getTranslationX()
+                                                + (mIsRtl ? -translationX : translationX))
+                                        .build());
+                launcherAnimator.play(otherAdjacentTaskParallaxToRight);
+            }
+        }
+
+        Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(),
+                ALL_APPS_PROGRESS, ALL_APPS_PROGRESS_OFF_SCREEN);
+        launcherAnimator.play(allAppsSlideOut);
+
+        Workspace workspace = mLauncher.getWorkspace();
+        float[] workspaceScaleAndTranslation = LauncherState.NORMAL
+                .getWorkspaceScaleAndTranslation(mLauncher);
+        Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder(
+                workspace, new PropertyListBuilder()
+                        .translationX(workspaceScaleAndTranslation[1])
+                        .translationY(workspaceScaleAndTranslation[2])
+                        .build());
+        launcherAnimator.play(recenterWorkspace);
+        CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt(
+                workspace.getCurrentPage());
+        Animator hideWorkspaceScrim = ObjectAnimator.ofInt(
+                currentWorkspacePage.getScrimBackground(), DRAWABLE_ALPHA, 0);
+        launcherAnimator.play(hideWorkspaceScrim);
+
+        launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+        launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION);
+        return launcherAnimator;
     }
 
     /**
@@ -246,7 +347,10 @@
         RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator(
                 new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
                 v.getThumbnail().getInsets(),
-                taskViewBounds, new Rect(0, v.getThumbnail().getTop(), 0, 0));
+                taskViewBounds,
+                new Rect(0, v.getThumbnail().getTop(), 0, 0),
+                v.getScaleX(),
+                v.getTranslationX());
 
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
@@ -309,6 +413,13 @@
                 isFirstFrame = false;
             }
         });
+        appAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Make sure recents gets fixed up by resetting task alphas and scales, etc.
+                mLauncher.getStateManager().reapplyState();
+            }
+        });
         return appAnimator;
     }
 
@@ -317,17 +428,19 @@
      */
     private LauncherTransitionAnimator composeAppLaunchAnimator(View v,
             RemoteAnimationTargetCompat[] targets) {
-        return new LauncherTransitionAnimator(getLauncherAnimators(v),
+        return new LauncherTransitionAnimator(getLauncherAnimators(v, targets),
                 getWindowAnimators(v, targets));
     }
 
     /**
      * @return Animators that control the movements of the Launcher and icon of the opening target.
      */
-    private AnimatorSet getLauncherAnimators(View v) {
+    private AnimatorSet getLauncherAnimators(View v, RemoteAnimationTargetCompat[] targets) {
         AnimatorSet launcherAnimators = new AnimatorSet();
-        launcherAnimators.play(getLauncherContentAnimator(false /* show */));
         launcherAnimators.play(getIconAnimator(v));
+        if (launcherIsATargetWithMode(targets, MODE_CLOSING)) {
+            launcherAnimators.play(getLauncherContentAnimator(false /* show */));
+        }
         return launcherAnimators;
     }
 
@@ -388,8 +501,10 @@
         mFloatingView = new View(mLauncher);
         if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
             // Create a copy of the app icon
-            mFloatingView.setBackground(
-                    DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag()));
+            ItemInfoWithIcon info = (ItemInfoWithIcon) v.getTag();
+            FastBitmapDrawable d = DrawableFactory.get(mLauncher).newIcon(info);
+            d.setIsDisabled(info.isDisabled());
+            mFloatingView.setBackground(d);
         }
 
         // Position the floating view exactly on top of the original
@@ -431,6 +546,8 @@
         boolean isBelowCenterY = lp.topMargin < centerY;
         x.setDuration(isBelowCenterY ? 500 : 233);
         y.setDuration(isBelowCenterY ? 233 : 500);
+        x.setInterpolator(Interpolators.AGGRESSIVE_EASE);
+        y.setInterpolator(Interpolators.AGGRESSIVE_EASE);
         appIconAnimatorSet.play(x);
         appIconAnimatorSet.play(y);
 
@@ -443,18 +560,18 @@
         ObjectAnimator sY = ObjectAnimator.ofFloat(mFloatingView, View.SCALE_Y, 1f, scale);
         sX.setDuration(500);
         sY.setDuration(500);
+        sX.setInterpolator(Interpolators.EXAGGERATED_EASE);
+        sY.setInterpolator(Interpolators.EXAGGERATED_EASE);
         appIconAnimatorSet.play(sX);
         appIconAnimatorSet.play(sY);
 
         // Fade out the app icon.
         ObjectAnimator alpha = ObjectAnimator.ofFloat(mFloatingView, View.ALPHA, 1f, 0f);
-        alpha.setStartDelay(17);
-        alpha.setDuration(33);
+        alpha.setStartDelay(32);
+        alpha.setDuration(50);
+        alpha.setInterpolator(Interpolators.LINEAR);
         appIconAnimatorSet.play(alpha);
 
-        for (Animator a : appIconAnimatorSet.getChildAnimations()) {
-            a.setInterpolator(Interpolators.AGGRESSIVE_EASE);
-        }
         return appIconAnimatorSet;
     }
 
@@ -515,9 +632,9 @@
 
                 // Fade in the app window.
                 float alphaDelay = 0;
-                float alphaDuration = 50;
+                float alphaDuration = 60;
                 float alpha = getValue(0f, 1f, alphaDelay, alphaDuration,
-                        appAnimator.getDuration() * percent, Interpolators.AGGRESSIVE_EASE);
+                        appAnimator.getDuration() * percent, Interpolators.LINEAR);
 
                 // Animate the window crop so that it starts off as a square, and then reveals
                 // horizontally.
@@ -530,7 +647,7 @@
 
                 TransactionCompat t = new TransactionCompat();
                 for (RemoteAnimationTargetCompat target : targets) {
-                    if (target.mode == RemoteAnimationTargetCompat.MODE_OPENING) {
+                    if (target.mode == MODE_OPENING) {
                         t.setAlpha(target.leash, alpha);
 
                         // TODO: This isn't correct at the beginning of the animation, but better
@@ -573,6 +690,16 @@
         }
     }
 
+    private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
+        int launcherTaskId = mLauncher.getTaskId();
+        for (RemoteAnimationTargetCompat target : targets) {
+            if (target.mode == mode && target.taskId == launcherTaskId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * @return Runner that plays when user goes to Launcher
      *         ie. pressing home, swiping up from nav bar.
@@ -584,9 +711,13 @@
                                          Runnable finishedCallback) {
                 Handler handler = mLauncher.getWindow().getDecorView().getHandler();
                 postAtFrontOfQueueAsynchronously(handler, () -> {
-                    if (Utilities.getPrefs(mLauncher).getBoolean("pref_use_screenshot_animation",
-                            true) && mLauncher.isInState(LauncherState.OVERVIEW)) {
-                        // We use a separate transition for Overview mode.
+                    if ((Utilities.getPrefs(mLauncher)
+                            .getBoolean("pref_use_screenshot_for_swipe_up", false)
+                            && mLauncher.isInState(LauncherState.OVERVIEW))
+                            || !launcherIsATargetWithMode(targets, MODE_OPENING)) {
+                        // 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;
@@ -691,9 +822,9 @@
             // 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;
+            final float startY = ALL_APPS_PROGRESS_OFF_SCREEN;
             // And will end slightly pulled up, so that there is something to overshoot back to 1f.
-            final float slideEnd = ALL_APPS_PROGRESS_SLIDE_END;
+            final float slideEnd = ALL_APPS_PROGRESS_OVERSHOOT;
 
             allAppsController.setProgress(startY);
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
index e39430d..541c6bb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
@@ -24,16 +24,55 @@
 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.LauncherState;
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 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.
  */
@@ -42,6 +81,8 @@
 
     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);
@@ -63,6 +104,10 @@
         return isTransitionFlipped() ? DIRECTION_NEGATIVE : DIRECTION_POSITIVE;
     }
 
+    public EdgeSwipeController(Launcher l, LauncherState baseState) {
+        super(l, baseState);
+    }
+
     @Override
     protected boolean isTransitionFlipped() {
         return mLauncher.getDeviceProfile().isSeascape();
@@ -70,7 +115,31 @@
 
     @Override
     protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
-        // TODO: Log something
+        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);
+
+            // Add user event logging for launcher pipeline
+            int direction = Direction.UP;
+            if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+                direction = Direction.LEFT;
+                if (mLauncher.getDeviceProfile().isSeascape()) {
+                    direction = Direction.RIGHT;
+                }
+            }
+            mLauncher.getUserEventDispatcher().logStateChangeAction(
+                    wasFling ? Touch.FLING : Touch.SWIPE, direction,
+                    ContainerType.NAVBAR, ContainerType.WORKSPACE, // src target
+                    ContainerType.TASKSWITCHER,                    // dst target
+                    mLauncher.getWorkspace().getCurrentPage());
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 5706d32..9ba2308 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -40,7 +40,7 @@
             | FLAG_DISABLE_RESTORE;
 
     public OverviewState(int id) {
-        super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
+        super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
index 1fd541a..468a561 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
@@ -31,6 +31,10 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.RecentsView;
 import com.android.quickstep.TaskView;
@@ -70,6 +74,7 @@
     private float mDisplacementShift;
     private float mProgressMultiplier;
     private float mEndDisplacement;
+    private int mStartingTarget;
 
     private TaskView mTaskBeingDragged;
 
@@ -120,7 +125,6 @@
             // calling the callbacks.
             final int directionsToDetectScroll;
             boolean ignoreSlopWhenSettling = false;
-
             if (mCurrentAnimation != null) {
                 directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
                 ignoreSlopWhenSettling = true;
@@ -139,12 +143,15 @@
                         // The tile can be dragged down to open the task.
                         mTaskBeingDragged = (TaskView) view;
                         directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+                        mStartingTarget = LauncherLogProto.ItemType.TASK;
                     } else if (isEventOverHotseat(ev)) {
                         // The hotseat is being dragged
                         directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
                         mSwipeDownEnabled = false;
+                        mStartingTarget = ContainerType.HOTSEAT;
                     } else {
                         mNoIntercept = true;
+                        mStartingTarget = ContainerType.WORKSPACE;
                         return false;
                     }
                 }
@@ -249,8 +256,9 @@
     @Override
     public void onDragEnd(float velocity, boolean fling) {
         final boolean goingToEnd;
-
+        final int logAction;
         if (fling) {
+            logAction = Touch.FLING;
             boolean goingUp = velocity < 0;
             if (!goingUp && !mSwipeDownEnabled) {
                 goingToEnd = false;
@@ -269,6 +277,7 @@
                 goingToEnd = true;
             }
         } else {
+            logAction = Touch.SWIPE;
             goingToEnd = mCurrentAnimation.getProgressFraction() > SUCCESS_TRANSITION_PROGRESS;
         }
 
@@ -280,7 +289,7 @@
                 progress + velocity * SINGLE_FRAME_MS / Math.abs(mEndDisplacement), 0f, 1f);
 
 
-        mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd));
+        mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd, logAction));
 
         ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
         anim.setFloatValues(nextFrameProgress, goingToEnd ? 1f : 0f);
@@ -289,19 +298,28 @@
         anim.start();
     }
 
-    private void onCurrentAnimationEnd(boolean wasSuccess) {
-        // TODO: Might be a good time to log something.
+    private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
         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);
+                mLauncher.getUserEventDispatcher().logTaskLaunch(logAction,
+                        Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent());
             }
         }
+        if (mTaskBeingDragged == null || (wasSuccess && mCurrentAnimationIsGoingUp)) {
+            mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+                    mCurrentAnimationIsGoingUp ? Direction.UP : Direction.DOWN,
+                    mStartingTarget, ContainerType.TASKSWITCHER,
+                    mLauncher.getStateManager().getState().containerType,
+                    mRecentsView.getCurrentPage());
+        }
         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
index 3ae8f41..4fb3886 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeUpController.java
@@ -58,10 +58,12 @@
     protected void onTransitionComplete(boolean wasFling, boolean stateChanged) {
         if (stateChanged) {
             // Transition complete. log the action
-            mLauncher.getUserEventDispatcher().logActionOnContainer(
+            mLauncher.getUserEventDispatcher().logStateChangeAction(
                     wasFling ? Touch.FLING : Touch.SWIPE,
                     Direction.UP,
-                    ContainerType.OVERVIEW,
+                    ContainerType.HOTSEAT,
+                    ContainerType.TASKSWITCHER,
+                    ContainerType.ALLAPPS,
                     mLauncher.getWorkspace().getCurrentPage());
         }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 9a5640b..7d371e9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsView;
+import com.android.quickstep.TaskView;
 
 public class RecentsViewStateController implements StateHandler {
 
@@ -62,6 +63,12 @@
         mWorkspaceCard.setWorkspaceScrollingEnabled(state == OVERVIEW);
         setVisibility(state == OVERVIEW);
         setTransitionProgress(state == OVERVIEW ? 1 : 0);
+        if (state == OVERVIEW) {
+            for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+                ((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
+            }
+            mRecentsView.updateCurveProperties();
+        }
     }
 
     @Override
@@ -139,7 +146,9 @@
         applyProgress();
         if (mIsRecentsScrollingToFirstTask) {
             int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
-            mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask));
+            int scrollForPage0 = mRecentsView.getScrollForPage(0);
+            mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
+                    + (1 - mTransitionProgress.value) * scrollForPage0));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
index fb59946..2695054 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -50,10 +50,7 @@
 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;
 
@@ -371,9 +368,12 @@
     private void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
         if (targetState != mFromState) {
             // Transition complete. log the action
-            mLauncher.getUserEventDispatcher().logActionOnContainer(logAction,
+            mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
                     mToState == ALL_APPS ? Direction.UP : Direction.DOWN,
-                    mStartContainerType, mLauncher.getWorkspace().getCurrentPage());
+                    mStartContainerType,
+                    mFromState.containerType,
+                    mToState.containerType,
+                    mLauncher.getWorkspace().getCurrentPage());
         }
         clearState();
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index b4f40c2..7bd4366 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,12 +16,11 @@
 
 package com.android.launcher3.uioverrides;
 
-import android.content.pm.PackageManager;
+import static com.android.launcher3.LauncherState.NORMAL;
+
 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 com.android.launcher3.Launcher;
@@ -29,6 +28,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.graphics.BitmapRenderer;
 import com.android.launcher3.util.TouchController;
+import com.android.quickstep.OverviewInteractionState;
 import com.android.quickstep.RecentsView;
 import com.android.systemui.shared.recents.view.RecentsTransition;
 
@@ -68,6 +68,11 @@
         OptionsPopupView.show(launcher, touchPoint.x, touchPoint.y);
     }
 
+    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) {
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index fae9b66..6e92d83 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -16,17 +16,22 @@
 package com.android.quickstep;
 
 import static android.view.MotionEvent.ACTION_CANCEL;
+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;
+import android.util.Log;
 import android.view.Choreographer;
 import android.view.MotionEvent;
 
 import com.android.systemui.shared.system.ChoreographerCompat;
 
 import java.util.ArrayList;
-import java.util.function.Consumer;
 
 /**
  * Helper class for batching input events
@@ -34,6 +39,21 @@
 @TargetApi(Build.VERSION_CODES.O)
 public class MotionEventQueue {
 
+    private static final String TAG = "MotionEventQueue";
+
+    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);
+    private static final int ACTION_QUICK_SCRUB_PROGRESS =
+            ACTION_VIRTUAL | (3 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_QUICK_SCRUB_END =
+            ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
+    private static final int ACTION_RESET =
+            ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
+
     private final EventArray mEmptyArray = new EventArray();
     private final Object mExecutionLock = new Object();
 
@@ -46,45 +66,48 @@
 
     private final Choreographer mMainChoreographer;
 
-    private Consumer<MotionEvent> mConsumer;
+    private final TouchConsumer mConsumer;
 
     private Choreographer mInterimChoreographer;
     private Choreographer mCurrentChoreographer;
 
     private Runnable mCurrentRunnable;
 
-    public MotionEventQueue(Choreographer choreographer, Consumer<MotionEvent> consumer) {
+    public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
         mMainChoreographer = choreographer;
         mConsumer = consumer;
 
         mCurrentChoreographer = mMainChoreographer;
         mCurrentRunnable = mMainFrameCallback;
-    }
-
-    public void setConsumer(Consumer<MotionEvent> consumer) {
-        synchronized (mExecutionLock) {
-            mConsumer = consumer;
-        }
+        setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
     }
 
     public void setInterimChoreographer(Choreographer choreographer) {
         synchronized (mExecutionLock) {
             synchronized (mArrays) {
-                mInterimChoreographer = choreographer;
-                if (choreographer == null) {
-                    mCurrentChoreographer = mMainChoreographer;
-                    mCurrentRunnable = mMainFrameCallback;
-                } else {
-                    mCurrentChoreographer = mInterimChoreographer;
-                    mCurrentRunnable = mInterimFrameCallback;
-                }
-
+                setInterimChoreographerLocked(choreographer);
                 ChoreographerCompat.postInputFrame(mCurrentChoreographer, mCurrentRunnable);
             }
         }
     }
 
+    private void  setInterimChoreographerLocked(Choreographer choreographer) {
+        mInterimChoreographer = choreographer;
+        if (choreographer == null) {
+            mCurrentChoreographer = mMainChoreographer;
+            mCurrentRunnable = mMainFrameCallback;
+        } else {
+            mCurrentChoreographer = mInterimChoreographer;
+            mCurrentRunnable = mInterimFrameCallback;
+        }
+    }
+
     public void queue(MotionEvent event) {
+        mConsumer.preProcessMotionEvent(event);
+        queueNoPreProcess(event);
+    }
+
+    private void queueNoPreProcess(MotionEvent event) {
         synchronized (mArrays) {
             EventArray array = mArrays[mCurrentIndex];
             if (array.isEmpty()) {
@@ -116,7 +139,29 @@
             int size = array.size();
             for (int i = 0; i < size; i++) {
                 MotionEvent event = array.get(i);
-                mConsumer.accept(event);
+                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;
+                        case ACTION_QUICK_SCRUB_PROGRESS:
+                            mConsumer.onQuickScrubProgress(event.getX());
+                            break;
+                        case ACTION_QUICK_SCRUB_END:
+                            mConsumer.onQuickScrubEnd();
+                            break;
+                        case ACTION_RESET:
+                            mConsumer.reset();
+                            break;
+                        default:
+                            Log.e(TAG, "Invalid virtual event: " + event.getAction());
+                    }
+                } else {
+                    mConsumer.accept(event);
+                }
                 event.recycle();
             }
             array.clear();
@@ -135,6 +180,30 @@
         }
     }
 
+    private void queueVirtualAction(int action, float progress) {
+        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 onQuickScrubProgress(float progress) {
+        queueVirtualAction(ACTION_QUICK_SCRUB_PROGRESS, progress);
+    }
+
+    public void onQuickScrubEnd() {
+        queueVirtualAction(ACTION_QUICK_SCRUB_END, 0);
+    }
+
+    public void reset() {
+        queueVirtualAction(ACTION_RESET, 0);
+    }
+
     private static class EventArray extends ArrayList<MotionEvent> {
 
         public int lastEventAction = ACTION_CANCEL;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 40246e2..ff7d434 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -67,7 +67,6 @@
 
     private static final long MAX_SWIPE_DURATION = 200;
     private static final long MIN_SWIPE_DURATION = 80;
-    private static final int QUICK_SWITCH_SNAP_DURATION = 120;
 
     // Ideal velocity for a smooth transition
     private static final float PIXEL_PER_MS = 2f;
@@ -369,18 +368,8 @@
             ((TaskView) currentRecentsPage).animateIconToScale(1f);
         }
         if (mInteractionType == INTERACTION_QUICK_SWITCH) {
-            for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
-                TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
-                if (taskView.getTask().key.id != mRunningTaskId) {
-                    mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION);
-                    taskView.postDelayed(() -> {taskView.launchTask(true);},
-                            QUICK_SWITCH_SNAP_DURATION);
-                    break;
-                }
-            }
-        } else if (mInteractionType == INTERACTION_QUICK_SCRUB) {
             if (mQuickScrubController != null) {
-                mQuickScrubController.snapToPageForCurrentQuickScrubSection();
+                mQuickScrubController.onQuickSwitch();
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
new file mode 100644
index 0000000..431fb30
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.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;
+
+import android.annotation.TargetApi;
+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.Build.VERSION_CODES;
+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.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 LauncherIcons mLauncherIcons;
+
+    public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
+            LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+        super(context, iconCache, activityInfoCache);
+    }
+
+    @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);
+                mDefaultIcons.put(userId, info);
+            }
+
+            return new FastBitmapDrawable(info);
+        }
+    }
+
+    @Override
+    protected Drawable createBadgedDrawable(Drawable drawable, int userId) {
+        return new FastBitmapDrawable(getBitmapInfo(drawable, userId));
+    }
+
+    private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId) {
+        if (mLauncherIcons == null) {
+            mLauncherIcons = LauncherIcons.obtain(mContext);
+        }
+
+        // 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);
+    }
+
+    @Override
+    protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId) {
+        return createBadgedDrawable(
+                activityInfo.loadUnbadgedIcon(mContext.getPackageManager()), userId);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index d8f7aaf..488cd72 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -23,6 +23,8 @@
 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_BACK;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityOptions;
@@ -35,9 +37,12 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.metrics.LogMaker;
 import android.os.Bundle;
 import android.os.Looper;
+import android.os.SystemClock;
 import android.util.Log;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -52,6 +57,7 @@
 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.HitTarget;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RecentsAnimationListener;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -60,6 +66,40 @@
 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
  */
@@ -73,6 +113,7 @@
     private final Intent mHomeIntent;
     private final ISystemUiProxy mISystemUiProxy;
     private final MainThreadExecutor mMainThreadExecutor;
+    private final Choreographer mBackgroundThreadChoreographer;
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
@@ -83,12 +124,17 @@
     private BaseSwipeInteractionHandler 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();
 
     public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
             RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
-            MainThreadExecutor mainThreadExecutor) {
+            MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
+            @HitTarget int downHitTarget) {
         super(base);
         mRunningTask = runningTaskInfo;
         mRecentsModel = recentsModel;
@@ -96,6 +142,8 @@
         mVelocityTracker = VelocityTracker.obtain();
         mISystemUiProxy = systemUiProxy;
         mMainThreadExecutor = mainThreadExecutor;
+        mBackgroundThreadChoreographer = backgroundThreadChoreographer;
+        mDownHitTarget = downHitTarget;
     }
 
     @Override
@@ -109,12 +157,13 @@
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
-                mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+                mTouchSlop = ViewConfiguration.get(this).getScaledPagingTouchSlop();
                 mTouchThresholdCrossed = false;
 
-                // Start the window animation on down to give more time for launcher to draw
-                if (!isUsingScreenShot()) {
-                    startTouchTrackingForWindowAnimation();
+                // 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() && mDownHitTarget != HIT_TARGET_BACK) {
+                    startTouchTrackingForWindowAnimation(ev.getEventTime());
                 }
 
                 Display display = getSystemService(WindowManager.class).getDefaultDisplay();
@@ -155,11 +204,15 @@
 
                         if (isUsingScreenShot()) {
                             startTouchTrackingForScreenshotAnimation();
+                        } else if (mDownHitTarget == HIT_TARGET_BACK) {
+                            // If we deferred starting the window animation on touch down, then
+                            // start tracking now
+                            startTouchTrackingForWindowAnimation(ev.getEventTime());
                         }
 
                         notifyGestureStarted();
                     }
-                } else {
+                } else if (mInteractionHandler != null) {
                     // Move
                     mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
                 }
@@ -177,6 +230,9 @@
     }
 
     private void notifyGestureStarted() {
+        if (mInteractionHandler == null) {
+            return;
+        }
         // Notify the handler that the gesture has actually started
         mInteractionHandler.onGestureStarted();
 
@@ -195,7 +251,7 @@
     }
 
     private boolean isUsingScreenShot() {
-        return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_animation", true);
+        return Utilities.getPrefs(this).getBoolean("pref_use_screenshot_for_swipe_up", false);
     }
 
     /**
@@ -222,7 +278,7 @@
         // Preload the plan
         mRecentsModel.loadTasks(mRunningTask.id, null);
         mInteractionHandler = handler;
-        mInteractionHandler.setGestureEndCallback(this::onFinish);
+        mInteractionHandler.setGestureEndCallback(mEventQueue::reset);
     }
 
     private Bitmap getCurrentTaskSnapshot() {
@@ -253,7 +309,7 @@
         }
     }
 
-    private void startTouchTrackingForWindowAnimation() {
+    private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
         // Create the shared handler
         final WindowTransformSwipeHandler handler =
                 new WindowTransformSwipeHandler(mRunningTask, this);
@@ -261,7 +317,7 @@
         // 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(() -> {
@@ -270,14 +326,15 @@
                 switchToMainChoreographer();
             }
         });
-        handler.initWhenReady(mMainThreadExecutor);
+        handler.initWhenReady();
 
+        TraceHelper.beginSection("RecentsController");
         Runnable startActivity = () -> ActivityManagerWrapper.getInstance()
                 .startRecentsActivity(mHomeIntent,
                 new AssistDataReceiver() {
                     @Override
                     public void onHandleAssistData(Bundle bundle) {
-                        // Pass to AIAI
+                        mRecentsModel.preloadAssistData(mRunningTask.id, bundle);
                     }
                 },
                 new RecentsAnimationListener() {
@@ -286,16 +343,30 @@
                             RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
                             Rect minimizedHomeBounds) {
                         if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(controller, apps, homeContentInsets,
+                            TraceHelper.partitionSection("RecentsController", "Received");
+                            handler.onRecentsAnimationStart(controller, apps, homeContentInsets,
                                     minimizedHomeBounds);
                         } else {
+                            TraceHelper.endSection("RecentsController", "Finishing no handler");
                             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() {
+                        TraceHelper.endSection("RecentsController",
+                                "Cancelled: " + mInteractionHandler);
                         if (mInteractionHandler == handler) {
-                            handler.setRecentsAnimation(null, null, null, null);
+                            handler.onRecentsAnimationCanceled();
                         }
                     }
                 }, null, null);
@@ -319,7 +390,7 @@
      * the animation can still be running.
      */
     private void finishTouchTracking() {
-        if (mTouchThresholdCrossed) {
+        if (mTouchThresholdCrossed && mInteractionHandler != null) {
             mVelocityTracker.computeCurrentVelocity(1000,
                     ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
 
@@ -331,11 +402,13 @@
             // 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();
         }
         mVelocityTracker.recycle();
         mVelocityTracker = null;
-
-        onTouchTrackingComplete();
     }
 
     @Override
@@ -343,8 +416,8 @@
         // Clean up the old interaction handler
         if (mInteractionHandler != null) {
             final BaseSwipeInteractionHandler handler = mInteractionHandler;
-            mMainThreadExecutor.execute(handler::reset);
             mInteractionHandler = null;
+            mMainThreadExecutor.execute(handler::reset);
         }
     }
 
@@ -352,16 +425,23 @@
     public void updateTouchTracking(int interactionType) {
         notifyGestureStarted();
 
-        mMainThreadExecutor.execute(() -> {
+        if (isUsingScreenShot()) {
+            mMainThreadExecutor.execute(() -> {
+                if (mInteractionHandler != null) {
+                    mInteractionHandler.updateInteractionType(interactionType);
+                }
+            });
+        } else {
             if (mInteractionHandler != null) {
                 mInteractionHandler.updateInteractionType(interactionType);
             }
-        });
+        }
     }
 
     @Override
-    public boolean shouldUseBackgroundConsumer() {
-        return !isUsingScreenShot();
+    public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+        mEventQueue = queue;
+        return isUsingScreenShot() ? null : mBackgroundThreadChoreographer;
     }
 
     @Override
@@ -378,14 +458,10 @@
         }
     }
 
-    private void onFinish() {
-        mInteractionHandler = null;
+    public void switchToMainChoreographer() {
+        mEventQueue.setInterimChoreographer(null);
     }
 
-    public void onTouchTrackingComplete() { }
-
-    public void switchToMainChoreographer() { }
-
     @Override
     public void preProcessMotionEvent(MotionEvent ev) {
         if (mVelocityTracker != null) {
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
new file mode 100644
index 0000000..3c68281
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.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.quickstep;
+
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.launcher3.util.UiThreadHelper;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+
+/**
+ * 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.
+ */
+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 int sFlags;
+
+    public static void setBackButtonVisible(Context context, boolean visible) {
+        updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
+    }
+
+    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 void updateOverviewInteractionFlag(Context context, int flag, boolean enabled) {
+        if (enabled) {
+            sFlags |= flag;
+        } else {
+            sFlags &= ~flag;
+        }
+
+        ISystemUiProxy systemUiProxy = RecentsModel.getInstance(context).getSystemUiProxy();
+        if (systemUiProxy == null) {
+            Log.w(TAG, "Unable to update overview interaction flags; not bound to service");
+            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));
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index d1ce820..f28d51c 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -21,6 +21,11 @@
 import com.android.launcher3.Alarm;
 import com.android.launcher3.Launcher;
 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.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
 
 /**
  * Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -30,52 +35,67 @@
  */
 public class QuickScrubController implements OnAlarmListener {
 
-    private static final int NUM_QUICK_SCRUB_SECTIONS = 5;
+    public static final int QUICK_SWITCH_START_DURATION = 133;
+    public static final int QUICK_SWITCH_SNAP_DURATION = 120;
+
+    private static final boolean ENABLE_AUTO_ADVANCE = true;
+    private static final int NUM_QUICK_SCRUB_SECTIONS = 3;
+    private static final long INITIAL_AUTO_ADVANCE_DELAY = 1000;
     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 Launcher mLauncher;
-    private Alarm mAutoAdvanceAlarm;
-    private RecentsView mRecentsView;
+    private final Alarm mAutoAdvanceAlarm;
+    private final RecentsView mRecentsView;
+    private final Launcher mLauncher;
 
+    private boolean mInQuickScrub;
     private int mQuickScrubSection;
     private int mStartPage;
+    private boolean mHasAlarmRun;
 
-    public QuickScrubController(Launcher launcher) {
+    public QuickScrubController(Launcher launcher, RecentsView recentsView) {
         mLauncher = launcher;
-        mAutoAdvanceAlarm = new Alarm();
-        mAutoAdvanceAlarm.setOnAlarmListener(this);
+        mRecentsView = recentsView;
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm = new Alarm();
+            mAutoAdvanceAlarm.setOnAlarmListener(this);
+        }
     }
 
     public void onQuickScrubStart(boolean startingFromHome) {
-        mRecentsView = mLauncher.getOverviewPanel();
+        mInQuickScrub = true;
         mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
         mQuickScrubSection = 0;
+        mHasAlarmRun = false;
+        mLauncher.getUserEventDispatcher().resetActionDurationMillis();
     }
 
     public void onQuickScrubEnd() {
-        mAutoAdvanceAlarm.cancelAlarm();
-        if (mRecentsView == null) {
-        } else {
-            int page = mRecentsView.getNextPage();
-            Runnable launchTaskRunnable = () -> {
-                if (page < mRecentsView.getFirstTaskIndex()) {
-                    mRecentsView.getPageAt(page).performClick();
-                } else {
-                    ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
-                }
-            };
-            int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
-                    * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
-            if (mRecentsView.snapToPage(page, snapDuration)) {
-                // Settle on the page then launch it
-                mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
-            } else {
-                // No page move needed, just launch it
-                launchTaskRunnable.run();
-            }
+        mInQuickScrub = false;
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm.cancelAlarm();
         }
+        int page = mRecentsView.getNextPage();
+        Runnable launchTaskRunnable = () -> {
+            if (page < mRecentsView.getFirstTaskIndex()) {
+                mRecentsView.getPageAt(page).performClick();
+            } else {
+                ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
+            }
+        };
+        int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
+                * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
+        if (mRecentsView.snapToPage(page, snapDuration)) {
+            // Settle on the page then launch it
+            mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
+        } else {
+            // No page move needed, just launch it
+            launchTaskRunnable.run();
+        }
+        mLauncher.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
+                ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+                        ContainerType.WORKSPACE : ContainerType.APP);
     }
 
     public void onQuickScrubProgress(float progress) {
@@ -83,20 +103,46 @@
         if (quickScrubSection != mQuickScrubSection) {
             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 (ENABLE_AUTO_ADVANCE) {
+                if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
+                    mAutoAdvanceAlarm.setAlarm(mHasAlarmRun
+                            ? AUTO_ADVANCE_DELAY : INITIAL_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;
+            }
+        }
+        mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
+                ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+                        ContainerType.WORKSPACE : ContainerType.APP);
+    }
+
     public void snapToPageForCurrentQuickScrubSection() {
-        goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+        if (mInQuickScrub) {
+            goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+        }
     }
 
     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;
@@ -115,6 +161,9 @@
         } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
             goToPageWithHaptic(currPage - 1);
         }
-        mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+        mHasAlarmRun = true;
+        if (ENABLE_AUTO_ADVANCE) {
+            mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
index 9cc038f..1f9c728 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
@@ -53,12 +53,15 @@
     private Rect mTaskInsets;
     private Rect mThumbnail;
 
-    private float mTaskScale;
+    private float mInitialTaskScale;
+    private float mInitialTaskTranslationX;
+    private float mFinalTaskScale;
     private Rect mScaledTask;
     private Rect mTargetTask;
     private Rect mSrcWindow;
 
-    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets) {
+    public RecentsAnimationInterpolator(Rect window, Rect insets, Rect task, Rect taskInsets,
+            float taskScale, float taskTranslationX) {
         mWindow = window;
         mInsets = insets;
         mTask = task;
@@ -68,16 +71,18 @@
 
         mThumbnail = new Rect(task);
         Utilities.insetRect(mThumbnail, taskInsets);
-        mTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
+        mInitialTaskScale = taskScale;
+        mInitialTaskTranslationX = taskTranslationX;
+        mFinalTaskScale = (float) mInsetWindow.width() / mThumbnail.width();
         mScaledTask = new Rect(task);
-        Utilities.scaleRectAboutCenter(mScaledTask, mTaskScale);
+        Utilities.scaleRectAboutCenter(mScaledTask, mFinalTaskScale);
         Rect finalScaledTaskInsets = new Rect(taskInsets);
-        Utilities.scaleRect(finalScaledTaskInsets, mTaskScale);
+        Utilities.scaleRect(finalScaledTaskInsets, mFinalTaskScale);
         mTargetTask = new Rect(mInsetWindow);
         mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top,
                 window.left + insets.left - finalScaledTaskInsets.left);
 
-        float initialWinScale = 1f / mTaskScale;
+        float initialWinScale = 1f / mFinalTaskScale;
         Rect scaledWindow = new Rect(mInsetWindow);
         Utilities.scaleRectAboutCenter(scaledWindow, initialWinScale);
         Rect scaledInsets = new Rect(insets);
@@ -89,13 +94,14 @@
 
     public TaskWindowBounds interpolate(float t) {
         mTmpTaskWindowBounds.taskScale = Utilities.mapRange(t,
-                1, (float) mInsetWindow.width() / mThumbnail.width());
+                mInitialTaskScale, mFinalTaskScale);
         mTmpTaskWindowBounds.taskX = Utilities.mapRange(t,
-                0, mTargetTask.left - mScaledTask.left);
+                mInitialTaskTranslationX, mTargetTask.left - mScaledTask.left);
         mTmpTaskWindowBounds.taskY = Utilities.mapRange(t,
                 0, mTargetTask.top - mScaledTask.top);
 
-        mTmpTaskWindowBounds.winScale = mTmpTaskWindowBounds.taskScale / mTaskScale;
+        float taskScale = Utilities.mapRange(t, 1, mFinalTaskScale);
+        mTmpTaskWindowBounds.winScale = taskScale / mFinalTaskScale;
         mTmpTaskWindowBounds.winX = Utilities.mapRange(t,
                 mSrcWindow.left, 0);
         mTmpTaskWindowBounds.winY = Utilities.mapRange(t,
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 7c98317..4e11220 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -15,6 +15,7 @@
  */
 package com.android.quickstep;
 
+import com.android.launcher3.util.TraceHelper;
 import com.android.systemui.shared.system.BackgroundExecutor;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -31,6 +32,7 @@
 
     public synchronized void setController(
             RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
+        TraceHelper.partitionSection("RecentsController", "Set controller " + controller);
         this.controller = controller;
         this.targets = targets;
 
@@ -39,12 +41,21 @@
         }
     }
 
-    public void finish(boolean toHome) {
+    /**
+     * @param onFinishComplete A callback that runs after the animation controller has finished
+     *                         on the background thread.
+     */
+    public void finish(boolean toHome, Runnable onFinishComplete) {
         BackgroundExecutor.get().submit(() -> {
             synchronized (this) {
+                TraceHelper.endSection("RecentsController",
+                        "Finish " + controller + ", toHome=" + toHome);
                 if (controller != null) {
                     controller.setInputConsumerEnabled(false);
                     controller.finish(toHome);
+                    if (onFinishComplete != null) {
+                        onFinishComplete.run();
+                    }
                 }
             }
         });
@@ -55,6 +66,8 @@
         if (mInputConsumerEnabled) {
             BackgroundExecutor.get().submit(() -> {
                 synchronized (this) {
+                    TraceHelper.partitionSection("RecentsController",
+                            "Enabling consumer on " + controller);
                     if (controller != null) {
                         controller.setInputConsumerEnabled(true);
                     }
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index d10c5a6..7fe7751 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -16,22 +16,33 @@
 package com.android.quickstep;
 
 import android.annotation.TargetApi;
+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.UserHandle;
+import android.support.annotation.WorkerThread;
+import android.util.LruCache;
+import android.util.SparseArray;
 
 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;
 
@@ -60,6 +71,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,6 +82,7 @@
     private int mLastLoadPlanId;
     private int mTaskChangeId;
     private ISystemUiProxy mSystemUiProxy;
+    private boolean mClearAssistCacheOnStackChange = true;
 
     private RecentsModel(Context context) {
         mContext = context;
@@ -75,7 +90,15 @@
         Resources res = context.getResources();
         mRecentsTaskLoader = new RecentsTaskLoader(mContext,
                 res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize),
-                res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0);
+                res.getInteger(R.integer.config_recentsMaxIconCacheSize), 0) {
+
+            @Override
+            protected IconLoader createNewIconLoader(Context context,
+                    TaskKeyLruCache<Drawable> iconCache,
+                    LruCache<ComponentName, ActivityInfo> activityInfoCache) {
+                return new NormalizedIconLoader(context, iconCache, activityInfoCache);
+            }
+        };
         mRecentsTaskLoader.startLoader(mContext);
 
         mMainThreadExecutor = new MainThreadExecutor();
@@ -130,6 +153,13 @@
     @Override
     public void onTaskStackChanged() {
         mTaskChangeId++;
+
+        Preconditions.assertUIThread();
+        if (mClearAssistCacheOnStackChange) {
+            mCachedAssistData.clear();
+        } else {
+            mClearAssistCacheOnStackChange = true;
+        }
     }
 
     public boolean isLoadPlanValid(int resultId) {
@@ -147,4 +177,40 @@
     public ISystemUiProxy getSystemUiProxy() {
         return mSystemUiProxy;
     }
+
+    @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
index 343922c..ec0716c 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -16,6 +16,11 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.TaskView.CURVE_FACTOR;
+import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
+
 import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -54,10 +59,6 @@
 
 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.
  */
@@ -108,6 +109,8 @@
     private Matrix mFadeMatrix;
     private boolean mScrimOnLeft;
 
+    private boolean mFirstTaskIconScaledDown = false;
+
     public RecentsView(Context context) {
         this(context, null);
     }
@@ -124,21 +127,22 @@
         setClipToOutline(true);
 
         mLauncher = Launcher.getLauncher(context);
-        mQuickScrubController = new QuickScrubController(mLauncher);
+        mQuickScrubController = new QuickScrubController(mLauncher, this);
         mModel = RecentsModel.getInstance(context);
 
         mScrollState.isRtl = mIsRtl;
     }
 
-    public void updateThumbnail(int taskId, ThumbnailData thumbnailData) {
+    public TaskView 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;
+                return taskView;
             }
         }
+        return null;
     }
 
     private void setupLayoutTransition() {
@@ -218,8 +222,8 @@
     }
 
     public boolean isTaskViewVisible(TaskView tv) {
-        // For now, just check if it's the active task
-        return indexOfChild(tv) == getNextPage();
+        // 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) {
@@ -266,6 +270,8 @@
             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());
@@ -289,13 +295,15 @@
             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);
+            taskView.resetVisualProperties();
             loader.loadTaskData(task);
         }
+        updateCurveProperties();
+        applyIconScale(false /* animate */);
+
+        if (oldChildCount != getChildCount()) {
+            mQuickScrubController.snapToPageForCurrentQuickScrubSection();
+        }
     }
 
     private void updateTaskStackListenerState() {
@@ -392,7 +400,7 @@
     /**
      * Scales and adjusts translation of adjacent pages as if on a curved carousel.
      */
-    private void updateCurveProperties() {
+    public void updateCurveProperties() {
         if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
             return;
         }
@@ -431,6 +439,10 @@
         return getChildCount() - mFirstTaskIndex;
     }
 
+    public int getRunningTaskId() {
+        return mRunningTaskId;
+    }
+
     /**
      * Reloads the view if anything in recents changed.
      */
@@ -468,9 +480,7 @@
         mRunningTaskId = runningTaskId;
         setCurrentPage(mFirstTaskIndex);
         if (mCurrentPage >= mFirstTaskIndex) {
-            TaskView currentTask = (TaskView) getPageAt(mCurrentPage);
-            currentTask.setIconScale(0);
-            currentTask.setAlpha(0);
+            getPageAt(mCurrentPage).setAlpha(0);
         }
     }
 
@@ -478,6 +488,26 @@
         return mQuickScrubController;
     }
 
+    public void setFirstTaskIconScaledDown(boolean isScaledDown, boolean animate) {
+        if (mFirstTaskIconScaledDown == isScaledDown) {
+            return;
+        }
+        mFirstTaskIconScaledDown = isScaledDown;
+        applyIconScale(animate);
+    }
+
+    private void applyIconScale(boolean animate) {
+        float scale = mFirstTaskIconScaledDown ? 0 : 1;
+        TaskView firstTask = (TaskView) getChildAt(mFirstTaskIndex);
+        if (firstTask != null) {
+            if (animate) {
+                firstTask.animateIconToScale(scale);
+            } else {
+                firstTask.setIconScale(scale);
+            }
+        }
+    }
+
     @Override
     public void draw(Canvas canvas) {
         if (mScrim == null) {
diff --git a/quickstep/src/com/android/quickstep/TaskMenuView.java b/quickstep/src/com/android/quickstep/TaskMenuView.java
index 52b2400..6bbcb37 100644
--- a/quickstep/src/com/android/quickstep/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/TaskMenuView.java
@@ -144,6 +144,7 @@
         icon.setBounds(0, 0, iconSize, iconSize);
         mTaskIconAndName.setCompoundDrawables(null, icon, null, null);
         mTaskIconAndName.setText(TaskUtils.getTitle(mLauncher, taskView.getTask()));
+        mTaskIconAndName.setOnClickListener(v -> close(true));
 
         for (TaskSystemShortcut menuOption : MENU_OPTIONS) {
             OnClickListener onClickListener = menuOption.getOnClickListener(mLauncher, taskView);
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index c2fb7be..66969c6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Preconditions;
+import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 /**
@@ -47,7 +48,7 @@
 
     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..75d8619 100644
--- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
+++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java
@@ -23,7 +23,6 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 
@@ -98,11 +97,14 @@
 
         @Override
         public View.OnClickListener getOnClickListener(Launcher launcher, TaskView taskView) {
-            if (launcher.getDeviceProfile().inMultiWindowMode()) {
+            if (launcher.getDeviceProfile().isMultiWindowMode) {
+                return null;
+            }
+            final Task task  = taskView.getTask();
+            if (!task.isDockable) {
                 return null;
             }
             return (v -> {
-                Task task  = taskView.getTask();
                 final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true);
                 final Consumer<Boolean> resultCallback = success -> {
                     if (success) {
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
index 4f93b1c..9b9c6f2 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -55,6 +55,7 @@
 
     private final Matrix mMatrix = new Matrix();
 
+    private Task mTask;
     private ThumbnailData mThumbnailData;
     protected BitmapShader mBitmapShader;
 
@@ -83,6 +84,7 @@
      * Updates this thumbnail.
      */
     public void setThumbnail(Task task, ThumbnailData thumbnailData) {
+        mTask = task;
         mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000);
 
         if (thumbnailData != null && thumbnailData.thumbnail != null) {
@@ -189,7 +191,7 @@
             mPaint.setShader(shader);
         }
 
-        mOverlay.setTaskInfo(mThumbnailData, mMatrix);
+        mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix);
         invalidate();
     }
 
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index 8865a42..b407f75 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -19,34 +19,27 @@
 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.Launcher;
 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;
 
 /**
@@ -68,23 +61,9 @@
 
     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);
@@ -136,26 +115,7 @@
         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);
+                opts = Launcher.getLauncher(getContext()).getActivityLaunchOptions(this, false);
             } else {
                 opts = ActivityOptions.makeCustomAnimation(getContext(), 0, 0);
             }
@@ -185,16 +145,21 @@
     }
 
     public void animateIconToScale(float scale) {
-        ObjectAnimator.ofFloat(this, SCALE_ICON_PROPERTY, scale)
-                .setDuration(SCALE_ICON_DURATION).start();
+        mIconView.animate().scaleX(scale).scaleY(scale).setDuration(SCALE_ICON_DURATION).start();
     }
 
     protected void setIconScale(float iconScale) {
-        mIconScale = iconScale;
-        if (mIconView != null) {
-            mIconView.setScaleX(mIconScale);
-            mIconView.setScaleY(mIconScale);
-        }
+        mIconView.animate().cancel();
+        mIconView.setScaleX(iconScale);
+        mIconView.setScaleY(iconScale);
+    }
+
+    public void resetVisualProperties() {
+        setScaleX(1f);
+        setScaleY(1f);
+        setTranslationX(0f);
+        setTranslationY(0f);
+        setAlpha(1f);
     }
 
     @Override
@@ -228,7 +193,6 @@
         return SCROLL_TYPE_TASK;
     }
 
-
     private static final class TaskOutlineProvider extends ViewOutlineProvider {
 
         private final int mMarginTop;
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index 77480af..f35f6a6 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -18,8 +18,11 @@
 import android.annotation.TargetApi;
 import android.os.Build;
 import android.support.annotation.IntDef;
+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;
@@ -46,10 +49,6 @@
 
     default void reset() { }
 
-    default boolean shouldUseBackgroundConsumer() {
-        return false;
-    }
-
     default void updateTouchTracking(@InteractionType int interactionType) { }
 
     default void onQuickScrubEnd() { }
@@ -61,4 +60,8 @@
      * posted on a handler thread.
      */
     default void preProcessMotionEvent(MotionEvent ev) { }
+
+    default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+        return null;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5e89644..c166292 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,9 +21,8 @@
 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.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
-import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
 
 import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
@@ -36,7 +35,9 @@
 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;
@@ -45,11 +46,13 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.model.ModelPreload;
 import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.util.TraceHelper;
 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.NavigationBarCompat.HitTarget;
 
 /**
  * Service connected by system-UI for handling touch interaction.
@@ -57,6 +60,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";
@@ -69,8 +81,20 @@
     private final IBinder mMyBinder = new IOverviewProxy.Stub() {
 
         @Override
+        public void onPreMotionEvent(@HitTarget int downHitTarget) throws RemoteException {
+            TraceHelper.beginSection("SysUiBinder");
+            onBinderPreMotionEvent(downHitTarget);
+            TraceHelper.partitionSection("SysUiBinder", "Down target " + downHitTarget);
+        }
+
+        @Override
         public void onMotionEvent(MotionEvent ev) {
-            onBinderMotionEvent(ev);
+            mEventQueue.queue(ev);
+
+            String name = sMotionEventNames.get(ev.getActionMasked());
+            if (name != null){
+                TraceHelper.partitionSection("SysUiBinder", name);
+            }
         }
 
         @Override
@@ -79,33 +103,38 @@
             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() {
-            mCurrentConsumer.updateTouchTracking(INTERACTION_QUICK_SWITCH);
+            mEventQueue.onQuickSwitch();
+            TraceHelper.endSection("SysUiBinder", "onQuickSwitch");
         }
 
         @Override
         public void onQuickScrubStart() {
-            mCurrentConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
+            mEventQueue.onQuickScrubStart();
             sQuickScrubEnabled = true;
-        }
-
-        @Override
-        public void onQuickScrubEnd() {
-            mCurrentConsumer.onQuickScrubEnd();
-            sQuickScrubEnabled = false;
+            TraceHelper.partitionSection("SysUiBinder", "onQuickScrubStart");
         }
 
         @Override
         public void onQuickScrubProgress(float progress) {
-            mCurrentConsumer.onQuickScrubProgress(progress);
+            mEventQueue.onQuickScrubProgress(progress);
+        }
+
+        @Override
+        public void onQuickScrubEnd() {
+            mEventQueue.onQuickScrubEnd();
+            TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
+            sQuickScrubEnabled = false;
         }
     };
 
     private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
-    private TouchConsumer mCurrentConsumer = mNoOpTouchConsumer;
 
     private static boolean sConnected = false;
     private static boolean sQuickScrubEnabled = false;
@@ -126,7 +155,10 @@
     private MotionEventQueue mEventQueue;
     private MainThreadExecutor mMainThreadExecutor;
     private ISystemUiProxy mISystemUiProxy;
+
+    private Choreographer mMainThreadChoreographer;
     private Choreographer mBackgroundThreadChoreographer;
+    private MotionEventQueue mNoOpEventQueue;
 
     @Override
     public void onCreate() {
@@ -144,10 +176,14 @@
         // Clear the packageName as system can fail to dedupe it b/64108432
         mHomeIntent.setComponent(mLauncher).setPackage(null);
 
-        mEventQueue = new MotionEventQueue(Choreographer.getInstance(), mNoOpTouchConsumer);
+        mMainThreadChoreographer = Choreographer.getInstance();
+        mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
+        mEventQueue = mNoOpEventQueue;
+
         sConnected = true;
 
-        new ModelPreload().start(this);
+        // Temporarily disable model preload
+        // new ModelPreload().start(this);
         initBackgroundChoreographer();
     }
 
@@ -164,89 +200,72 @@
         return mMyBinder;
     }
 
-    private void onBinderMotionEvent(MotionEvent ev) {
-        if (ev.getActionMasked() == ACTION_DOWN) {
-            mRunningTask = mAM.getRunningTask();
+    private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
+        mRunningTask = mAM.getRunningTask();
 
-            mCurrentConsumer.reset();
-            if (mRunningTask == null) {
-                mCurrentConsumer = mNoOpTouchConsumer;
-            } else if (mRunningTask.topActivity.equals(mLauncher)) {
-                mCurrentConsumer = getLauncherConsumer();
-            } else {
-                mCurrentConsumer = getOtherActivityConsumer();
-            }
+        mEventQueue.reset();
 
-            mEventQueue.setConsumer(mCurrentConsumer);
-            mEventQueue.setInterimChoreographer(mCurrentConsumer.shouldUseBackgroundConsumer()
-                    ? mBackgroundThreadChoreographer : null);
+        if (mRunningTask == null) {
+            mEventQueue = mNoOpEventQueue;
+        } else if (mRunningTask.topActivity.equals(mLauncher)) {
+            mEventQueue = getLauncherEventQueue();
+        } else {
+            mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
+                    new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
+                    mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
+                    mBackgroundThreadChoreographer, downHitTarget));
         }
-        mCurrentConsumer.preProcessMotionEvent(ev);
-        mEventQueue.queue(ev);
     }
 
-    private TouchConsumer getOtherActivityConsumer() {
-        TouchConsumer consumer = new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
-                mHomeIntent, mISystemUiProxy, mMainThreadExecutor) {
-
-            @Override
-            public void switchToMainChoreographer() {
-                if (mCurrentConsumer == this) {
-                    mEventQueue.setInterimChoreographer(null);
-                }
-            }
-
-            @Override
-            public void onTouchTrackingComplete() {
-                if (mCurrentConsumer == this) {
-                    mCurrentConsumer = mNoOpTouchConsumer;
-                    mEventQueue.setConsumer(mCurrentConsumer);
-                }
-            }
-        };
-        return consumer;
-    }
-
-    private TouchConsumer getLauncherConsumer() {
-
+    private MotionEventQueue getLauncherEventQueue() {
         Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
         if (launcher == null) {
-            return mNoOpTouchConsumer;
+            return mNoOpEventQueue;
         }
 
         View target = launcher.getDragLayer();
-        if (!target.getWindowId().isFocused()) {
-            return mNoOpTouchConsumer;
-        }
-        return new LauncherTouchConsumer(target);
+        return new MotionEventQueue(mMainThreadChoreographer,
+                new LauncherTouchConsumer(launcher, target));
     }
 
-    private class LauncherTouchConsumer implements TouchConsumer {
+    private static class LauncherTouchConsumer implements TouchConsumer {
 
+        private final Launcher mLauncher;
         private final View mTarget;
         private final int[] mLocationOnScreen = new int[2];
         private final PointF mDownPos = new PointF();
         private final int mTouchSlop;
+        private final QuickScrubController mQuickScrubController;
 
         private boolean mTrackingStarted = false;
+        private boolean mInvalidated = false;
+        private boolean mHadWindowFocusOnDown;
 
-        LauncherTouchConsumer(View target) {
+        LauncherTouchConsumer(Launcher launcher, View target) {
+            mLauncher = launcher;
             mTarget = target;
             mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+
+            mQuickScrubController = mLauncher.<RecentsView>getOverviewPanel()
+                    .getQuickScrubController();
         }
 
         @Override
         public void accept(MotionEvent ev) {
+            if (mInvalidated) {
+                return;
+            }
             int action = ev.getActionMasked();
             if (action == ACTION_DOWN) {
                 mTrackingStarted = false;
                 mDownPos.set(ev.getX(), ev.getY());
-            } else if (!mTrackingStarted) {
+                mHadWindowFocusOnDown = mTarget.hasWindowFocus();
+            } else if (!mTrackingStarted && mHadWindowFocusOnDown) {
                 switch (action) {
                     case ACTION_POINTER_UP:
                     case ACTION_POINTER_DOWN:
                         if (!mTrackingStarted) {
-                            mEventQueue.setConsumer(mNoOpTouchConsumer);
+                            mInvalidated = true;
                         }
                         break;
                     case ACTION_MOVE: {
@@ -270,7 +289,7 @@
             }
 
             if (action == ACTION_UP || action == ACTION_CANCEL) {
-                mEventQueue.setConsumer(mNoOpTouchConsumer);
+                mInvalidated = true;
             }
         }
 
@@ -282,6 +301,47 @@
             ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
             ev.setEdgeFlags(flags);
         }
+
+        @Override
+        public void updateTouchTracking(int interactionType) {
+            if (mInvalidated) {
+                return;
+            }
+            if (TouchConsumer.isInteractionQuick(interactionType)) {
+                Runnable action = () -> {
+                    Runnable onComplete = null;
+                    if (interactionType == INTERACTION_QUICK_SCRUB) {
+                        mQuickScrubController.onQuickScrubStart(true);
+                    } else if (interactionType == INTERACTION_QUICK_SWITCH) {
+                        onComplete = mQuickScrubController::onQuickSwitch;
+                    }
+                    mLauncher.getStateManager().goToState(OVERVIEW, true, 0,
+                            QUICK_SWITCH_START_DURATION, onComplete);
+                };
+
+                if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
+                    // Hide the minus one overlay so launcher can get window focus.
+                    mLauncher.onQuickstepGestureStarted(true);
+                }
+            }
+        }
+
+        @Override
+        public void onQuickScrubEnd() {
+            if (mInvalidated) {
+                return;
+            }
+            mQuickScrubController.onQuickScrubEnd();
+        }
+
+        @Override
+        public void onQuickScrubProgress(float progress) {
+            if (mInvalidated) {
+                return;
+            }
+            mQuickScrubController.onQuickScrubProgress(progress);
+        }
+
     }
 
     private void initBackgroundChoreographer() {
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 7247af4..19942c3 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -18,6 +18,7 @@
 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.quickstep.QuickScrubController.QUICK_SWITCH_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;
@@ -28,14 +29,16 @@
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 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.Matrix.ScaleToFit;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
@@ -57,10 +60,16 @@
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.util.Preconditions;
+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.TraceHelper;
+import com.android.launcher3.util.ViewOnDrawExecutor;
 import com.android.quickstep.TouchConsumer.InteractionType;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.RectFEvaluator;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.TransactionCompat;
@@ -75,38 +84,51 @@
 
     // 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 = 1 << 8;
+    private static final int STATE_GESTURE_CANCELLED = 1 << 9;
+
+    // States for quick switch/scrub
+    private static final int STATE_SWITCH_TO_SCREENSHOT_COMPLETE = 1 << 10;
+    private static final int STATE_QUICK_SWITCH = 1 << 11;
+    private static final int STATE_QUICK_SCRUB_START = 1 << 12;
+    private static final int STATE_QUICK_SCRUB_END = 1 << 13;
 
     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;
 
     // 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_GESTURE_STARTED",
+            "STATE_GESTURE_CANCELLED",
+            "STATE_SWITCH_TO_SCREENSHOT_COMPLETE",
+            "STATE_QUICK_SWITCH",
+            "STATE_QUICK_SCRUB_START",
+            "STATE_QUICK_SCRUB_END"
     };
 
     private static final long MAX_SWIPE_DURATION = 200;
     private static final long MIN_SWIPE_DURATION = 80;
-    private static final int QUICK_SWITCH_START_DURATION = 133;
-    private static final int QUICK_SWITCH_SNAP_DURATION = 120;
 
     private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
 
@@ -115,22 +137,21 @@
     // 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();
+    private final RectF mSourceRect = new RectF();
+    // The bounds of the task view in launcher window coordinates
+    private final RectF mTargetRect = new RectF();
+    // Doesn't change after initialized, used as an anchor when changing mTargetRect
+    private final RectF mInitialTargetRect = new RectF();
     // 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();
+    private final RectF mSourceWindowClipInsets = new RectF();
+
     // 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 RectFEvaluator mRectFEvaluator = new RectFEvaluator();
     private DeviceProfile mDp;
     private int mTransitionDragLength;
 
@@ -159,10 +180,12 @@
 
     private float mCurrentDisplacement;
     private boolean mGestureStarted;
+    private int mLogAction = Touch.SWIPE;
 
     private @InteractionType int mInteractionType = INTERACTION_NORMAL;
-    private boolean mStartedQuickScrubFromHome;
-    private boolean mDeferredQuickScrubEnd;
+
+    private InputConsumerController mInputConsumer =
+            InputConsumerController.getRecentsAnimationInputConsumer();
 
     private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
     private Matrix mTmpMatrix = new Matrix();
@@ -170,6 +193,7 @@
     WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) {
         mContext = context;
         mRunningTaskId = runningTaskInfo.id;
+        mInputConsumer.registerInputConsumer();
         initStateCallbacks();
     }
 
@@ -181,32 +205,46 @@
                 super.setState(stateFlag);
             }
         };
+
         mStateCallback.addCallback(STATE_LAUNCHER_DRAWN | STATE_GESTURE_STARTED,
                 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_LAUNCHER_PRESENT | STATE_LAUNCHER_STARTED
+                        | STATE_GESTURE_CANCELLED,
+                this::resetStateForAnimationCancel);
 
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_APP | STATE_APP_CONTROLLER_RECEIVED,
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+                        | STATE_SCALED_CONTROLLER_APP,
                 this::resumeLastTask);
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
                         | STATE_ACTIVITY_MULTIPLIER_COMPLETE
-                        | STATE_APP_CONTROLLER_RECEIVED,
+                        | STATE_SCALED_CONTROLLER_RECENTS,
                 this::switchToScreenshot);
-
-        mStateCallback.addCallback(STATE_SCALED_CONTROLLER_RECENTS
-                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE,
+        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED
+                        | STATE_ACTIVITY_MULTIPLIER_COMPLETE
+                        | STATE_SCALED_CONTROLLER_RECENTS
+                        | STATE_SWITCH_TO_SCREENSHOT_COMPLETE,
                 this::setupLauncherUiAfterSwipeUpAnimation);
 
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_APP,
                 this::reset);
-        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SCALED_CONTROLLER_RECENTS,
-                this::reset);
 
         mStateCallback.addCallback(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
         mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                 this::invalidateHandlerWithLauncher);
+
+        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
+                | STATE_QUICK_SCRUB_END, this::switchToFinalAppAfterQuickScrub);
     }
 
     private void setStateOnUiThread(int stateFlag) {
@@ -220,10 +258,14 @@
 
     private void initTransitionEndpoints(DeviceProfile dp) {
         mDp = dp;
+        mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
+                mSourceStackBounds.width() - mSourceInsets.right,
+                mSourceStackBounds.height() - mSourceInsets.bottom);
 
-        mSourceRect.set(0, 0, dp.widthPx - mSourceInsets.left - mSourceInsets.right,
-                dp.heightPx - mSourceInsets.top - mSourceInsets.bottom);
-        RecentsView.getPageRect(dp, mContext, mTargetRect);
+        Rect tempRect = new Rect();
+        RecentsView.getPageRect(dp, mContext, tempRect);
+
+        mTargetRect.set(tempRect);
         mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
                 mHomeStackBounds.top - mSourceStackBounds.top);
         mInitialTargetRect.set(mTargetRect);
@@ -232,21 +274,23 @@
         // 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);
+        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);
 
         Rect targetInsets = dp.getInsets();
-        mTransitionDragLength = dp.hotseatBarSizePx;
         if (dp.isVerticalBarLayout()) {
             int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
-            mTransitionDragLength += dp.hotseatBarSidePaddingPx + hotseatInset;
+            mTransitionDragLength = dp.hotseatBarSizePx + dp.hotseatBarSidePaddingPx + hotseatInset;
         } else {
-            mTransitionDragLength += targetInsets.bottom;
+            mTransitionDragLength = dp.heightPx - tempRect.bottom;
         }
     }
 
@@ -277,35 +321,56 @@
         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);
+        mRecentsView = mLauncher.getOverviewPanel();
+        mQuickScrubController = mRecentsView.getQuickScrubController();
+        mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
+
+        mStateCallback.setState(STATE_LAUNCHER_PRESENT);
+        if (alreadyOnHome) {
+            onLauncherStart(launcher);
+        } else {
+            launcher.setOnStartCallback(this::onLauncherStart);
+        }
+        return true;
+    }
+
+    private void onLauncherStart(final Launcher launcher) {
+        if (mLauncher != launcher) {
+            return;
+        }
+        if ((mStateCallback.getState() & STATE_HANDLER_INVALIDATED) != 0) {
+            return;
+        }
+
+        mStateCallback.setState(STATE_LAUNCHER_STARTED);
         LauncherState startState = mLauncher.getStateManager().getState();
         if (startState.disableRestore) {
             startState = mLauncher.getStateManager().getRestState();
         }
         mLauncher.getStateManager().setRestState(startState);
 
-        AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+        AbstractFloatingView.closeAllOpenViews(mLauncher, mWasLauncherAlreadyVisible);
 
-        mRecentsView = mLauncher.getOverviewPanel();
-        mLauncherLayoutListener = new LauncherLayoutListener(mLauncher);
 
-        final int state;
-        if (mWasLauncherAlreadyVisible) {
+        if (mWasLauncherAlreadyVisible && !mLauncher.getAppTransitionManager().isAnimating()) {
             DeviceProfile dp = mLauncher.getDeviceProfile();
             long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
-            mLauncherTransitionController = launcher.getStateManager()
+            mLauncherTransitionController = mLauncher.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);
+            mLauncher.getStateManager().goToState(OVERVIEW, false);
             TraceHelper.partitionSection("WTS-init", "State changed");
 
             // TODO: Implement a better animation for fading in
-            View rootView = launcher.getRootView();
+            View rootView = mLauncher.getRootView();
             rootView.setAlpha(0);
             rootView.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
 
@@ -321,17 +386,14 @@
                     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);
+        mRecentsView.setFirstTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
         mLauncherLayoutListener.open();
-
-        mStateCallback.setState(state);
-        return true;
     }
 
     public void setLauncherOnDrawCallback(Runnable callback) {
@@ -362,7 +424,6 @@
     }
 
     public void updateInteractionType(@InteractionType int interactionType) {
-        Preconditions.assertUIThread();
         if (mInteractionType != INTERACTION_NORMAL) {
             throw new IllegalArgumentException(
                     "Can't change interaction type from " + mInteractionType);
@@ -373,20 +434,15 @@
         }
         mInteractionType = interactionType;
 
-        if (mLauncher != null) {
-            updateUiForQuickScrub();
-        }
+        setStateOnUiThread(interactionType == INTERACTION_QUICK_SWITCH
+                ? STATE_QUICK_SWITCH : STATE_QUICK_SCRUB_START);
+
+        // Start the window animation without waiting for launcher.
+        animateToProgress(1f, QUICK_SWITCH_START_DURATION);
     }
 
-    private void updateUiForQuickScrub() {
-        mStartedQuickScrubFromHome = mWasLauncherAlreadyVisible;
-        mDeferredQuickScrubEnd = false;
-        mQuickScrubController = mRecentsView.getQuickScrubController();
-        mQuickScrubController.onQuickScrubStart(mStartedQuickScrubFromHome);
-        animateToProgress(1f, QUICK_SWITCH_START_DURATION);
-        if (mStartedQuickScrubFromHome) {
-            mLauncherLayoutListener.setVisibility(View.INVISIBLE);
-        }
+    private void onQuickInteractionStart() {
+        mQuickScrubController.onQuickScrubStart(false);
     }
 
     @WorkerThread
@@ -431,27 +487,24 @@
 
     @WorkerThread
     private void updateFinalShift() {
-        if (mStartedQuickScrubFromHome) {
-            return;
-        }
-
         float shift = mCurrentShift.value;
 
         synchronized (mRecentsAnimationWrapper) {
             if (mRecentsAnimationWrapper.controller != null) {
+                RectF currentRect;
                 synchronized (mTargetRect) {
-                    mRectEvaluator.evaluate(shift, mSourceRect, mTargetRect);
+                    currentRect = mRectFEvaluator.evaluate(shift, mSourceRect, mTargetRect);
                 }
-                float scale = (float) mCurrentRect.width() / mSourceRect.width();
 
                 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));
+                mClipRect.right = (int)
+                        (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * shift));
+                mClipRect.bottom = (int)
+                        (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * shift));
 
-                mTmpMatrix.setScale(scale, scale, 0, 0);
-                mTmpMatrix.postTranslate(mCurrentRect.left - mSourceInsets.left * scale * shift,
-                        mCurrentRect.top - mSourceInsets.top * scale * shift);
+                mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
+
                 TransactionCompat transaction = new TransactionCompat();
                 for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
                     if (app.mode == MODE_CLOSING) {
@@ -466,6 +519,9 @@
 
         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.
@@ -476,8 +532,8 @@
                 if (offsetFromFirstTask != 0) {
                     synchronized (mTargetRect) {
                         mTargetRect.set(mInitialTargetRect);
-                        Utilities.scaleRectAboutCenter(mTargetRect, firstTask.getScaleX());
-                        int offsetX = (int) (offsetFromFirstTask + firstTask.getTranslationX());
+                        Utilities.scaleRectFAboutCenter(mTargetRect, firstTask.getScaleX());
+                        float offsetX = offsetFromFirstTask + firstTask.getTranslationX();
                         mTargetRect.offset(offsetX, 0);
                     }
                 }
@@ -491,7 +547,7 @@
         }
     }
 
-    public void setRecentsAnimation(RecentsAnimationControllerCompat controller,
+    public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
             RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) {
         if (apps != null) {
             // Use the top closing app to determine the insets for the animation
@@ -532,13 +588,17 @@
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
     }
 
-    public void onGestureStarted() {
-        if (mLauncher != null) {
-            notifyGestureStarted();
-        }
+    public void onRecentsAnimationCanceled() {
+        mRecentsAnimationWrapper.setController(null, null);
+        clearReference();
+        setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
+    }
 
+    public void onGestureStarted() {
+        notifyGestureStarted();
         setStateOnUiThread(STATE_GESTURE_STARTED);
         mGestureStarted = true;
+        mRecentsAnimationWrapper.enableInputConsumer();
     }
 
     /**
@@ -546,7 +606,10 @@
      * on both background and UI threads
      */
     private void notifyGestureStarted() {
-        mLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+        final Launcher curLauncher = mLauncher;
+        if (curLauncher != null) {
+            curLauncher.onQuickstepGestureStarted(mWasLauncherAlreadyVisible);
+        }
     }
 
     @WorkerThread
@@ -559,6 +622,7 @@
         final float endShift;
         if (!isFling) {
             endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? 1 : 0;
+            mLogAction = Touch.SWIPE;
         } else {
             endShift = endVelocity < 0 ? 1 : 0;
             float minFlingVelocity = res.getDimension(R.dimen.quickstep_fling_min_velocity);
@@ -570,11 +634,28 @@
                 // derivative of the scroll interpolator at zero, ie. 5.
                 duration = 5 * Math.round(1000 * Math.abs(distanceToTravel / endVelocity));
             }
+            mLogAction = Touch.FLING;
         }
 
         animateToProgress(endShift, duration);
     }
 
+    private void doLogGesture(boolean toLauncher) {
+        final int direction;
+        if (mDp.isVerticalBarLayout()) {
+            direction = (mDp.isSeascape() ^ toLauncher) ? Direction.LEFT : Direction.RIGHT;
+        } else {
+            direction = toLauncher ? Direction.UP : Direction.DOWN;
+        }
+
+        int dstContainerType = toLauncher ? ContainerType.TASKSWITCHER : ContainerType.APP;
+        UserEventDispatcher.newInstance(mContext, mDp).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);
@@ -591,7 +672,8 @@
 
     @UiThread
     private void resumeLastTask() {
-        mRecentsAnimationWrapper.finish(false /* toHome */);
+        mRecentsAnimationWrapper.finish(false /* toHome */, null);
+        doLogGesture(false /* toLauncher */);
     }
 
     public void reset() {
@@ -610,12 +692,23 @@
         }
 
         clearReference();
+        mInputConsumer.unregisterInputConsumer();
     }
 
     private void invalidateHandlerWithLauncher() {
         mLauncherTransitionController = null;
         mLauncherLayoutListener.setHandler(null);
         mLauncherLayoutListener.close(false);
+
+        // Restore the requested orientation to the user preference after the gesture has ended
+        mLauncher.updateRequestedOrientation();
+        mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
+    }
+
+    private void resetStateForAnimationCancel() {
+        LauncherState startState = mLauncher.getStateManager().getRestState();
+        boolean animate = mWasLauncherAlreadyVisible || mGestureStarted;
+        mLauncher.getStateManager().goToState(startState, animate);
     }
 
     public void layoutListenerClosed() {
@@ -625,73 +718,70 @@
     }
 
     private void switchToScreenshot() {
+        boolean finishTransitionPosted = false;
+        final Runnable finishTransitionRunnable = () -> {
+            synchronized (mRecentsAnimationWrapper) {
+                mRecentsAnimationWrapper.finish(true /* toHome */,
+                        () -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE));
+            }
+        };
         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 =
+                        ThumbnailData thumbnail =
                                 mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
-                        mRecentsView.updateThumbnail(app.taskId, thumbnail);
+                        TaskView taskView = mRecentsView.updateThumbnail(app.taskId, thumbnail);
+                        if (taskView != null) {
+                            // Defer finishing the animation until the next launcher frame with the
+                            // new thumbnail
+                            ViewOnDrawExecutor executor = new ViewOnDrawExecutor() {
+                                @Override
+                                public void onViewDetachedFromWindow(View v) {
+                                    if (!isCompleted()) {
+                                        runAllTasks();
+                                    }
+                                }
+                            };
+                            executor.attachTo(mLauncher, taskView,
+                                    false /* waitForLoadAnimation */);
+                            executor.execute(finishTransitionRunnable);
+                            finishTransitionPosted = true;
+                        }
                     }
                 }
                 transaction.apply();
             }
         }
-        mRecentsAnimationWrapper.finish(true /* toHome */);
-
-        if (mInteractionType == INTERACTION_QUICK_SWITCH) {
-            for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
-                TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
-                if (taskView.getTask().key.id != mRunningTaskId) {
-                    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;
-                }
-            }
-        } else if (mInteractionType == INTERACTION_QUICK_SCRUB) {
-            if (mQuickScrubController != null) {
-                if (mDeferredQuickScrubEnd) {
-                    onQuickScrubEnd();
-                } else {
-                    mQuickScrubController.snapToPageForCurrentQuickScrubSection();
-                }
-            }
+        if (!finishTransitionPosted) {
+            // If we haven't posted the transition end runnable, run it now
+            finishTransitionRunnable.run();
         }
+        doLogGesture(true /* toLauncher */);
     }
 
     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);
-        }
+        // Animate the first icon.
+        mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
+
+        reset();
     }
 
     public void onQuickScrubEnd() {
-        if ((mStateCallback.getState() & STATE_SCALED_CONTROLLER_RECENTS) == 0) {
-            // If we are still animating into recents, then defer until that has run to end
-            // quick scrub since we need to finish the window animation before launching the next
-            // task
-            mDeferredQuickScrubEnd = true;
-            return;
-        }
+        setStateOnUiThread(STATE_QUICK_SCRUB_END);
+    }
 
-        if (mQuickScrubController != null) {
-            mQuickScrubController.onQuickScrubEnd();
-        } else {
-            // TODO:
-        }
+    private void switchToFinalAppAfterQuickSwitch() {
+        mQuickScrubController.onQuickSwitch();
+    }
+
+    private void switchToFinalAppAfterQuickScrub() {
+        mQuickScrubController.onQuickScrubEnd();
 
         // Normally this is handled in reset(), but since we are still scrubbing after the
         // transition into recents, we need to defer the handler invalidation for quick scrub until
@@ -700,14 +790,16 @@
     }
 
     public void onQuickScrubProgress(float progress) {
-        if (mQuickScrubController != null) {
-            mQuickScrubController.onQuickScrubProgress(progress);
-        } else {
-            // TODO:
+        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 synchronized void debugNewState(int stateFlag) {
+    private void debugNewState(int stateFlag) {
         if (!DEBUG_STATES) {
             return;
         }
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index 54a9b88..2accd2d 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -14,21 +14,23 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<com.android.launcher3.allapps.InterceptingViewPager
+<com.android.launcher3.allapps.AllAppsPagedView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:id="@+id/all_apps_tabs_view_pager"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_below="@id/search_container_all_apps"
     android:layout_gravity="center_horizontal|top"
     android:layout_marginTop="@dimen/all_apps_header_tab_height"
-    android:clipChildren="false"
+    android:clipChildren="true"
     android:clipToPadding="false"
     android:descendantFocusability="afterDescendants"
-    android:paddingTop="@dimen/all_apps_header_top_padding">
+    android:paddingTop="@dimen/all_apps_header_top_padding"
+    launcher:pageIndicator="@+id/tabs" >
 
     <include layout="@layout/all_apps_rv_layout" />
 
     <include layout="@layout/all_apps_rv_layout" />
 
-</com.android.launcher3.allapps.InterceptingViewPager>
\ No newline at end of file
+</com.android.launcher3.allapps.AllAppsPagedView>
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 9d0158b..1ff9a2d 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is \'n stelselprogram en kan nie gedeïnstalleer word nie."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamlose vouer"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Het <xliff:g id="APP_NAME">%1$s</xliff:g> gedeaktiveer"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> het <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> kennisgewings</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> het <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> kennisgewing</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Bladsy %1$d van %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tuisskerm %1$d van %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nuwe tuisskermbladsy"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 56742d3..67c26e7 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -60,6 +60,10 @@
     <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">"ገጽ %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>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 17075ce..1b1d7ca 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -33,8 +33,8 @@
     <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="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>
@@ -60,6 +60,14 @@
     <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="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>
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g>، به <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> إشعارات</item>
+      <item quantity="many"><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>
+      <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">"‏الصفحة %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>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 1e42fe8..00f71d0 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu sistem tətbiqi olduğu üçün sistemdən silinə bilməz."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Qovluq"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> deaktiv edildi"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> tətbiqində <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> bildiriş var</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> tətbiqində <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> bildiriş var</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Səhifə %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Əsas Səhifə ekranı %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni əsas ekran səhifəsi"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 6fc1968..0ee8b3a 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -60,6 +60,11 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je sistemska aplikacija i ne može da se deinstalira."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovani direktorijum"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućena"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obaveštenje</item>
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obaveštenja</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obaveštenja</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. stranica od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. početni ekran od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index f9e73ca..2f5eac7 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -60,6 +60,12 @@
     <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="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g>: ёсць <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> апавяшчэнні</item>
+      <item quantity="many"><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">"Старонка %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>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 86a79b3..94b7f13 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -60,6 +60,10 @@
     <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">"Страница %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>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index d7f61eb..d9c6033 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index fbbab0e..84b2b78 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -60,6 +60,11 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je sistemska aplikacija i ne može se deinstalirati."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovani folder"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućena"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenje</item>
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenja</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavještenja</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni ekran %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 793b1c7..1ca68eb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aquesta aplicació és una aplicació del sistema i no es pot desinstal·lar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sense nom"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"S\'ha desactivat <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> té <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificacions</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> té <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificació</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pàgina %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla d\'inici %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Pàgina de la pantalla d\'inici nova"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0d73f82..e5fde42 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -60,6 +60,12 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikace a nelze ji odinstalovat."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Složka bez názvu"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> je zakázána"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="few">Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> oznámení</item>
+      <item quantity="many">Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> oznámení</item>
+      <item quantity="other">Aplikace <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> oznámení</item>
+      <item quantity="one">Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> oznámení</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Strana %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 27d615a..97d8a26 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp, som ikke kan afinstalleres."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unavngiven mappe"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> er deaktiveret"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> har <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> underretning</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> har <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> underretninger</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d ud af %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskærm %1$d ud af %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny startskærm"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 8fec587..96acfba 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unbenannter Ordner"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> deaktiviert"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, hat <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> Benachrichtigungen</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, hat <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> Benachrichtigung</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Seite %1$d von %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startbildschirm %1$d von %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Neue Startbildschirmseite"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index a78b820..9328c5f 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -60,6 +60,10 @@
     <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">"Σελίδα %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>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 11389d4..d7ab7d2 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <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>, has <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifications</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, has <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notification</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 11389d4..d7ab7d2 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <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>, has <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifications</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, has <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notification</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 11389d4..d7ab7d2 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Disabled <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>, has <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifications</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, has <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notification</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d of %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"New home screen page"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 5a13087..11cfa2a 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta es una aplicación del sistema y no se puede desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Se inhabilitó <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> tiene <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificaciones</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> tiene <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificación</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla principal %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nueva página en la pantalla principal"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 1f1e3b7..39da94c 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación es del sistema y no se puede desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Se ha inhabilitado <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> tiene <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificaciones</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> tiene <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificación</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nueva página de pantalla de inicio"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 162da73..68a0429 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"See on süsteemirakendus ja seda ei saa desinstallida."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetu kaust"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> on keelatud"</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> märguannet</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> märguanne</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Leht %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Avaekraan %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uus avaekraan"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 3f137e4..27a56dd 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Sistema-aplikazioa da hau eta ezin da desinstalatu."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Izenik gabeko karpeta"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desgaituta dago"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> jakinarazpen dauzka <xliff:g id="APP_NAME_2">%1$s</xliff:g> aplikazioak</item>
+      <item quantity="one"><xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> jakinarazpen dauka <xliff:g id="APP_NAME_0">%1$s</xliff:g> aplikazioak</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d hasierako pantaila"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Hasierako pantailaren orri berria"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index f4b000d..128af90 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -60,6 +60,10 @@
     <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">"‏صفحه %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>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 6146ef9..f5b0817 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetön kansio"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> poistettiin käytöstä"</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> ilmoitusta</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>: <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ilmoitus</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sivu %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Aloitusruutu %1$d/%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Uusi aloitusnäytön sivu"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 43bcc5c..4093535 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est désactivée"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> a <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notification</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> a <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifications</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 8994ef4..520ad78 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> est désactivé."</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g> comporte <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notification</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> comporte <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifications</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nouvelle page d\'écran d\'accueil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index f7b433b..9a842b1 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación é do sistema e non se pode desinstalar."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartafol sen nome"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Desactivouse <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>, ten <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificacións</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ten <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificación</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Páxina %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Pantalla de inicio %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova páxina da pantalla de inicio"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index c292826..e030659 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 5282a93..aa1e8dd 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 42eb733..ec3c6b2 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -60,6 +60,11 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je aplikacija sustava i ne može se ukloniti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> onemogućena"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavijest</item>
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavijesti</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obavijesti</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stranica %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Početni zaslon %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog zaslona"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index db39449..697153a 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ez egy rendszeralkalmazás, és nem lehet eltávolítani."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Névtelen mappa"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> letiltva"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other">A(z) <xliff:g id="APP_NAME_2">%1$s</xliff:g> <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> értesítéssel rendelkezik</item>
+      <item quantity="one">A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> értesítéssel rendelkezik</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$d/%1$d. oldal"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%2$d/%1$d. kezdőképernyő"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Új kezdőképernyő oldal"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 611a038..02a561f 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -60,6 +60,10 @@
     <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">"Էջ %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>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index ff49b49..d115c73 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dinonaktifkan"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, memiliki <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifikasi</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, memiliki <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notifikasi</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string>
     <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>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index c3988f3..ba9a47d 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ónefnd mappa"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Óvirkt <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>, er með <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> tilkynningu</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, er með <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> tilkynningar</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Síða %1$d af %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Heimaskjár %1$d af %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ný síða á heimaskjá"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 174949e..6c98d3e 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartella senza nome"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"App <xliff:g id="APP_NAME">%1$s</xliff:g> disattivata"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> ha <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notifiche</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> ha <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notifica</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d di %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Schermata Home %1$d di %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nuova pagina Schermata Home"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index db156e1..43c8520 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -60,6 +60,12 @@
     <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="two">לאפליקציה <xliff:g id="APP_NAME_2">%1$s</xliff:g> יש <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> הודעות</item>
+      <item quantity="many">לאפליקציה <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>
+      <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">"‏דף %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>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 527cb95..36f3c5e 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -60,6 +60,10 @@
     <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">"%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>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 7e1752c..b6d7877 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -60,6 +60,10 @@
     <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">"გვერდი %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>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index ef92146..6c4deec 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -60,6 +60,10 @@
     <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">"%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>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index e52e0b2..d588bc1 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -60,6 +60,10 @@
     <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">"ទំព័រ %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>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 4bb0d22..a8f9784 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index a50a107..0ebbbe7 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -60,6 +60,10 @@
     <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="NOTIFICATION_COUNT_3">%2$d</xliff:g>개의 <xliff:g id="APP_NAME_2">%1$s</xliff:g> 알림 있음</item>
+      <item quantity="one"><xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g>개의 <xliff:g id="APP_NAME_0">%1$s</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_new_page" msgid="257366611030256142">"새로운 홈 화면 페이지"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index e2fde48..05652fc 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 3099d1f..e446e7c 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -60,6 +60,10 @@
     <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">"ໜ້າ %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>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 5b2e951..2e37e98 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -60,6 +60,12 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tai sistemos programa ir jos negalima pašalinti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Aplankas be pavadinimo"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ išjungta"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one">„<xliff:g id="APP_NAME_2">%1$s</xliff:g>“, yra <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pranešimas</item>
+      <item quantity="few">„<xliff:g id="APP_NAME_2">%1$s</xliff:g>“, yra <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pranešimai</item>
+      <item quantity="many">„<xliff:g id="APP_NAME_2">%1$s</xliff:g>“, yra <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pranešimo</item>
+      <item quantity="other">„<xliff:g id="APP_NAME_2">%1$s</xliff:g>“, yra <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pranešimų</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d psl. iš %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d pagrindinis ekranas iš %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Naujas pagrindinio ekrano puslapis"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index eec27b1..3b96ffa 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -60,6 +60,11 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Šī ir sistēmas lietotne, un to nevar atinstalēt."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mape bez nosaukuma"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> ir atspējota"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="zero"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ir <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> paziņojumi</item>
+      <item quantity="one"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ir <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> paziņojums</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ir <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> paziņojumi</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. lapa no %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Sākuma ekrāns: %1$d no %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Jauna sākuma ekrāna lapa"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 53944cb..3a0fc2b 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -60,6 +60,10 @@
     <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">"Страница %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>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index c247c4e..84f769b 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -60,6 +60,10 @@
     <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">"പേജ് %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>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 1deef00..5e91a46 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index c11883d..94b75d7 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f88fe96..6e19421 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini ialah apl sistem dan tidak boleh dinyahpasang."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dilumpuhkan"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, mempunyai <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> pemberitahuan</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, mempunyai <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> pemberitahuan</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d daripada %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Skrin Laman Utama %1$d daripada %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Halaman skrin utama baharu"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index f44f28c..3cf9208 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -60,6 +60,10 @@
     <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">"စာမျက်နှာ %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>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ee374f8..2bdd6ce 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp som ikke kan avinstalleres."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mappe uten navn"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Slo av <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> har <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> varsler</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> har <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> varsel</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Side %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startside %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny side på startskjermen"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 8d6819a..d15e8b2 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -60,6 +60,10 @@
     <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">"गृह स्क्रिन %1$d को %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"नयाँ गृह स्क्रिन पृष्ठ"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index a9123bd..38c24a5 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is een systeemapp die niet kan worden verwijderd."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamloze map"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> is uitgeschakeld"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> heeft <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> meldingen</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> heeft <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> melding</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d van %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startscherm %1$d van %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nieuwe startschermpagina"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 602bc34..6b6c929 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 0db8d62..c90ba1e 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -60,6 +60,12 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To aplikacja systemowa i nie można jej odinstalować."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder bez nazwy"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest wyłączona"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> powiadomienia</item>
+      <item quantity="many"><xliff:g id="APP_NAME_2">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> powiadomień</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> powiadomienia</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> – <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> powiadomienie</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Strona %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekran główny %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nowa strona ekranu głównego"</string>
@@ -131,7 +137,7 @@
     <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 do pracy"</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="work_mode_on_label" msgid="4781128097185272916">"Profil zarządzany przez Twoją organizację"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index ca4a1c6..c370a8e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma aplicação de sistema e não pode ser desinstalada."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desativado"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, tem <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificações.</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, tem <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificação.</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecrã principal %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova página do ecrã principal"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 77cc50f..0686ae7 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Este é um app do sistema e não pode ser desinstalado."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desativado"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one">O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificação</item>
+      <item quantity="other">O app <xliff:g id="APP_NAME_2">%1$s</xliff:g> tem <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificações</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Página %1$d de %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Tela inicial %1$d de %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova página na tela inicial"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 7b2409c..651b264 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -60,6 +60,11 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aceasta este o aplicație de sistem și nu poate fi dezinstalată."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosar fără nume"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"S-a dezactivat <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="few"><xliff:g id="APP_NAME_2">%1$s</xliff:g> are <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notificări</item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> are <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> de notificări</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> are <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> notificare</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pagina %1$d din %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ecranul de pornire %1$d din %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Pagină nouă pe ecranul de pornire"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 5242322..9f43c56 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -33,7 +33,7 @@
     <string name="long_accessible_way_to_add" msgid="4289502106628154155">"Чтобы выбрать виджет или использовать специальные действия, нажмите на него дважды и не отпускайте."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %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="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>
@@ -60,6 +60,12 @@
     <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="few">В приложении \"<xliff:g id="APP_NAME_2">%1$s</xliff:g>\" <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> уведомления</item>
+      <item quantity="many">В приложении \"<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">"Стр. %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>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 31d26e4..bbcc257 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 9567889..a3bc4ec 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -60,6 +60,12 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikácia a nedá sa odinštalovať."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nepomenovaný priečinok"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je deaktivovaná"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="few">Aplikácia <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> upozornenia</item>
+      <item quantity="many">Aplikácia <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> upozornenia</item>
+      <item quantity="other">Aplikácia <xliff:g id="APP_NAME_2">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> upozornení</item>
+      <item quantity="one">Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> má <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> upozornenie</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stránka %1$d z %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Plocha %1$d z %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nová stránka plochy"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index ca59140..337cb2d 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -60,6 +60,12 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To je sistemska aplikacija in je ni mogoče odstraniti."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogočena"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one">Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obvestilo</item>
+      <item quantity="two">Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obvestili</item>
+      <item quantity="few">Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obvestila</item>
+      <item quantity="other">Aplikacija <xliff:g id="APP_NAME_2">%1$s</xliff:g> ima <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> obvestil</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Stran %1$d od %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Začetni zaslon %1$d od %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Nova stran na začetnem zaslonu"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 7f4c3bc..e79f0d4 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ky është aplikacion sistemi dhe nuk mund të çinstalohet."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosje e paemërtuar"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> u çaktivizua"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ka <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> njoftime</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ka <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> njoftime</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Faqja: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ekrani bazë: %1$d nga gjithsej %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Faqja e ekranit të ri kryesor"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6d757fd..7d5e28d 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -60,6 +60,11 @@
     <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="few"><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">"%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>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index b61ed69..c886780 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Det här är en systemapp som inte kan avinstalleras."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Namnlös mapp"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inaktiverats"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> har <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> aviseringar</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> har <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> avisering</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sidan %1$d av %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Startskärmen %1$d av %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ny sida på startskärmen"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 05864fa..8925c89 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Hii ni programu ya mfumo na haiwezi kuondolewa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folda isiyo na jina"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> imezimwa"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, ina arifa <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g></item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, ina arifa <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g></item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Ukurasa%1$d wa %2$d"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for workspace_scroll_format (8458889198184077399) -->
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index aafb982..fc68b82 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -60,6 +60,10 @@
     <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">"பக்கம் %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"முகப்புத் திரை %1$d of %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"புதிய முகப்புத் திரை பக்கம்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 83d32f2..fb8a71b 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -60,6 +60,10 @@
     <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>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 5006d2e..6f2bc71 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -60,6 +60,10 @@
     <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">"หน้า %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>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index de90f30..5aad29a 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Isa itong app ng system at hindi maaaring i-uninstall."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Walang Pangalang Folder"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Naka-disable ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="one">May <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> notification ang <xliff:g id="APP_NAME_2">%1$s</xliff:g></item>
+      <item quantity="other">May <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> na notification ang <xliff:g id="APP_NAME_2">%1$s</xliff:g></item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Pahina %1$d ng %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Home screen %1$d ng %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Bagong page ng home screen"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index d8184e4..a0ebe6f0 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu bir sistem uygulamasıdır ve yüklemesi kaldırılamaz."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Klasör"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> devre dışı"</string>
+    <plurals name="badged_app_label" formatted="false" msgid="7948068486082879291">
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g> uygulamasının <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> bildirimi var</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulamasının <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> bildirimi var</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Sayfa %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Ana ekran %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yeni ana ekran sayfası"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index eb0d2be..ffced57 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -60,6 +60,12 @@
     <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="few">Додаток <xliff:g id="APP_NAME_2">%1$s</xliff:g> має <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> сповіщення</item>
+      <item quantity="many">Додаток <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">"Сторінка %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>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1070d89..cd65738 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -60,6 +60,10 @@
     <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">"‏صفحہ ‎%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>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 54a4ec0..200c2c0 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nomsiz jild"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi o‘chirib qo‘yildi"</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> ta bildirishnoma bor</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> ta bildirishnoma bor</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"%2$ddan %1$d ta sahifa"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Uy ekrani %2$ddan %1$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Yangi bosh ekran sahifasi"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 1bd7317..a5b4892 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Đây là ứng dụng hệ thống và không thể gỡ cài đặt."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Thư mục chưa đặt tên"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Đã vô hiệu hóa <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>, có <xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g> thông báo</item>
+      <item quantity="one"><xliff:g id="APP_NAME_0">%1$s</xliff:g>, có <xliff:g id="NOTIFICATION_COUNT_1">%2$d</xliff:g> thông báo</item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Trang %1$d / %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Màn hình chính %1$d / %2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Trang màn hình chính mới"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3610ef0..71e06e7 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -60,6 +60,10 @@
     <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">"第%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>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 0895651..7f792f8 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -60,6 +60,10 @@
     <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">"第 %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>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 76fbdb1..b95e838 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -60,6 +60,10 @@
     <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">"第 %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>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 53dbdd6..65d7d4c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -60,6 +60,10 @@
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Lolu uhlelo lokusebenza lwesistimu futhi alikwazi ukukhishwa."</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ifolda engenagama"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"Kukhutshaziwe <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>, inezaziso ezingu-<xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g></item>
+      <item quantity="other"><xliff:g id="APP_NAME_2">%1$s</xliff:g>, inezaziso ezingu-<xliff:g id="NOTIFICATION_COUNT_3">%2$d</xliff:g></item>
+    </plurals>
     <string name="default_scroll_format" msgid="7475544710230993317">"Ikhasi elingu-%1$d kwangu-%2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Isikrini sasekhaya esingu-%1$d se-%2$d"</string>
     <string name="workspace_new_page" msgid="257366611030256142">"Ikhasi elisha lesikrini sasekhaya"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 3dddac2..065ad36 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -101,6 +101,9 @@
     <!-- Name of a subclass of com.android.launcher3.util.InstantAppResolver. Can be empty. -->
     <string name="instant_app_resolver_class" translatable="false"></string>
 
+    <!-- Name of a main process initializer class. -->
+    <string name="main_process_initializer_class" translatable="false"></string>
+
     <!-- Package name of the default wallpaper picker. -->
     <string name="wallpaper_picker_package" translatable="false"></string>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2318e9e..381830c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -334,7 +334,7 @@
     <!-- 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>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 12f022f..fc5ce8f 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -92,7 +92,8 @@
     public final void close(boolean animate) {
         animate &= !Utilities.isPowerSaverOn(getContext());
         handleClose(animate);
-        Launcher.getLauncher(getContext()).getUserEventDispatcher().resetElapsedContainerMillis();
+        Launcher.getLauncher(getContext()).getUserEventDispatcher()
+                .resetElapsedContainerMillis("container closed");
     }
 
     protected abstract void handleClose(boolean animate);
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 4a0f52d..12db3b6 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -48,8 +48,7 @@
 
     public final UserEventDispatcher getUserEventDispatcher() {
         if (mUserEventDispatcher == null) {
-            mUserEventDispatcher = UserEventDispatcher.newInstance(this,
-                    mDeviceProfile.isLandscape, isInMultiWindowModeCompat());
+            mUserEventDispatcher = UserEventDispatcher.newInstance(this, mDeviceProfile);
         }
         return mUserEventDispatcher;
     }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 950c7f7..ba55b36 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -40,7 +40,9 @@
     public final boolean transposeLayoutWithOrientation;
 
     // Device properties in current orientation
-    public final boolean isLandscape;
+    private final boolean isLandscape;
+    public final boolean isMultiWindowMode;
+
     public final int widthPx;
     public final int heightPx;
     public final int availableWidthPx;
@@ -121,10 +123,11 @@
 
     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;
 
         Resources res = context.getResources();
         DisplayMetrics dm = res.getDisplayMetrics();
@@ -214,7 +217,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 +230,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
@@ -288,7 +292,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}.
@@ -503,14 +507,10 @@
         }
     }
 
-    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);
+        return !isMultiWindowMode && (touchedLhsEdge || touchedRhsEdge);
     }
 
     private static Context getContext(Context c, int orientation) {
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index bd19dfa..c4ec8c9 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -29,6 +29,8 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.util.Property;
 import android.util.SparseArray;
 
@@ -304,4 +306,30 @@
         }
         invalidateSelf();
     }
+
+    @Override
+    public ConstantState getConstantState() {
+        return new MyConstantState(mBitmap, mIconColor);
+    }
+
+    private static class MyConstantState extends ConstantState {
+        private final Bitmap mBitmap;
+        private 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..4eac4a4 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -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;
     }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 957a5e5..d0581a2 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -785,7 +785,7 @@
     }
 
     private static final class IconDB extends SQLiteCacheHelper {
-        private final static int RELEASE_VERSION = 20;
+        private final static int RELEASE_VERSION = 21;
 
         private final static String TABLE_NAME = "icons";
         private final static String COLUMN_ROWID = "rowid";
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 246fa74..e460911 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -162,9 +162,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/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4d820bc..55bfef6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -39,6 +39,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
+import android.app.ActivityOptions;
 import android.app.AlertDialog;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -239,6 +240,7 @@
 
     @Thunk boolean mWorkspaceLoading = true;
 
+    private OnStartCallback mOnStartCallback;
     private OnResumeCallback mOnResumeCallback;
 
     private ViewOnDrawExecutor mPendingExecutor;
@@ -294,10 +296,6 @@
         }
         TraceHelper.beginSection("Launcher-onCreate");
 
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.preOnCreate();
-        }
-
         WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
         wallpaperColorInfo.setOnThemeChangeListener(this);
         overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText());
@@ -307,12 +305,11 @@
 
         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);
 
@@ -375,11 +372,7 @@
         // For handling default keys
         setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
 
-        // 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);
-
+        updateRequestedOrientation();
         setContentView(mLauncherView);
         getRootView().dispatchInsets();
 
@@ -402,6 +395,13 @@
         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 onConfigurationChanged(Configuration newConfig) {
         int diff = newConfig.diff(mOldConfig);
@@ -434,6 +434,7 @@
             display.getSize(mwSize);
             mDeviceProfile = mDeviceProfile.getMultiWindowProfile(this, mwSize);
         }
+        mModelWriter = mModel.getWriter(mDeviceProfile.isVerticalBarLayout());
     }
 
     @Override
@@ -784,7 +785,7 @@
 
         if (!mAppLaunchSuccess) {
             getUserEventDispatcher().logActionCommand(Action.Command.STOP,
-                    mStateManager.getState().containerType);
+                    mStateManager.getState().containerType, -1);
         }
         NotificationListener.removeNotificationsChangedListener();
         getStateManager().moveToRestState();
@@ -795,6 +796,10 @@
         super.onStart();
         FirstFrameAnimatorHelper.setIsVisible(true);
 
+        if (mOnStartCallback != null) {
+            mOnStartCallback.onLauncherStart(this);
+            mOnStartCallback = null;
+        }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onStart();
         }
@@ -859,6 +864,12 @@
         }
     }
 
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        mStateManager.onWindowFocusChanged();
+    }
+
     public interface LauncherOverlay {
 
         /**
@@ -1275,7 +1286,8 @@
                 } 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
@@ -1651,7 +1663,8 @@
             topView.onBackPressed();
         } 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
@@ -1677,7 +1690,7 @@
 
         if (v instanceof Workspace) {
             if (isInState(OVERVIEW)) {
-                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
+                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP,
                         LauncherLogProto.Action.Direction.NONE,
                         LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
                 mStateManager.goToState(NORMAL);
@@ -1688,7 +1701,7 @@
         if (v instanceof CellLayout) {
             if (isInState(OVERVIEW)) {
                 int page = mWorkspace.indexOfChild(v);
-                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
+                getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP,
                         LauncherLogProto.Action.Direction.NONE,
                         LauncherLogProto.ContainerType.OVERVIEW, page);
                 mWorkspace.snapToPageFromOverView(page);
@@ -1852,6 +1865,18 @@
         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);
     }
 
@@ -1900,7 +1925,7 @@
             intent.setSourceBounds(getViewBounds(v));
             // If there is no target package, use the default intent chooser animation
             launchOptions = hasTargetPackage
-                    ? getActivityLaunchOptions(v, isInMultiWindowModeCompat())
+                    ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
                     : null;
         } else {
             launchOptions = null;
@@ -1955,8 +1980,13 @@
         }
     }
 
+    public Bundle getActivityLaunchOptionsAsBundle(View v, boolean useDefaultLaunchOptions) {
+        ActivityOptions activityOptions = getActivityLaunchOptions(v, useDefaultLaunchOptions);
+        return activityOptions == null ? null : activityOptions.toBundle();
+    }
+
     @TargetApi(Build.VERSION_CODES.M)
-    public Bundle getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
+    public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
         return useDefaultLaunchOptions
                 ? mAppTransitionManager.getDefaultActivityLaunchOptions(this, v)
                 : mAppTransitionManager.getActivityLaunchOptions(this, v);
@@ -1975,18 +2005,12 @@
             return mAppLaunchSuccess;
         }
 
-        boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
-                && (item instanceof ShortcutInfo)
-                && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
-                || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
-                && !((ShortcutInfo) item).isPromise();
-
         // 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, isShortcut || isInMultiWindowModeCompat())
+                ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
                 : null;
 
         UserHandle user = item == null ? null : item.user;
@@ -1997,6 +2021,11 @@
             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);
@@ -2159,6 +2188,10 @@
         mOnResumeCallback = callback;
     }
 
+    public void setOnStartCallback(OnStartCallback callback) {
+        mOnStartCallback = callback;
+    }
+
     /**
      * Implementation of the method from LauncherModel.Callbacks.
      */
@@ -2864,4 +2897,12 @@
 
         void onLauncherResume();
     }
+
+    /**
+     * Callback for listening for onStart
+     */
+    public interface OnStartCallback {
+
+        void onLauncherStart(Launcher launcher);
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 43d5e62..19fa3d4 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.view.View;
 
 /**
@@ -34,7 +33,7 @@
                 context, R.string.app_transition_manager_class);
     }
 
-    public Bundle getDefaultActivityLaunchOptions(Launcher launcher, View v) {
+    public ActivityOptions getDefaultActivityLaunchOptions(Launcher launcher, View v) {
         if (Utilities.ATLEAST_MARSHMALLOW) {
             int left = 0, top = 0;
             int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
@@ -49,23 +48,27 @@
                     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) {
+    public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) {
         return getDefaultActivityLaunchOptions(launcher, v);
     }
 
     /** Cancels the current Launcher transition animation */
     public void finishLauncherAnimation() {
     }
+
+    public boolean isAnimating() {
+        // We don't know when the activity options are being used.
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index ed7bf3d..35faaea 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -37,7 +37,6 @@
      * Activity life-cycle methods. These methods are triggered after
      * the code in the corresponding Launcher method is executed.
      */
-    void preOnCreate();
     void onCreate(Bundle savedInstanceState);
     void onResume();
     void onStart();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 929606e..6646b78 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -444,11 +444,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();
@@ -493,6 +489,15 @@
         }
     }
 
+    public void startLoaderForResultsIfNotLoaded(LoaderResults results) {
+        synchronized (mLock) {
+            if (!isModelLoaded()) {
+                Log.d(TAG, "Workspace not loaded, loading now");
+                startLoaderForResults(results);
+            }
+        }
+    }
+
     /**
      * Loads the workspace screen ids in an ordered list.
      */
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 98568e4..138ea0f 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -54,7 +54,6 @@
 import com.android.launcher3.LauncherSettings.WorkspaceScreens;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.IconShapeOverride;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DbDowngradeHelper;
 import com.android.launcher3.provider.LauncherDbUtils;
@@ -116,11 +115,8 @@
         mListenerHandler = new Handler(mListenerWrapper);
 
         // The content provider exists for the entire duration of the launcher main process and
-        // is the first component to get created. Initializing FileLog here ensures that it's
-        // always available in the main process.
-        FileLog.setDir(getContext().getApplicationContext().getFilesDir());
-        IconShapeOverride.apply(getContext());
-        SessionCommitReceiver.applyDefaultUserPrefs(getContext());
+        // is the first component to get created.
+        MainProcessInitializer.initialize(getContext().getApplicationContext());
         return true;
     }
 
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 137e4b1..2f8687d 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -158,6 +158,11 @@
 
     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) {
@@ -170,6 +175,7 @@
         mConfig.reset();
 
         if (!animated) {
+            preOnStateTransitionStart();
             onStateTransitionStart(state);
             for (StateHandler handler : getStateHandlers()) {
                 handler.setState(state);
@@ -189,6 +195,9 @@
         // 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;
+        }
 
         AnimatorSet animation = createAnimationToNewWorkspaceInternal(
                 state, new AnimatorSetBuilder(), onCompleteRunnable);
@@ -223,6 +232,8 @@
 
     protected AnimatorSet createAnimationToNewWorkspaceInternal(final LauncherState state,
             AnimatorSetBuilder builder, final Runnable onCompleteRunnable) {
+        preOnStateTransitionStart();
+
         for (StateHandler handler : getStateHandlers()) {
             builder.startTag(handler);
             handler.setStateWithAnimation(state, builder, mConfig);
@@ -261,6 +272,15 @@
         return mConfig.mCurrentAnimation;
     }
 
+    private void preOnStateTransitionStart() {
+        // 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();
+        }
+    }
+
     private void onStateTransitionStart(LauncherState state) {
         mState.onStateDisabled(mLauncher);
         mState = state;
@@ -271,13 +291,6 @@
             // 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();
-        }
     }
 
     private void onStateTransitionEnd(LauncherState state) {
@@ -289,12 +302,17 @@
 
         state.onStateTransitionEnd(mLauncher);
         mLauncher.getWorkspace().setClipChildren(!state.disablePageClipping);
-        mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
         mLauncher.finishAutoCancelActionMode();
 
         if (state == NORMAL) {
             setRestState(null);
         }
+
+        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+    }
+
+    public void onWindowFocusChanged() {
+        UiFactory.onLauncherStateOrFocusChanged(mLauncher);
     }
 
     public LauncherState getLastState() {
diff --git a/src/com/android/launcher3/MainProcessInitializer.java b/src/com/android/launcher3/MainProcessInitializer.java
new file mode 100644
index 0000000..462eadb
--- /dev/null
+++ b/src/com/android/launcher3/MainProcessInitializer.java
@@ -0,0 +1,40 @@
+/*
+ * 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.content.Context;
+
+import com.android.launcher3.graphics.IconShapeOverride;
+import com.android.launcher3.logging.FileLog;
+
+/**
+ * Utility class to handle one time initializations of the main process
+ */
+public class MainProcessInitializer {
+
+    public static void initialize(Context context) {
+        Utilities.getOverrideObject(
+                MainProcessInitializer.class, context, R.string.main_process_initializer_class)
+                .init(context);
+    }
+
+    protected void init(Context context) {
+        FileLog.setDir(context.getApplicationContext().getFilesDir());
+        IconShapeOverride.apply(context);
+        SessionCommitReceiver.applyDefaultUserPrefs(context);
+    }
+}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index bb137b0..d6e5d18 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -59,14 +59,11 @@
  * An abstraction of the original Workspace which supports browsing through a
  * sequential list of "pages"
  */
-public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
+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;
-
     public static final int PAGE_SNAP_ANIMATION_DURATION = 750;
     public static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
 
@@ -154,7 +151,7 @@
 
     // Page Indicator
     @Thunk int mPageIndicatorViewId;
-    protected PageIndicator mPageIndicator;
+    protected T mPageIndicator;
 
     // Reordering
     // We use the min scale to determine how much to expand the actually PagedView measured
@@ -224,7 +221,6 @@
         mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * density);
         mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * density);
         mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
-        setOnHierarchyChangeListener(this);
         setWillNotDraw(false);
     }
 
@@ -235,9 +231,9 @@
 
     public void initParentViews(View parent) {
         if (mPageIndicatorViewId > -1) {
-            mPageIndicator = (PageIndicator) parent.findViewById(mPageIndicatorViewId);
+            mPageIndicator = parent.findViewById(mPageIndicatorViewId);
             mPageIndicator.setMarkersCount(getChildCount());
-            mPageIndicator.setContentDescription(getPageIndicatorDescription());
+            mPageIndicator.setPageDescription(getPageIndicatorDescription());
         }
     }
 
@@ -282,7 +278,7 @@
         }
     }
 
-    public PageIndicator getPageIndicator() {
+    public T getPageIndicator() {
         return mPageIndicator;
     }
 
@@ -384,7 +380,7 @@
     private void updatePageIndicator() {
         // Update the page indicator (when we aren't reordering)
         if (mPageIndicator != null) {
-            mPageIndicator.setContentDescription(getPageIndicatorDescription());
+            mPageIndicator.setPageDescription(getPageIndicatorDescription());
             if (!isReordering(false)) {
                 mPageIndicator.setActiveMarker(getNextPage());
             }
@@ -748,63 +744,24 @@
         requestLayout();
     }
 
-    @Override
-    public void onChildViewAdded(View parent, View child) {
-        // Update the page indicator, we don't update the page indicator as we
-        // add/remove pages
-        if (mPageIndicator != null && !isReordering(false)) {
-            mPageIndicator.addMarker();
+    private void dispatchPageCountChanged() {
+        if (mPageIndicator != null) {
+            mPageIndicator.setMarkersCount(getChildCount());
         }
-
         // This ensures that when children are added, they get the correct transforms / alphas
         // in accordance with any scroll effects.
         invalidate();
     }
 
     @Override
-    public void onChildViewRemoved(View parent, View child) {
+    public void onViewAdded(View child) {
+        dispatchPageCountChanged();
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
         mCurrentPage = validateNewPage(mCurrentPage);
-        invalidate();
-    }
-
-    private void removeMarkerForView() {
-        // Update the page indicator, we don't update the page indicator as we
-        // add/remove pages
-        if (mPageIndicator != null && !isReordering(false)) {
-            mPageIndicator.removeMarker();
-        }
-    }
-
-    @Override
-    public void removeView(View v) {
-        // XXX: We should find a better way to hook into this before the view
-        // gets removed form its parent...
-        removeMarkerForView();
-        super.removeView(v);
-    }
-    @Override
-    public void removeViewInLayout(View v) {
-        // XXX: We should find a better way to hook into this before the view
-        // gets removed form its parent...
-        removeMarkerForView();
-        super.removeViewInLayout(v);
-    }
-    @Override
-    public void removeViewAt(int index) {
-        // XXX: We should find a better way to hook into this before the view
-        // gets removed form its parent...
-        removeMarkerForView();
-        super.removeViewAt(index);
-    }
-    @Override
-    public void removeAllViewsInLayout() {
-        // Update the page indicator, we don't update the page indicator as we
-        // add/remove pages
-        if (mPageIndicator != null) {
-            mPageIndicator.setMarkersCount(0);
-        }
-
-        super.removeAllViewsInLayout();
+        dispatchPageCountChanged();
     }
 
     protected int getChildOffset(int index) {
@@ -1352,9 +1309,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
@@ -1932,6 +1887,14 @@
                 getNextPage() + 1, getChildCount());
     }
 
+    protected float getDownMotionX() {
+        return mDownMotionX;
+    }
+
+    protected float getDownMotionY() {
+        return mDownMotionY;
+    }
+
     @Override
     public boolean onHoverEvent(android.view.MotionEvent event) {
         return true;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index d559b44..31dab97 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -31,6 +31,7 @@
 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;
@@ -232,6 +233,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();
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 2d24028..1414946 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -52,6 +52,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.widget.Toast;
 
 import com.android.launcher3.Launcher.LauncherOverlay;
@@ -75,6 +76,7 @@
 import com.android.launcher3.folder.PreviewBackground;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
 import com.android.launcher3.uioverrides.UiFactory;
@@ -100,10 +102,9 @@
  * Each page contains a number of icons, folders or widgets the user can
  * interact with. A workspace is meant to be used with a fixed width only.
  */
-public class Workspace extends PagedView
+public class Workspace extends PagedView<WorkspacePageIndicator>
         implements DropTarget, DragSource, View.OnTouchListener,
-        DragController.DragListener, ViewGroup.OnHierarchyChangeListener,
-        Insettable, LauncherStateManager.StateHandler {
+        DragController.DragListener, Insettable, LauncherStateManager.StateHandler {
     private static final String TAG = "Launcher.Workspace";
 
     /** The value that {@link #mTransitionProgress} must be greater than for
@@ -235,6 +236,7 @@
     boolean mStartedSendingScrollEvents;
     float mLastOverlayScroll = 0;
     boolean mOverlayShown = false;
+    private Runnable mOnOverlayHiddenCallback;
 
     private boolean mForceDrawAdjacentPages = false;
     private boolean mPageRearrangeEnabled = false;
@@ -273,9 +275,7 @@
 
         mWallpaperOffset = new WallpaperOffsetInterpolator(this);
 
-        setOnHierarchyChangeListener(this);
         setHapticFeedbackEnabled(false);
-
         initWorkspace();
 
         // Disable multitouch across the workspace/all apps/customize tray
@@ -463,7 +463,7 @@
     }
 
     @Override
-    public void onChildViewAdded(View parent, View child) {
+    public void onViewAdded(View child) {
         if (!(child instanceof CellLayout)) {
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
@@ -471,7 +471,7 @@
         cl.setOnInterceptTouchListener(this);
         cl.setClickable(true);
         cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
-        super.onChildViewAdded(parent, child);
+        super.onViewAdded(child);
     }
 
     boolean isTouchActive() {
@@ -1165,6 +1165,7 @@
                         Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
             }
             mOverlayShown = false;
+            tryRunOverlayCallback();
         }
         float offset = 0f;
         float slip = 0f;
@@ -1188,6 +1189,59 @@
         mLauncher.getDragLayer().setAlpha(alpha);
     }
 
+    /**
+     * @return false if the callback is still pending
+     */
+    private boolean tryRunOverlayCallback() {
+        if (mOnOverlayHiddenCallback == null) {
+            // Return true as no callback is pending. This is used by OnWindowFocusChangeListener
+            // to remove itself if multiple focus handles were added.
+            return true;
+        }
+        if (mOverlayShown || !hasWindowFocus()) {
+            return false;
+        }
+
+        mOnOverlayHiddenCallback.run();
+        mOnOverlayHiddenCallback = null;
+        return true;
+    }
+
+    /**
+     * Runs the given callback when the minus one overlay is hidden. Specifically, it is run
+     * when launcher's window has focus and the overlay is no longer being shown. If a callback
+     * is already present, the new callback will chain off it so both are run.
+     *
+     * @return Whether the callback was deferred.
+     */
+    public boolean runOnOverlayHidden(Runnable callback) {
+        if (mOnOverlayHiddenCallback == null) {
+            mOnOverlayHiddenCallback = callback;
+        } else {
+            // Chain the new callback onto the previous callback(s).
+            Runnable oldCallback = mOnOverlayHiddenCallback;
+            mOnOverlayHiddenCallback = () -> {
+                oldCallback.run();
+                callback.run();
+            };
+        }
+        if (!tryRunOverlayCallback()) {
+            ViewTreeObserver observer = getViewTreeObserver();
+            if (observer != null && observer.isAlive()) {
+                observer.addOnWindowFocusChangeListener(
+                        new ViewTreeObserver.OnWindowFocusChangeListener() {
+                            @Override
+                            public void onWindowFocusChanged(boolean hasFocus) {
+                                if (tryRunOverlayCallback() && observer.isAlive()) {
+                                    observer.removeOnWindowFocusChangeListener(this);
+                                }
+                            }});
+            }
+            return true;
+        }
+        return false;
+    }
+
     @Override
     protected void notifyPageSwitchListener(int prevPage) {
         super.notifyPageSwitchListener(prevPage);
@@ -1625,7 +1679,7 @@
             if (popupContainer != null) {
                 dragOptions.preDragCondition = popupContainer.createPreDragCondition();
 
-                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("dragging started");
             }
         }
 
@@ -2662,10 +2716,16 @@
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                if (info.container == NO_ID && info instanceof AppInfo) {
+                if (info.container == NO_ID) {
                     // Came from all apps -- make a copy
-                    info = ((AppInfo) info).makeShortcut();
-                    d.dragInfo = info;
+                    if (info instanceof AppInfo) {
+                        info = ((AppInfo) info).makeShortcut();
+                        d.dragInfo = info;
+                    } else if (info instanceof ShortcutInfo) {
+                        info = new ShortcutInfo((ShortcutInfo) info);
+                        d.dragInfo = info;
+                    }
+
                 }
                 view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info);
                 break;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index d4277db..a7eae39 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -21,8 +21,6 @@
 import android.os.Process;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.text.Selection;
@@ -50,7 +48,6 @@
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.PromiseAppInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.config.FeatureFlags;
@@ -59,12 +56,8 @@
 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.PackageUserKey;
 import com.android.launcher3.views.BottomUserEducationView;
 
-import java.util.List;
-import java.util.Set;
-
 /**
  * The all apps view container.
  */
@@ -80,9 +73,8 @@
 
     private SearchUiManager mSearchUiManager;
     private View mSearchContainer;
-    private InterceptingViewPager mViewPager;
+    private AllAppsPagedView mViewPager;
     private FloatingHeaderView mHeader;
-    private TabsPagerAdapter mTabsPagerAdapter;
 
     private SpannableStringBuilder mSearchQueryBuilder = null;
 
@@ -184,7 +176,7 @@
     }
 
     public AllAppsRecyclerView getActiveRecyclerView() {
-        if (!mUsingTabs || mViewPager.getCurrentItem() == 0) {
+        if (!mUsingTabs || mViewPager.getNextPage() == 0) {
             return mAH[AdapterHolder.MAIN].recyclerView;
         } else {
             return mAH[AdapterHolder.WORK].recyclerView;
@@ -329,9 +321,8 @@
         if (mUsingTabs) {
             mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
             mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
-            setupWorkProfileTabs();
+            onTabChanged(mViewPager.getNextPage());
         } else {
-            mTabsPagerAdapter = null;
             mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
             mAH[AdapterHolder.WORK].recyclerView = null;
         }
@@ -355,50 +346,35 @@
         int layout = showTabs ? R.layout.all_apps_tabs : R.layout.all_apps_rv_layout;
         View newView = LayoutInflater.from(getContext()).inflate(layout, this, false);
         addView(newView, index);
-        mViewPager = showTabs ? (InterceptingViewPager) newView : null;
+        if (showTabs) {
+            mViewPager = (AllAppsPagedView) newView;
+            mViewPager.initParentViews(this);
+            mViewPager.getPageIndicator().setContainerView(this);
+        } else {
+            mViewPager = null;
+        }
     }
 
     public View getRecyclerViewContainer() {
         return mViewPager != null ? mViewPager : findViewById(R.id.apps_list_view);
     }
 
-    private void setupWorkProfileTabs() {
-        if (mTabsPagerAdapter != null) {
-            return;
+    public void onTabChanged(int pos) {
+        mHeader.setMainActive(pos == 0);
+        reset();
+        applyTouchDelegate();
+        if (mAH[pos].recyclerView != null) {
+            mAH[pos].recyclerView.bindFastScrollbar();
+
+            findViewById(R.id.tab_personal)
+                    .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.MAIN));
+            findViewById(R.id.tab_work)
+                    .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
+
         }
-        final PersonalWorkSlidingTabStrip tabs = findViewById(R.id.tabs);
-        mViewPager.setAdapter(mTabsPagerAdapter = new TabsPagerAdapter());
-        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-
-            @Override
-            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-                tabs.updateIndicatorPosition(position, positionOffset);
-            }
-
-            @Override
-            public void onPageSelected(int pos) {
-                tabs.updateTabTextColor(pos);
-                mHeader.setMainActive(pos == 0);
-                reset();
-                applyTouchDelegate();
-                if (mAH[pos].recyclerView != null) {
-                    mAH[pos].recyclerView.bindFastScrollbar();
-                }
-                if (pos == AdapterHolder.WORK) {
-                    BottomUserEducationView.showIfNeeded(mLauncher);
-                }
-            }
-
-            @Override
-            public void onPageScrollStateChanged(int state) {
-            }
-        });
-        mAH[AdapterHolder.MAIN].recyclerView.bindFastScrollbar();
-
-        findViewById(R.id.tab_personal)
-                .setOnClickListener((View view) -> mViewPager.setCurrentItem(0));
-        findViewById(R.id.tab_work)
-                .setOnClickListener((View view) -> mViewPager.setCurrentItem(1));
+        if (pos == AdapterHolder.WORK) {
+            BottomUserEducationView.showIfNeeded(mLauncher);
+        }
     }
 
     public AlphabeticalAppsList getApps() {
@@ -519,37 +495,4 @@
                     && verticalFadingEdge);
         }
     }
-
-    private class TabsPagerAdapter extends PagerAdapter {
-        @Override
-        public int getCount() {
-            return 2;
-        }
-
-        @Override
-        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
-            return view == object;
-        }
-
-        @NonNull
-        @Override
-        public Object instantiateItem(@NonNull ViewGroup container, int position) {
-            if (position == 0) {
-                return mAH[AdapterHolder.MAIN].recyclerView;
-            } else {
-                return mAH[AdapterHolder.WORK].recyclerView;
-            }
-        }
-
-        @Nullable
-        @Override
-        public CharSequence getPageTitle(int position) {
-            if (position == 0) {
-                return getResources().getString(R.string.all_apps_personal_tab);
-            } else {
-                return getResources().getString(R.string.all_apps_work_tab);
-            }
-        }
-    }
-
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsPagedView.java b/src/com/android/launcher3/allapps/AllAppsPagedView.java
new file mode 100644
index 0000000..3b4450b
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsPagedView.java
@@ -0,0 +1,80 @@
+/*
+ * 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.allapps;
+
+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> {
+
+  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);
+    }
+
+    public AllAppsPagedView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsPagedView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected String getCurrentPageDescription() {
+        return getResources().getString(
+                getNextPage() == 0 ? R.string.all_apps_personal_tab : R.string.all_apps_work_tab);
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        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);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/allapps/InterceptingViewPager.java b/src/com/android/launcher3/allapps/InterceptingViewPager.java
deleted file mode 100644
index 3524ca9..0000000
--- a/src/com/android/launcher3/allapps/InterceptingViewPager.java
+++ /dev/null
@@ -1,91 +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.allapps;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.ViewConfiguration;
-
-import com.android.launcher3.touch.SwipeDetector;
-
-import static android.view.MotionEvent.INVALID_POINTER_ID;
-
-
-public class InterceptingViewPager extends ViewPager {
-
-
-    private final PointF mDownPos = new PointF();
-    private final PointF mLastPos = new PointF();
-    private final int mSlop;
-    private int mActivePointerId = INVALID_POINTER_ID;
-
-    public InterceptingViewPager(@NonNull Context context) {
-        super(context);
-        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
-    }
-
-    public InterceptingViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        boolean result = super.onInterceptTouchEvent(ev);
-        if (!result) {
-            switch (ev.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    mActivePointerId = ev.getPointerId(0);
-                    mDownPos.set(ev.getX(), ev.getY());
-                    mLastPos.set(mDownPos);
-                    break;
-                case MotionEvent.ACTION_POINTER_UP:
-                    int ptrIdx = ev.getActionIndex();
-                    int ptrId = ev.getPointerId(ptrIdx);
-                    if (ptrId == mActivePointerId) {
-                        final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
-                        mDownPos.set(
-                                ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
-                                ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
-                        mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
-                        mActivePointerId = ev.getPointerId(newPointerIdx);
-                    }
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    int pointerIndex = ev.findPointerIndex(mActivePointerId);
-                    if (pointerIndex == INVALID_POINTER_ID) {
-                        break;
-                    }
-                    float deltaX = ev.getX() - mDownPos.x;
-                    float deltaY = ev.getY() - mDownPos.y;
-                    if (Math.abs(deltaX) > mSlop && Math.abs(deltaX) > Math.abs(deltaY)) {
-                        return true;
-                    }
-                    mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
-                    break;
-                default:
-                    break;
-            }
-        }
-        return result;
-    }
-
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
index 05cd655..a069d5d 100644
--- a/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
+++ b/src/com/android/launcher3/allapps/PersonalWorkSlidingTabStrip.java
@@ -25,16 +25,16 @@
 import android.view.View;
 import android.widget.Button;
 import android.widget.LinearLayout;
-
 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;
 
 /**
  * Supports two indicator colors, dedicated for personal and work tabs.
  */
-public class PersonalWorkSlidingTabStrip extends LinearLayout {
+public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageIndicator {
     private static final int POSITION_PERSONAL = 0;
     private static final int POSITION_WORK = 1;
 
@@ -47,10 +47,13 @@
     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);
         setOrientation(HORIZONTAL);
@@ -69,15 +72,15 @@
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height));
 
         mSharedPreferences = Launcher.getLauncher(getContext()).getSharedPrefs();
+        mIsRtl = Utilities.isRtl(getResources());
     }
 
-    public void updateIndicatorPosition(int position, float positionOffset) {
-        mIndicatorPosition = position;
-        mIndicatorOffset = positionOffset;
+    private void updateIndicatorPosition(float scrollOffset) {
+        mScrollOffset = scrollOffset;
         updateIndicatorPosition();
     }
 
-    public void updateTabTextColor(int pos) {
+    private void updateTabTextColor(int pos) {
         mSelectedPosition = pos;
         for (int i = 0; i < getChildCount(); i++) {
             Button tab = (Button) getChildAt(i);
@@ -89,32 +92,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;
@@ -129,8 +123,6 @@
 
         float y = getHeight() - mDividerPaint.getStrokeWidth();
         canvas.drawLine(getPaddingLeft(), y, getWidth() - getPaddingRight(), y, mDividerPaint);
-
-        final float middleX = getWidth() / 2.0f;
         canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
             mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
     }
@@ -139,7 +131,7 @@
         if (mSharedPreferences.getBoolean(KEY_SHOWED_PEEK_WORK_TAB, false)) {
             return;
         }
-        if (mIndicatorPosition != POSITION_PERSONAL) {
+        if (mLastActivePage != POSITION_PERSONAL) {
             return;
         }
         highlightWorkTab();
@@ -153,4 +145,32 @@
             v.setPressed(false);
         });
     }
+
+    @Override
+    public void setScroll(int currentScroll, int totalScroll) {
+        float scrollOffset = ((float) currentScroll) / totalScroll;
+        updateIndicatorPosition(scrollOffset);
+    }
+
+    @Override
+    public void setActiveMarker(int activePage) {
+        updateTabTextColor(activePage);
+        if (mContainerView != null && mLastActivePage != activePage) {
+            mContainerView.onTabChanged(activePage);
+        }
+        mLastActivePage = activePage;
+    }
+
+    public void setContainerView(AllAppsContainerView containerView) {
+        mContainerView = containerView;
+    }
+
+    @Override
+    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.
+    }
 }
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 0dcebe3..6078776 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.anim;
 
+import android.graphics.Path;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -44,9 +45,19 @@
     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;
+
+    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 APP_CLOSE_ALPHA = new PathInterpolator(0.4f, 0, 1f, 1f);
 
     public static final Interpolator OVERSHOOT_0 = new OvershootInterpolator(0);
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 8abafb0..993663e 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -522,7 +522,7 @@
         onCompleteRunnable = new Runnable() {
             @Override
             public void run() {
-                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+                mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("folder opened");
             }
         };
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index f4462aa..a468cb5 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -44,14 +44,14 @@
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
-import com.android.launcher3.pageindicators.PageIndicator;
+import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.Map;
 
-public class FolderPagedView extends PagedView {
+public class FolderPagedView extends PagedView<PageIndicatorDots> {
 
     private static final String TAG = "FolderPagedView";
 
@@ -89,8 +89,6 @@
     private Folder mFolder;
     private PagedFolderKeyEventListener mKeyListener;
 
-    private PageIndicator mPageIndicator;
-
     public FolderPagedView(Context context, AttributeSet attrs) {
         super(context, attrs);
         InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 00ee009..c608a23 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -71,7 +71,7 @@
         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;
@@ -114,11 +114,20 @@
         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;
+        return typeStr;
+    }
+
+    public static Target newItemTarget(int itemType) {
+        Target t = newTarget(Target.Type.ITEM);
+        t.itemType = itemType;
+        return t;
     }
 
     public static Target newItemTarget(View v) {
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 243dbea..627115d 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -27,11 +27,13 @@
 import android.view.View;
 import android.view.ViewParent;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ItemInfo;
 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;
@@ -64,8 +66,7 @@
             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, DeviceProfile dp) {
         SharedPreferences sharedPrefs = Utilities.getDevicePrefs(context);
         String uuidStr = sharedPrefs.getString(UUID_STORAGE, null);
         if (uuidStr == null) {
@@ -74,8 +75,8 @@
         }
         UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
                 context.getApplicationContext(), R.string.user_event_dispatcher_class);
-        ued.mIsInLandscapeMode = isInLandscapeMode;
-        ued.mIsInMultiWindowMode = isInMultiWindowMode;
+        ued.mIsInLandscapeMode = dp.isVerticalBarLayout();
+        ued.mIsInMultiWindowMode = dp.isMultiWindowMode;
         ued.mUuidStr = uuidStr;
         return ued;
     }
@@ -158,9 +159,23 @@
         dispatchUserEvent(event, intent);
     }
 
+    public void logTaskLaunch(int action, int direction, ComponentName componentName){
+        LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE
+                newTarget(Target.Type.ITEM));
+        if (action == Action.Touch.SWIPE || action == Action.Touch.FLING) {
+            event.action.dir = direction;
+        }
+        event.srcTarget[0].itemType = LauncherLogProto.ItemType.TASK;
+        fillComponentInfo(event.srcTarget[0], componentName);
+        dispatchUserEvent(event, null);
+    }
+
     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();
@@ -176,19 +191,29 @@
         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 (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));
 
@@ -196,22 +221,39 @@
             // 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, @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);
     }
 
@@ -232,10 +274,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 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) {
@@ -257,7 +324,7 @@
         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
@@ -290,9 +357,15 @@
 
     /**
      * 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() {
@@ -321,13 +394,13 @@
             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/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java
index 24e5b9c..5acc790 100644
--- a/src/com/android/launcher3/model/LoaderResults.java
+++ b/src/com/android/launcher3/model/LoaderResults.java
@@ -162,7 +162,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
diff --git a/src/com/android/launcher3/model/ModelPreload.java b/src/com/android/launcher3/model/ModelPreload.java
index 6f33bed..f186e95 100644
--- a/src/com/android/launcher3/model/ModelPreload.java
+++ b/src/com/android/launcher3/model/ModelPreload.java
@@ -49,11 +49,8 @@
 
     @Override
     public final void run() {
-        if (!mModel.isModelLoaded()) {
-            Log.d(TAG, "Workspace not loaded, loading now");
-            mModel.startLoaderForResults(
-                    new LoaderResults(mApp, mBgDataModel, mAllAppsList, 0, null));
-        }
+        mModel.startLoaderForResultsIfNotLoaded(
+                new LoaderResults(mApp, mBgDataModel, mAllAppsList, 0, null));
         Log.d(TAG, "Preload completed : " + mModel.isModelLoaded());
         onComplete(mModel.isModelLoaded());
     }
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 114b2b8..cbdabf3 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,8 @@
     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<>();
 
     private SettingsObserver mNotificationBadgingObserver;
 
@@ -258,6 +260,48 @@
         }
     }
 
+    @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. */
     public List<StatusBarNotification> getNotificationsForKeys(List<NotificationKeyData> keys) {
         StatusBarNotification[] notifications = NotificationListener.this
@@ -295,20 +339,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 +355,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/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 5e3d216..3ce7291 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -15,41 +15,16 @@
  */
 package com.android.launcher3.pageindicators;
 
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
 /**
  * Base class for a page indicator.
  */
-public abstract class PageIndicator extends View {
+public interface PageIndicator {
 
-    protected int mNumPages = 1;
+    void setScroll(int currentScroll, int totalScroll);
 
-    public PageIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
+    void setActiveMarker(int activePage);
 
-    public void setScroll(int currentScroll, int totalScroll) {}
+    void setMarkersCount(int numMarkers);
 
-    public void setActiveMarker(int activePage) {}
-
-    public void addMarker() {
-        mNumPages++;
-        onPageCountChanged();
-    }
-
-    public void removeMarker() {
-        mNumPages--;
-        onPageCountChanged();
-    }
-
-    public void setMarkersCount(int numMarkers) {
-        mNumPages = numMarkers;
-        onPageCountChanged();
-    }
-
-    protected void onPageCountChanged() {}
-
-    public void setShouldAutoHide(boolean shouldAutoHide) {}
+    void setPageDescription(CharSequence description);
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 6276c80..524ec3c 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -43,7 +43,7 @@
  * {@link PageIndicator} which shows dots per page. The active page is shown with the current
  * accent color.
  */
-public class PageIndicatorDots extends PageIndicator {
+public class PageIndicatorDots extends View implements PageIndicator {
 
     private static final float SHIFT_PER_ANIMATION = 0.5f;
     private static final float SHIFT_THRESHOLD = 0.1f;
@@ -79,6 +79,7 @@
     private final int mInActiveColor;
     private final boolean mIsRtl;
 
+    private int mNumPages;
     private int mActivePage;
 
     /**
@@ -221,11 +222,17 @@
     }
 
     @Override
-    protected void onPageCountChanged() {
+    public void setMarkersCount(int numMarkers) {
+        mNumPages = numMarkers;
         requestLayout();
     }
 
     @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 ee4e4ee..4fc7d8a 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -41,7 +41,8 @@
  *
  * The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
  */
-public class WorkspacePageIndicator extends PageIndicator implements Insettable, OnClickListener {
+public class WorkspacePageIndicator extends View
+        implements Insettable, OnClickListener, PageIndicator {
 
     private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
     private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -185,14 +186,18 @@
     }
 
     @Override
-    public void setActiveMarker(int activePage) {
+    public void setActiveMarker(int activePage) { }
+
+    @Override
+    public void setMarkersCount(int numMarkers) {
+        if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
+            animateToNumPages(numMarkers);
+        }
     }
 
     @Override
-    protected void onPageCountChanged() {
-        if (Float.compare(mNumPages, mNumPagesFloat) != 0) {
-            animateToNumPages(mNumPages);
-        }
+    public void setPageDescription(CharSequence description) {
+        setContentDescription(description);
     }
 
     public void setShouldAutoHide(boolean shouldAutoHide) {
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index d2bcd18..32fd063 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -82,7 +82,7 @@
                 @Override
                 public void onClick(View view) {
                     Rect sourceBounds = launcher.getViewBounds(view);
-                    Bundle opts = launcher.getActivityLaunchOptions(view, false);
+                    Bundle opts = launcher.getActivityLaunchOptionsAsBundle(view, false);
                     InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, sourceBounds, opts);
                     launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                             ControlType.APPINFO_TARGET, view);
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..d3c0fef 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,12 @@
         return intent;
     }
 
-    public final void initWhenReady(MainThreadExecutor executor) {
-        sPendingHandler = new WeakReference<>(this);
-        executor.execute(this::initIfReadOnUIThread);
-    }
-
-    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 final void initWhenReady() {
+        sScheduler.schedule(this);
     }
 
     public void clearReference() {
-        if (sPendingHandler.get() == this) {
-            sPendingHandler.clear();
-        }
+        sScheduler.clearReference(this);
     }
 
     public static boolean handleCreate(Launcher launcher, Intent intent) {
@@ -101,14 +82,53 @@
             }
         }
         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 synchronized void schedule(InternalStateHandler handler) {
+            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 synchronized boolean initIfPending(Launcher launcher, boolean alreadyOnHome) {
+            InternalStateHandler pendingHandler = mPendingHandler.get();
+            if (pendingHandler != null) {
+                if (!pendingHandler.init(launcher, alreadyOnHome)) {
+                    mPendingHandler.clear();
+                }
+                return true;
+            }
+            return false;
+        }
+
+        public synchronized void clearReference(InternalStateHandler handler) {
+            if (mPendingHandler.get() == handler) {
+                mPendingHandler.clear();
+            }
+        }
+    }
 }
\ No newline at end of file
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/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index bde9c0a..ac381cc 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -15,12 +15,16 @@
  */
 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;
 import android.util.Log;
 import android.util.MutableLong;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 
 /**
@@ -31,7 +35,8 @@
  */
 public class TraceHelper {
 
-    private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;
+    private static final boolean FORCE_LOG = Utilities.IS_DEBUG_DEVICE;
+    private static final boolean ENABLED = FORCE_LOG || FeatureFlags.IS_DOGFOOD_BUILD;
 
     private static final boolean SYSTEM_TRACE = false;
     private static final ArrayMap<String, MutableLong> sUpTimes = ENABLED ? new ArrayMap<>() : null;
@@ -40,7 +45,7 @@
         if (ENABLED) {
             MutableLong time = sUpTimes.get(sectionName);
             if (time == null) {
-                time = new MutableLong(Log.isLoggable(sectionName, Log.VERBOSE) ? 0 : -1);
+                time = new MutableLong((FORCE_LOG || 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
index 735fb2f..a647378 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -62,7 +62,7 @@
     private boolean mNoIntercept;
 
     private AnimatorPlaybackController mCurrentAnimation;
-    private LauncherState mToState;
+    protected LauncherState mToState;
 
     private float mStartProgress;
     // Ratio of transition process [0, 1] to drag displacement (px)
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_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
index 2d39505..4168e11 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewPanel.java
@@ -159,7 +159,7 @@
                 .setPackage(getContext().getPackageName());
         intent.setSourceBounds(mLauncher.getViewBounds(v));
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        getContext().startActivity(intent, mLauncher.getActivityLaunchOptions(v, false));
+        getContext().startActivity(intent, mLauncher.getActivityLaunchOptionsAsBundle(v, false));
     }
 
     @Override
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 744125e..64a29ea 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.uioverrides;
 
+import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 
 import android.graphics.Bitmap;
@@ -61,4 +62,6 @@
     }
 
     public static void resetOverview(Launcher launcher) { }
+
+    public static void onLauncherStateOrFocusChanged(Launcher launcher) { }
 }