resolved conflicts for merge of 13ef17a3 to mnc-dr-dev
b/22609402
Change-Id: I140cf972d57e14737a6f91c0b4a8ec6c7ff1af2b
diff --git a/.gitignore b/.gitignore
index f830c66..aea5d61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,10 @@
 db_files
+*.iml
+.project
+.classpath
+.project.properties
+gen/
+tests/stress/gen/
+WallpaperPicker/gen/
+WallpaperPicker/.project.properties
+bin/
diff --git a/Android.mk b/Android.mk
index 2a406e7..134cfb5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,28 +23,23 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
-
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-java-files-under, WallpaperPicker/src) \
-    $(call all-renderscript-files-under, src) \
     $(call all-proto-files-under, protos)
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/WallpaperPicker/res $(LOCAL_PATH)/res
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := nano
 LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/
+LOCAL_AAPT_FLAGS := --auto-add-overlay
 
-LOCAL_SDK_VERSION := 21
-
+LOCAL_SDK_VERSION := current
 LOCAL_PACKAGE_NAME := Launcher3
 #LOCAL_CERTIFICATE := shared
 
 LOCAL_OVERRIDES_PACKAGES := Home Launcher2
 
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
 include $(BUILD_PACKAGE)
 
 
@@ -83,4 +78,6 @@
 	$(copy-file-to-new-target)
 	$(hide) chmod 755 $@
 
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fb7ac3f..1fb8e8d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -29,12 +29,6 @@
         android:label="@string/permlab_install_shortcut"
         android:description="@string/permdesc_install_shortcut" />
     <permission
-        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_uninstall_shortcut"
-        android:description="@string/permdesc_uninstall_shortcut"/>
-    <permission
         android:name="com.android.launcher3.permission.READ_SETTINGS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="normal"
@@ -71,7 +65,6 @@
     <uses-permission android:name="com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST" />
 
     <application
-        android:name="com.android.launcher3.LauncherApplication"
         android:allowBackup="@bool/enable_backup"
         android:backupAgent="com.android.launcher3.LauncherBackupAgentHelper"
         android:hardwareAccelerated="true"
@@ -89,6 +82,8 @@
             android:theme="@style/Theme"
             android:windowSoftInputMode="adjustPan"
             android:screenOrientation="nosensor"
+            android:resumeWhilePausing="true"
+            android:taskAffinity=""
             android:enabled="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -98,8 +93,10 @@
             </intent-filter>
         </activity>
 
+        <!-- ENABLE_FOR_TESTING
+
         <activity
-            android:name="com.android.launcher3.LauncherExtension"
+            android:name="com.android.launcher3.testing.LauncherExtension"
             android:launchMode="singleTask"
             android:clearTaskOnLaunch="true"
             android:stateNotNeeded="true"
@@ -115,6 +112,8 @@
             </intent-filter>
         </activity>
 
+        -->
+
         <activity
             android:name="com.android.launcher3.ToggleWeightWatcher"
             android:label="@string/toggle_weight_watcher"
@@ -128,7 +127,7 @@
         </activity>
 
         <activity
-            android:name="com.android.launcher3.LauncherWallpaperPickerActivity"
+            android:name="com.android.launcher3.WallpaperPickerActivity"
             android:theme="@style/Theme.WallpaperPicker"
             android:label="@string/pick_wallpaper"
             android:icon="@mipmap/ic_launcher_wallpaper"
@@ -154,6 +153,13 @@
             </intent-filter>
         </activity>
 
+        <activity
+            android:name="com.android.launcher3.SettingsActivity"
+            android:label="@string/settings_button_text"
+            android:autoRemoveFromRecents="true"
+            android:process=":settings_process">
+        </activity>
+
         <!-- Debugging tools -->
         <activity
             android:name="com.android.launcher3.MemoryDumpActivity"
@@ -191,15 +197,6 @@
             </intent-filter>
         </receiver>
 
-        <!-- Intent received used to uninstall shortcuts from other applications -->
-        <receiver
-            android:name="com.android.launcher3.UninstallShortcutReceiver"
-            android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT">
-            <intent-filter>
-                <action android:name="com.android.launcher.action.UNINSTALL_SHORTCUT" />
-            </intent-filter>
-        </receiver>
-
         <!-- Intent received used to initialize a restored widget -->
         <receiver android:name="com.android.launcher3.AppWidgetsRestoredReceiver" >
             <intent-filter>
@@ -207,24 +204,6 @@
             </intent-filter>
         </receiver>
 
-        <!-- New user initialization; set up initial wallpaper -->
-        <receiver
-            android:name="com.android.launcher3.UserInitializeReceiver"
-            android:exported="false">
-            <intent-filter>
-                <action android:name="android.intent.action.USER_INITIALIZE" />
-            </intent-filter>
-        </receiver>
-
-        <receiver android:name="com.android.launcher3.PackageChangedReceiver" >
-            <intent-filter>
-                <action android:name="android.intent.action.PACKAGE_CHANGED"/>
-                <action android:name="android.intent.action.PACKAGE_REPLACED"/>
-                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
-                <data android:scheme="package"></data>
-            </intent-filter>
-        </receiver>
-
         <receiver android:name="com.android.launcher3.StartupReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/WallpaperPicker/AndroidManifest.xml b/WallpaperPicker/AndroidManifest.xml
index 86a94d0..cb1457b 100644
--- a/WallpaperPicker/AndroidManifest.xml
+++ b/WallpaperPicker/AndroidManifest.xml
@@ -5,6 +5,6 @@
         android:versionName="1.0"
         >
 
-    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="19" />
-
+    <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" />
+    <application/>
 </manifest>
diff --git a/WallpaperPicker/res/drawable-hdpi/ic_images.png b/WallpaperPicker/res/drawable-hdpi/ic_images.png
index 0003c6c..15e511c 100644
--- a/WallpaperPicker/res/drawable-hdpi/ic_images.png
+++ b/WallpaperPicker/res/drawable-hdpi/ic_images.png
Binary files differ
diff --git a/WallpaperPicker/res/drawable-mdpi/ic_images.png b/WallpaperPicker/res/drawable-mdpi/ic_images.png
index aabc123..c4a2229 100644
--- a/WallpaperPicker/res/drawable-mdpi/ic_images.png
+++ b/WallpaperPicker/res/drawable-mdpi/ic_images.png
Binary files differ
diff --git a/WallpaperPicker/res/drawable-xhdpi/ic_images.png b/WallpaperPicker/res/drawable-xhdpi/ic_images.png
index 3f21faf..4974792 100644
--- a/WallpaperPicker/res/drawable-xhdpi/ic_images.png
+++ b/WallpaperPicker/res/drawable-xhdpi/ic_images.png
Binary files differ
diff --git a/WallpaperPicker/res/drawable-xxhdpi/ic_images.png b/WallpaperPicker/res/drawable-xxhdpi/ic_images.png
index d00db9a..c8b9f75 100644
--- a/WallpaperPicker/res/drawable-xxhdpi/ic_images.png
+++ b/WallpaperPicker/res/drawable-xxhdpi/ic_images.png
Binary files differ
diff --git a/WallpaperPicker/res/drawable-xxxhdpi/ic_images.png b/WallpaperPicker/res/drawable-xxxhdpi/ic_images.png
new file mode 100644
index 0000000..a19002e
--- /dev/null
+++ b/WallpaperPicker/res/drawable-xxxhdpi/ic_images.png
Binary files differ
diff --git a/WallpaperPicker/res/layout/wallpaper_cropper.xml b/WallpaperPicker/res/layout/wallpaper_cropper.xml
index abb8608..ffe8df0 100644
--- a/WallpaperPicker/res/layout/wallpaper_cropper.xml
+++ b/WallpaperPicker/res/layout/wallpaper_cropper.xml
@@ -19,7 +19,6 @@
 -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/wallpaper_root"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <com.android.launcher3.CropView
@@ -28,7 +27,7 @@
         android:layout_height="match_parent" />
     <ProgressBar
         android:id="@+id/loading"
-        style="@android:style/Widget.Holo.ProgressBar.Large"
+        style="?android:attr/progressBarStyleLarge"
         android:visibility="invisible"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/WallpaperPicker/res/layout/wallpaper_picker.xml b/WallpaperPicker/res/layout/wallpaper_picker.xml
index c36493d..0b970b0 100644
--- a/WallpaperPicker/res/layout/wallpaper_picker.xml
+++ b/WallpaperPicker/res/layout/wallpaper_picker.xml
@@ -18,60 +18,74 @@
 */
 -->
 
-<com.android.launcher3.WallpaperRootView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/wallpaper_root"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent" >
+
     <com.android.launcher3.CropView
         android:id="@+id/cropView"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
+
     <ProgressBar
         android:id="@+id/loading"
-        style="@android:style/Widget.Holo.ProgressBar.Large"
-        android:visibility="invisible"
+        style="?android:attr/progressBarStyleLarge"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_centerInParent="true"
+        android:layout_gravity="center"
         android:indeterminate="true"
         android:indeterminateOnly="true"
-        android:background="@android:color/transparent" />
+        android:visibility="invisible" />
+
     <LinearLayout
         android:id="@+id/wallpaper_strip"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
+        android:layout_gravity="bottom"
+        android:fitsSystemWindows="true"
         android:orientation="vertical" >
+
         <View
             android:layout_width="match_parent"
             android:layout_height="2dp"
             android:background="@drawable/tile_shadow_top" />
+
         <HorizontalScrollView
             android:id="@+id/wallpaper_scroll_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" >
-            <LinearLayout android:id="@+id/master_wallpaper_list"
+
+            <LinearLayout
+                android:id="@+id/master_wallpaper_list"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal" >
-                <LinearLayout android:id="@+id/wallpaper_list"
+
+                <LinearLayout
+                    android:id="@+id/wallpaper_list"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:orientation="horizontal" />
-                <LinearLayout android:id="@+id/live_wallpaper_list"
+
+                <LinearLayout
+                    android:id="@+id/live_wallpaper_list"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:orientation="horizontal" />
-                <LinearLayout android:id="@+id/third_party_wallpaper_list"
+
+                <LinearLayout
+                    android:id="@+id/third_party_wallpaper_list"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:orientation="horizontal" />
             </LinearLayout>
         </HorizontalScrollView>
+
         <View
             android:layout_width="match_parent"
             android:layout_height="2dp"
             android:background="@drawable/tile_shadow_bottom" />
     </LinearLayout>
-</com.android.launcher3.WallpaperRootView>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml b/WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml
index ae3c43d..dc65244 100644
--- a/WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml
+++ b/WallpaperPicker/res/layout/wallpaper_picker_image_picker_item.xml
@@ -20,7 +20,6 @@
     android:layout_height="@dimen/wallpaperThumbnailHeight"
     android:focusable="true"
     android:clickable="true"
-    android:background="@drawable/wallpaper_tile_fg"
     android:foreground="@drawable/wallpaper_tile_fg">
     <ImageView
         android:id="@+id/wallpaper_image"
diff --git a/WallpaperPicker/res/layout/wallpaper_picker_item.xml b/WallpaperPicker/res/layout/wallpaper_picker_item.xml
index 0ac8f97..3f57fcd 100644
--- a/WallpaperPicker/res/layout/wallpaper_picker_item.xml
+++ b/WallpaperPicker/res/layout/wallpaper_picker_item.xml
@@ -20,7 +20,6 @@
     android:layout_height="@dimen/wallpaperThumbnailHeight"
     android:focusable="true"
     android:clickable="true"
-    android:background="@drawable/wallpaper_tile_fg"
     android:foreground="@drawable/wallpaper_tile_fg">
     <ImageView
         android:id="@+id/wallpaper_image"
diff --git a/WallpaperPicker/res/layout/wallpaper_picker_live_wallpaper_item.xml b/WallpaperPicker/res/layout/wallpaper_picker_live_wallpaper_item.xml
index 29fdb1b..2b152fc 100644
--- a/WallpaperPicker/res/layout/wallpaper_picker_live_wallpaper_item.xml
+++ b/WallpaperPicker/res/layout/wallpaper_picker_live_wallpaper_item.xml
@@ -20,7 +20,6 @@
     android:layout_height="@dimen/wallpaperThumbnailHeight"
     android:focusable="true"
     android:clickable="true"
-    android:background="@drawable/wallpaper_tile_fg"
     android:foreground="@drawable/wallpaper_tile_fg">
     <ImageView
         android:id="@+id/wallpaper_image"
diff --git a/WallpaperPicker/res/layout/wallpaper_picker_third_party_item.xml b/WallpaperPicker/res/layout/wallpaper_picker_third_party_item.xml
index 68661bc..a7e3a0c 100644
--- a/WallpaperPicker/res/layout/wallpaper_picker_third_party_item.xml
+++ b/WallpaperPicker/res/layout/wallpaper_picker_third_party_item.xml
@@ -20,7 +20,6 @@
     android:layout_height="@dimen/wallpaperThumbnailHeight"
     android:focusable="true"
     android:clickable="true"
-    android:background="@drawable/wallpaper_tile_fg"
     android:foreground="@drawable/wallpaper_tile_fg">
     <ImageView
         android:id="@+id/wallpaper_image"
diff --git a/WallpaperPicker/res/values-af/strings.xml b/WallpaperPicker/res/values-af/strings.xml
index c17d26b..eb81640 100644
--- a/WallpaperPicker/res/values-af/strings.xml
+++ b/WallpaperPicker/res/values-af/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Muurpapier %1$d van %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Het <xliff:g id="LABEL">%1$s</xliff:g> gekies"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Vee uit"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Kies prent"</string>
+    <string name="pick_image" msgid="3189640419551368385">"My foto\'s"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Muurpapiere"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Snoei muurpapier"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-am/strings.xml b/WallpaperPicker/res/values-am/strings.xml
index 59c3bf7..7e79385 100644
--- a/WallpaperPicker/res/values-am/strings.xml
+++ b/WallpaperPicker/res/values-am/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ልጣፍ  %1$d የ%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ተመርጧል"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ሰርዝ"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ምስል ይምረጡ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"የእኔ ፎቶዎች"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"የግድግዳ ወረቀቶች"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ልጣፍ  ይከርክሙ"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ar/strings.xml b/WallpaperPicker/res/values-ar/strings.xml
index 2075cc8..84fa104 100644
--- a/WallpaperPicker/res/values-ar/strings.xml
+++ b/WallpaperPicker/res/values-ar/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"‏الخلفية %1$d من %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"تم تحديد <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"حذف"</string>
-    <string name="pick_image" msgid="6704438906027442697">"اختيار صورة"</string>
+    <string name="pick_image" msgid="3189640419551368385">"صوري"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"الخلفيات"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"اقتصاص الخلفية"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-az-rAZ/strings.xml b/WallpaperPicker/res/values-az-rAZ/strings.xml
index f9d1fcc..883673d 100644
--- a/WallpaperPicker/res/values-az-rAZ/strings.xml
+++ b/WallpaperPicker/res/values-az-rAZ/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Divar kağızı %1$d of %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> seçilib"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Sil"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Şəkil seçin"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Fotolarım"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Divar kağızları"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Divar kağızını kəsin"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-bg/strings.xml b/WallpaperPicker/res/values-bg/strings.xml
index ce4fc65..60ae302 100644
--- a/WallpaperPicker/res/values-bg/strings.xml
+++ b/WallpaperPicker/res/values-bg/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Тапет %1$d от %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Избрахте <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Изтриване"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Избиране на изображение"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Моите снимки"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Тапети"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Подрязване на тапета"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-bn-rBD/strings.xml b/WallpaperPicker/res/values-bn-rBD/strings.xml
index a4fccb2..74d7e57 100644
--- a/WallpaperPicker/res/values-bn-rBD/strings.xml
+++ b/WallpaperPicker/res/values-bn-rBD/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$dটির মধ্যে %1$dটি ওয়ালপেপার"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> নির্বাচন করা হয়েছে"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"মুছুন"</string>
-    <string name="pick_image" msgid="6704438906027442697">"চিত্র বাছুন"</string>
+    <string name="pick_image" msgid="3189640419551368385">"আমার ফটো"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ওয়ালপেপারগুলি"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ওয়ালপেপার কাটছাঁট করুন"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ca/strings.xml b/WallpaperPicker/res/values-ca/strings.xml
index 89de81c..cbec762 100644
--- a/WallpaperPicker/res/values-ca/strings.xml
+++ b/WallpaperPicker/res/values-ca/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fons de pantalla %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"S\'ha seleccionat <xliff:g id="LABEL">%1$s</xliff:g>."</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Suprimeix"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Tria una imatge"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Les meves fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fons de pantalla"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Retallar fons de pantalla"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-cs/strings.xml b/WallpaperPicker/res/values-cs/strings.xml
index a07b9ed..da0758e 100644
--- a/WallpaperPicker/res/values-cs/strings.xml
+++ b/WallpaperPicker/res/values-cs/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Tapeta %1$d z %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Vybrána položka <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Smazat"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Vybrat obrázek"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Moje fotografie"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Tapety"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Oříznutí tapety"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-da/strings.xml b/WallpaperPicker/res/values-da/strings.xml
index 5b233e1..12c0fe8 100644
--- a/WallpaperPicker/res/values-da/strings.xml
+++ b/WallpaperPicker/res/values-da/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Baggrund %1$d af %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> blev valgt"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Slet"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Vælg et billede"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mine billeder"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Baggrunde"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Beskær baggrunden"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-de/strings.xml b/WallpaperPicker/res/values-de/strings.xml
index 11c1cac..3171b3f 100644
--- a/WallpaperPicker/res/values-de/strings.xml
+++ b/WallpaperPicker/res/values-de/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Hintergrund %1$d von %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ausgewählt"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Löschen"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Bild auswählen"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Meine Fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Hintergründe"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Hintergrund zuschneiden"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-el/strings.xml b/WallpaperPicker/res/values-el/strings.xml
index 8e1e78f..2988bec 100644
--- a/WallpaperPicker/res/values-el/strings.xml
+++ b/WallpaperPicker/res/values-el/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Ταπετσαρία %1$d από %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Επιλέχθηκε το <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Διαγραφή"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Επιλογή εικόνας"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Οι φωτογραφίες μου"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Ταπετσαρίες"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Περικοπή ταπετσαρίας"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-en-rAU/strings.xml b/WallpaperPicker/res/values-en-rAU/strings.xml
index c057c0c..30450ee 100644
--- a/WallpaperPicker/res/values-en-rAU/strings.xml
+++ b/WallpaperPicker/res/values-en-rAU/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Wallpaper %1$d of %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Selected <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Delete"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pick image"</string>
+    <string name="pick_image" msgid="3189640419551368385">"My photos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Wallpapers"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Crop wallpaper"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-en-rGB/strings.xml b/WallpaperPicker/res/values-en-rGB/strings.xml
index c057c0c..30450ee 100644
--- a/WallpaperPicker/res/values-en-rGB/strings.xml
+++ b/WallpaperPicker/res/values-en-rGB/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Wallpaper %1$d of %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Selected <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Delete"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pick image"</string>
+    <string name="pick_image" msgid="3189640419551368385">"My photos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Wallpapers"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Crop wallpaper"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-en-rIN/strings.xml b/WallpaperPicker/res/values-en-rIN/strings.xml
index c057c0c..30450ee 100644
--- a/WallpaperPicker/res/values-en-rIN/strings.xml
+++ b/WallpaperPicker/res/values-en-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Wallpaper %1$d of %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Selected <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Delete"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pick image"</string>
+    <string name="pick_image" msgid="3189640419551368385">"My photos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Wallpapers"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Crop wallpaper"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-es-rUS/strings.xml b/WallpaperPicker/res/values-es-rUS/strings.xml
index 768385b..c18ecb2 100644
--- a/WallpaperPicker/res/values-es-rUS/strings.xml
+++ b/WallpaperPicker/res/values-es-rUS/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fondo de pantalla %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> seleccionado"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Eliminar"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Elegir imagen"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mis fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fondos de pantalla"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Recortar fondo de pantalla"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-es/strings.xml b/WallpaperPicker/res/values-es/strings.xml
index 702b6d4..b7221af 100644
--- a/WallpaperPicker/res/values-es/strings.xml
+++ b/WallpaperPicker/res/values-es/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fondo de pantalla %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> seleccionado"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Eliminar"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Seleccionar imagen"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mis fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fondos de pantalla"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Recortar fondo de pantalla"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-et-rEE/strings.xml b/WallpaperPicker/res/values-et-rEE/strings.xml
index c09e223..571a0ff 100644
--- a/WallpaperPicker/res/values-et-rEE/strings.xml
+++ b/WallpaperPicker/res/values-et-rEE/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d/%2$d taustapildist"</string>
     <string name="announce_selection" msgid="123723511662250539">"Valitud on <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Kustuta"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Vali kujutis"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Minu fotod"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Taustapildid"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Taustapildi kärpimine"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-eu-rES/strings.xml b/WallpaperPicker/res/values-eu-rES/strings.xml
index 327550d..45bf7a1 100644
--- a/WallpaperPicker/res/values-eu-rES/strings.xml
+++ b/WallpaperPicker/res/values-eu-rES/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d/%2$d horma-papera"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> hautatu da"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Ezabatu"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Hautatu irudia"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Nire argazkiak"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Horma-paperak"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Ebaki horma-papera"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-fa/strings.xml b/WallpaperPicker/res/values-fa/strings.xml
index e1d26a8..469ec12 100644
--- a/WallpaperPicker/res/values-fa/strings.xml
+++ b/WallpaperPicker/res/values-fa/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"‏کاغذدیواری %1$d از %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> انتخاب شد"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"حذف"</string>
-    <string name="pick_image" msgid="6704438906027442697">"انتخاب تصویر"</string>
+    <string name="pick_image" msgid="3189640419551368385">"عکس‌های من"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"کاغذدیواری‌ها"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"برش کاغذدیواری"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-fi/strings.xml b/WallpaperPicker/res/values-fi/strings.xml
index 0fa4b7b..c82d3e0 100644
--- a/WallpaperPicker/res/values-fi/strings.xml
+++ b/WallpaperPicker/res/values-fi/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Taustakuva %1$d/%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Valittu: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Poista"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Valitse kuva"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Omat valokuvat"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Taustakuvat"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Rajaa taustakuva"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-fr-rCA/strings.xml b/WallpaperPicker/res/values-fr-rCA/strings.xml
index e956706..9256896 100644
--- a/WallpaperPicker/res/values-fr-rCA/strings.xml
+++ b/WallpaperPicker/res/values-fr-rCA/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fond d\'écran %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Sélection : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Supprimer"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Choisir une image"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mes photos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fonds d\'écran"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Rogner le fond d\'écran"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-fr/strings.xml b/WallpaperPicker/res/values-fr/strings.xml
index 37846e0..479a7e4 100644
--- a/WallpaperPicker/res/values-fr/strings.xml
+++ b/WallpaperPicker/res/values-fr/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fond d\'écran %1$d sur %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> sélectionné"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Supprimer"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Sélectionner une image"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mes photos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fonds d\'écran"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Recadrer le fond d\'écran"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-gl-rES/strings.xml b/WallpaperPicker/res/values-gl-rES/strings.xml
index 9f1fd50..0396b2f 100644
--- a/WallpaperPicker/res/values-gl-rES/strings.xml
+++ b/WallpaperPicker/res/values-gl-rES/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fondo de pantalla %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Seleccionaches <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Eliminar"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Escoller imaxe"</string>
+    <string name="pick_image" msgid="3189640419551368385">"As miñas fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fondos de pantalla"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Recortar fondo de pantalla"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-gu-rIN/strings.xml b/WallpaperPicker/res/values-gu-rIN/strings.xml
index acee01c..e201d52 100644
--- a/WallpaperPicker/res/values-gu-rIN/strings.xml
+++ b/WallpaperPicker/res/values-gu-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d માંથી %1$d વૉલપેપર"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> પસંદ કર્યો"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"કાઢી નાખો"</string>
-    <string name="pick_image" msgid="6704438906027442697">"છબી ચૂંટો"</string>
+    <string name="pick_image" msgid="3189640419551368385">"મારા ફોટા"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"વૉલપેપર્સ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"વૉલપેપર કાપો"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-hi/strings.xml b/WallpaperPicker/res/values-hi/strings.xml
index fcb252e..60834e1 100644
--- a/WallpaperPicker/res/values-hi/strings.xml
+++ b/WallpaperPicker/res/values-hi/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"वॉलपेपर %2$d में से %1$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"चयनित <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"हटाएं"</string>
-    <string name="pick_image" msgid="6704438906027442697">"चित्र चुनें"</string>
+    <string name="pick_image" msgid="3189640419551368385">"मेरी फ़ोटो"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"वॉलपेपर"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"वॉलपेपर काटें"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-hr/strings.xml b/WallpaperPicker/res/values-hr/strings.xml
index 3d79e8f..9ed702c 100644
--- a/WallpaperPicker/res/values-hr/strings.xml
+++ b/WallpaperPicker/res/values-hr/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d. pozadinska slika od %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Odabrana je <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Izbriši"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Odaberi sliku"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Moje fotografije"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Pozadine"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Obrezivanje pozadinske slike"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-hu/strings.xml b/WallpaperPicker/res/values-hu/strings.xml
index 703aa12..d8b08fd 100644
--- a/WallpaperPicker/res/values-hu/strings.xml
+++ b/WallpaperPicker/res/values-hu/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d/%2$d. háttérkép"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> kiválasztva"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Törlés"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Kép kiválasztása"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Saját fotók"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Háttérképek"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Háttérkép körbevágása"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-hy-rAM/strings.xml b/WallpaperPicker/res/values-hy-rAM/strings.xml
index f3891dd..027b841 100644
--- a/WallpaperPicker/res/values-hy-rAM/strings.xml
+++ b/WallpaperPicker/res/values-hy-rAM/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d պաստառ՝ %2$d-ից"</string>
     <string name="announce_selection" msgid="123723511662250539">"Ընտրված է <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Ջնջել"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Ընտրել պատկեր"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Իմ լուսանկարները"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Պաստառներ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Եզրատել պաստառը"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-in/strings.xml b/WallpaperPicker/res/values-in/strings.xml
index f216cf3..9155452 100644
--- a/WallpaperPicker/res/values-in/strings.xml
+++ b/WallpaperPicker/res/values-in/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Wallpaper %1$d dari %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> terpilih"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Hapus"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pilih gambar"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Foto saya"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Wallpaper"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Pangkas wallpaper"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-is-rIS/strings.xml b/WallpaperPicker/res/values-is-rIS/strings.xml
index 6d5d680..69e6cd4 100644
--- a/WallpaperPicker/res/values-is-rIS/strings.xml
+++ b/WallpaperPicker/res/values-is-rIS/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Veggfóður %1$d af %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> valið"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Eyða"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Velja mynd"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Myndirnar mínar"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Veggfóður"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Skera veggfóður"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-it/strings.xml b/WallpaperPicker/res/values-it/strings.xml
index c29946f..f4d38d1 100644
--- a/WallpaperPicker/res/values-it/strings.xml
+++ b/WallpaperPicker/res/values-it/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Sfondo %1$d di %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Elemento selezionato: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Elimina"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Scegli l\'immagine"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Le mie foto"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Sfondi"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Ritaglia sfondo"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-iw/strings.xml b/WallpaperPicker/res/values-iw/strings.xml
index ddc96e9..e29f237 100644
--- a/WallpaperPicker/res/values-iw/strings.xml
+++ b/WallpaperPicker/res/values-iw/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"‏טפט %1$d מתוך %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"בחרת <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"מחק"</string>
-    <string name="pick_image" msgid="6704438906027442697">"בחר תמונה"</string>
+    <string name="pick_image" msgid="3189640419551368385">"התמונות שלי"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"טפטים"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"חתוך את הטפט"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ja/strings.xml b/WallpaperPicker/res/values-ja/strings.xml
index 80b0944..e86026b 100644
--- a/WallpaperPicker/res/values-ja/strings.xml
+++ b/WallpaperPicker/res/values-ja/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"壁紙: %1$d/%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"選択: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"削除"</string>
-    <string name="pick_image" msgid="6704438906027442697">"画像を選択"</string>
+    <string name="pick_image" msgid="3189640419551368385">"マイフォト"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"壁紙"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"壁紙のトリミング"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ka-rGE/strings.xml b/WallpaperPicker/res/values-ka-rGE/strings.xml
index 2f59712..1ae1021 100644
--- a/WallpaperPicker/res/values-ka-rGE/strings.xml
+++ b/WallpaperPicker/res/values-ka-rGE/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ფონი %1$d %2$d-დან"</string>
     <string name="announce_selection" msgid="123723511662250539">"არჩეული <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"წაშლა"</string>
-    <string name="pick_image" msgid="6704438906027442697">"სურათის ამორჩევა"</string>
+    <string name="pick_image" msgid="3189640419551368385">"ჩემი ფოტოები"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ფონები"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ფონის ჩამოჭრა"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-kk-rKZ/strings.xml b/WallpaperPicker/res/values-kk-rKZ/strings.xml
index dcf372c..a10e273 100644
--- a/WallpaperPicker/res/values-kk-rKZ/strings.xml
+++ b/WallpaperPicker/res/values-kk-rKZ/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d артқы фон, барлығы %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> таңдалған"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Жою"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Суретті таңдау"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Менің фотосуреттерім"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Артқы фондар"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Артқы фонды кесу"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-km-rKH/strings.xml b/WallpaperPicker/res/values-km-rKH/strings.xml
index 4172235..2a605e8 100644
--- a/WallpaperPicker/res/values-km-rKH/strings.xml
+++ b/WallpaperPicker/res/values-km-rKH/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ផ្ទាំង​រូបភាព %1$d នៃ %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"បាន​ជ្រើស <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"លុប"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ជ្រើស​យក​រូបភាព"</string>
+    <string name="pick_image" msgid="3189640419551368385">"រូបថតរបស់ខ្ញុំ"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ផ្ទាំង​រូបភាព"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ច្រឹប​ផ្ទាំង​រូបភាព"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-kn-rIN/strings.xml b/WallpaperPicker/res/values-kn-rIN/strings.xml
index 89203bf..b69bda5 100644
--- a/WallpaperPicker/res/values-kn-rIN/strings.xml
+++ b/WallpaperPicker/res/values-kn-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d ರಲ್ಲಿ %1$d ವಾಲ್‌ಪೇಪರ್‌"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ಅಳಿಸು"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"ನನ್ನ ಫೋಟೋಗಳು"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ವಾಲ್‌ಪೇಪರ್‌ಗಳು"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ವಾಲ್‌ಪೇಪರ್‌ ಕತ್ತರಿಸಿ"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ko/strings.xml b/WallpaperPicker/res/values-ko/strings.xml
index a5a85b7..30e7cfa 100644
--- a/WallpaperPicker/res/values-ko/strings.xml
+++ b/WallpaperPicker/res/values-ko/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"배경화면 %1$d/%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> 선택함"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"삭제"</string>
-    <string name="pick_image" msgid="6704438906027442697">"이미지 선택"</string>
+    <string name="pick_image" msgid="3189640419551368385">"내 사진"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"배경화면"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"배경화면 잘라내기"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ky-rKG/strings.xml b/WallpaperPicker/res/values-ky-rKG/strings.xml
index 696b3ee..f1ebf09 100644
--- a/WallpaperPicker/res/values-ky-rKG/strings.xml
+++ b/WallpaperPicker/res/values-ky-rKG/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d ичинен %1$d тушкагаз"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> тандалды"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Жок кылуу"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Сүрөт тандоо"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Менин сүрөттөрүм"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Тушкагаздар"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Тушкагазды тегиздөө"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-lo-rLA/strings.xml b/WallpaperPicker/res/values-lo-rLA/strings.xml
index e468591..e32cafb 100644
--- a/WallpaperPicker/res/values-lo-rLA/strings.xml
+++ b/WallpaperPicker/res/values-lo-rLA/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ພາບພື້ນຫຼັງ %1$d ໃນ %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"ເລືອກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ລຶບ"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ເລືອກ​ຮູບ​ພາບ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"ຮູບຂອງຂ້ອຍ"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ພາບພື້ນຫຼັງ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ຕັດພາບພື້ນຫຼັງ"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-lt/strings.xml b/WallpaperPicker/res/values-lt/strings.xml
index 86035b8..c442e3a 100644
--- a/WallpaperPicker/res/values-lt/strings.xml
+++ b/WallpaperPicker/res/values-lt/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d ekrano fonas iš %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Pasirinkta: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Ištrinti"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pasirinkti vaizdą"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mano nuotraukos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Ekrano fonai"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Apkirpti ekrano foną"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-lv/strings.xml b/WallpaperPicker/res/values-lv/strings.xml
index 02e5cfb..d05a175 100644
--- a/WallpaperPicker/res/values-lv/strings.xml
+++ b/WallpaperPicker/res/values-lv/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d. fona tapete no %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Atlasīta: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Dzēst"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Izvēlēties attēlu"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mani fotoattēli"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fona tapetes"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Apgriezt fona tapeti"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-mk-rMK/strings.xml b/WallpaperPicker/res/values-mk-rMK/strings.xml
index b1919cc..f9e0963 100644
--- a/WallpaperPicker/res/values-mk-rMK/strings.xml
+++ b/WallpaperPicker/res/values-mk-rMK/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Тапет %1$d од %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Избран <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Избриши"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Избери слика"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Моите фотографии"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Тапети"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Исечи тапет"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ml-rIN/strings.xml b/WallpaperPicker/res/values-ml-rIN/strings.xml
index 0b6a4c1..6be771c 100644
--- a/WallpaperPicker/res/values-ml-rIN/strings.xml
+++ b/WallpaperPicker/res/values-ml-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d / %2$d വാൾപേപ്പർ"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> തിരഞ്ഞെടുത്തു"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ഇല്ലാതാക്കുക"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
+    <string name="pick_image" msgid="3189640419551368385">"എന്റെ ഫോട്ടോകൾ"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"വാൾപേപ്പറുകൾ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"വാൾപേപ്പറിന്റെ വലുപ്പം മാറ്റൽ"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-mn-rMN/strings.xml b/WallpaperPicker/res/values-mn-rMN/strings.xml
index 71ff9e0..b88da5a 100644
--- a/WallpaperPicker/res/values-mn-rMN/strings.xml
+++ b/WallpaperPicker/res/values-mn-rMN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d ханын цаасны %1$d нь"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> сонгогдсон"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Устгах"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Зураг сонгох"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Миний зураг"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Ханын зураг"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Ханын зургийг тайрах"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-mr-rIN/strings.xml b/WallpaperPicker/res/values-mr-rIN/strings.xml
index 33cfaa1..128b21c 100644
--- a/WallpaperPicker/res/values-mr-rIN/strings.xml
+++ b/WallpaperPicker/res/values-mr-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d पैकी %1$d वॉलपेपर"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> निवडले"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"हटवा"</string>
-    <string name="pick_image" msgid="6704438906027442697">"प्रतिमा निवडा"</string>
+    <string name="pick_image" msgid="3189640419551368385">"माझे फोटो"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"वॉलपेपर"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"वॉलपेपर कापा"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ms-rMY/strings.xml b/WallpaperPicker/res/values-ms-rMY/strings.xml
index 950f4d0..9d824e4 100644
--- a/WallpaperPicker/res/values-ms-rMY/strings.xml
+++ b/WallpaperPicker/res/values-ms-rMY/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Kertas dinding %1$d daripada %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Memilih <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Padam"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pilih imej"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Foto saya"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Kertas dinding"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Pangkas kertas dinding"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-my-rMM/strings.xml b/WallpaperPicker/res/values-my-rMM/strings.xml
index 4d5ac47..2336114 100644
--- a/WallpaperPicker/res/values-my-rMM/strings.xml
+++ b/WallpaperPicker/res/values-my-rMM/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"နောက်ခံ %1$d မှ %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"ရွေးချယ်ထားသော <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ဖျက်ပါ"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ပုံ ရွေးပါ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"ကျွန်ုပ်၏ ဓာတ်ပုံများ"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"နောက်ခံများ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"နောက်ခံအား ဖြတ်ခြင်း"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-nb/strings.xml b/WallpaperPicker/res/values-nb/strings.xml
index 3589e4b..9ae0b98 100644
--- a/WallpaperPicker/res/values-nb/strings.xml
+++ b/WallpaperPicker/res/values-nb/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Bakgrunn %1$d av %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Valgt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Slett"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Velg bilde"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mine bilder"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Bakgrunner"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Beskjær bakgrunnen"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ne-rNP/strings.xml b/WallpaperPicker/res/values-ne-rNP/strings.xml
index 221fa94..5bca8d8 100644
--- a/WallpaperPicker/res/values-ne-rNP/strings.xml
+++ b/WallpaperPicker/res/values-ne-rNP/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d को %1$d वालपेपर"</string>
     <string name="announce_selection" msgid="123723511662250539">"चयन गरिएको <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"मेट्नुहोस्"</string>
-    <string name="pick_image" msgid="6704438906027442697">"तस्बिर छान्नुहोस्"</string>
+    <string name="pick_image" msgid="3189640419551368385">"मेरा तस्बिरहरू"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"वालपेपरहरु"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"वालपेपर काँटछाट गर्नुहोस्"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-nl/strings.xml b/WallpaperPicker/res/values-nl/strings.xml
index 7dd4f22..a86f0f6 100644
--- a/WallpaperPicker/res/values-nl/strings.xml
+++ b/WallpaperPicker/res/values-nl/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Achtergrond %1$d van %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> is geselecteerd"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Verwijderen"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Afbeelding kiezen"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mijn foto\'s"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Achtergronden"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Achtergrond bijsnijden"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-pa-rIN/strings.xml b/WallpaperPicker/res/values-pa-rIN/strings.xml
index 3be7bf8..e4225e0 100644
--- a/WallpaperPicker/res/values-pa-rIN/strings.xml
+++ b/WallpaperPicker/res/values-pa-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"ਵਾਲਪੇਪਰ %2$d ਦਾ %1$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ਮਿਟਾਓ"</string>
-    <string name="pick_image" msgid="6704438906027442697">"ਚਿੱਤਰ ਚੁਣੋ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"ਮੇਰੀਆਂ ਫੋਟੋਆਂ"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"ਵਾਲਪੇਪਰ"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ਵਾਲਪੇਪਰ ਕੱਟੋ"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-pl/strings.xml b/WallpaperPicker/res/values-pl/strings.xml
index bcdbb3d..cd52082 100644
--- a/WallpaperPicker/res/values-pl/strings.xml
+++ b/WallpaperPicker/res/values-pl/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Tapeta %1$d z %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Wybrano <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Usuń"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Wybierz obraz"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Moje zdjęcia"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Tapety"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Przytnij tapetę"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-pt-rPT/strings.xml b/WallpaperPicker/res/values-pt-rPT/strings.xml
index 8349232..82aa469 100644
--- a/WallpaperPicker/res/values-pt-rPT/strings.xml
+++ b/WallpaperPicker/res/values-pt-rPT/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Imagem de fundo %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> selecionada"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Eliminar"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Escolher imagem"</string>
+    <string name="pick_image" msgid="3189640419551368385">"As minhas fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Imagens de fundo"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Recortar imagem de fundo"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-pt/strings.xml b/WallpaperPicker/res/values-pt/strings.xml
index 2332fcb..74ff310 100644
--- a/WallpaperPicker/res/values-pt/strings.xml
+++ b/WallpaperPicker/res/values-pt/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Plano de fundo %1$d de %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> selecionado"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Excluir"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Escolher imagem"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Minhas fotos"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Planos de fundo"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Cortar plano de fundo"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ro/strings.xml b/WallpaperPicker/res/values-ro/strings.xml
index 8ee1a5a..6281b80 100644
--- a/WallpaperPicker/res/values-ro/strings.xml
+++ b/WallpaperPicker/res/values-ro/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Imaginea de fundal %1$d din %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"S-a selectat <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Ștergeți"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Alegeți imaginea"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Fotografiile mele"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Imagini de fundal"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Decupați imaginea de fundal"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ru/strings.xml b/WallpaperPicker/res/values-ru/strings.xml
index ff43ce8..959205a 100644
--- a/WallpaperPicker/res/values-ru/strings.xml
+++ b/WallpaperPicker/res/values-ru/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Обои %1$d из %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Выбран элемент \"<xliff:g id="LABEL">%1$s</xliff:g>\""</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Удалить"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Выбрать обои"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Мои фото"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Обои"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Кадрировать обои"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-si-rLK/strings.xml b/WallpaperPicker/res/values-si-rLK/strings.xml
index d175724..37ce1fc 100644
--- a/WallpaperPicker/res/values-si-rLK/strings.xml
+++ b/WallpaperPicker/res/values-si-rLK/strings.xml
@@ -32,7 +32,7 @@
     <skip />
     <string name="announce_selection" msgid="123723511662250539">"තෝරාගත්තේ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"මකන්න"</string>
-    <string name="pick_image" msgid="6704438906027442697">"පින්තූරයක් තෝරන්න"</string>
+    <string name="pick_image" msgid="3189640419551368385">"මගේ ඡායාරූප"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"වෝල්පේපර"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"වෝල්පේපරය කප්පාදු කිරීම"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sk/strings.xml b/WallpaperPicker/res/values-sk/strings.xml
index 33477a1..9d38de4 100644
--- a/WallpaperPicker/res/values-sk/strings.xml
+++ b/WallpaperPicker/res/values-sk/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Tapeta %1$d z %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Vybratá položka <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Odstrániť"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Vybrať obrázok"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Moje fotky"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Tapety"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Orezanie tapety"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sl/strings.xml b/WallpaperPicker/res/values-sl/strings.xml
index 06a508a..e776cc7 100644
--- a/WallpaperPicker/res/values-sl/strings.xml
+++ b/WallpaperPicker/res/values-sl/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%1$d. ozadje od %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Izbrano: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Izbriši"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Izberi sliko"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Moje fotografije"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Ozadja"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Obrezovanje ozadja"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sq-rAL/strings.xml b/WallpaperPicker/res/values-sq-rAL/strings.xml
index f21b7ef..8a9983b 100644
--- a/WallpaperPicker/res/values-sq-rAL/strings.xml
+++ b/WallpaperPicker/res/values-sq-rAL/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Imazhi i sfondit: %1$d nga gjithsej %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> u përzgjodh"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Fshi"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Zgjidh imazhin"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Fotografitë e mia"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Imazhet e sfondit"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Prit imazhin e sfondit"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sr/strings.xml b/WallpaperPicker/res/values-sr/strings.xml
index fdfaaf6..c37bc06 100644
--- a/WallpaperPicker/res/values-sr/strings.xml
+++ b/WallpaperPicker/res/values-sr/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Позадина %1$d од %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Изабрана је <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Избриши"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Изабери слику"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Моје фотографије"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Позадине"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Опсеци позадину"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sv/strings.xml b/WallpaperPicker/res/values-sv/strings.xml
index 57db3a6..044508b 100644
--- a/WallpaperPicker/res/values-sv/strings.xml
+++ b/WallpaperPicker/res/values-sv/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Bakgrund %1$d av %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> har valts"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Ta bort"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Välj bild"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mina foton"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Bakgrunder"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Beskär bakgrund"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sw/strings.xml b/WallpaperPicker/res/values-sw/strings.xml
index edea3de..367912a 100644
--- a/WallpaperPicker/res/values-sw/strings.xml
+++ b/WallpaperPicker/res/values-sw/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Mandhari %1$d ya %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> iliyochaguliwa"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Futa"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Chagua picha"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Picha zangu"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Mandhari"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Punguza mandhari"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-sw600dp/config.xml b/WallpaperPicker/res/values-sw600dp/config.xml
deleted file mode 100644
index 62342dc..0000000
--- a/WallpaperPicker/res/values-sw600dp/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <bool name="allow_rotation">true</bool>
-</resources>
diff --git a/WallpaperPicker/res/values-sw720dp-v19/styles.xml b/WallpaperPicker/res/values-sw720dp-v19/styles.xml
index 9107851..d8dab22 100644
--- a/WallpaperPicker/res/values-sw720dp-v19/styles.xml
+++ b/WallpaperPicker/res/values-sw720dp-v19/styles.xml
@@ -18,7 +18,7 @@
 -->
 
 <resources>
-    <style name="Theme" parent="android:Theme.Holo.Wallpaper.NoTitleBar">
+    <style name="Theme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:windowTranslucentStatus">true</item>
         <item name="android:windowTranslucentNavigation">true</item>
diff --git a/WallpaperPicker/res/values-sw720dp/dimens.xml b/WallpaperPicker/res/values-sw720dp/dimens.xml
deleted file mode 100644
index 9ae155b..0000000
--- a/WallpaperPicker/res/values-sw720dp/dimens.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <dimen name="app_icon_size">72dp</dimen>
-
-<!-- QSB -->
-    <dimen name="toolbar_button_vertical_padding">8dip</dimen>
-    <dimen name="toolbar_button_horizontal_padding">8dip</dimen>
-
-    <!-- When dragging items on the workspace, the number of dps by which the position of
-     the drag view should be offset from the position of the original view. -->
-    <dimen name="dragViewOffsetX">0dp</dimen>
-    <dimen name="dragViewOffsetY">0dp</dimen>
-</resources>
diff --git a/WallpaperPicker/res/values-sw720dp/styles.xml b/WallpaperPicker/res/values-sw720dp/styles.xml
index b489090..12f8884 100644
--- a/WallpaperPicker/res/values-sw720dp/styles.xml
+++ b/WallpaperPicker/res/values-sw720dp/styles.xml
@@ -18,7 +18,7 @@
 -->
 
 <resources>
-    <style name="Theme" parent="android:Theme.Holo.Wallpaper.NoTitleBar">
+    <style name="Theme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
         <item name="android:windowActionModeOverlay">true</item>
     </style>
 </resources>
diff --git a/WallpaperPicker/res/values-ta-rIN/strings.xml b/WallpaperPicker/res/values-ta-rIN/strings.xml
index 2b98427..7284da8 100644
--- a/WallpaperPicker/res/values-ta-rIN/strings.xml
+++ b/WallpaperPicker/res/values-ta-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"வால்பேப்பர் %1$d / %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட்டது"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"நீக்கு"</string>
-    <string name="pick_image" msgid="6704438906027442697">"படத்தைத் தேர்வுசெய்க"</string>
+    <string name="pick_image" msgid="3189640419551368385">"எனது படங்கள்"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"வால்பேப்பர்கள்"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"வால்பேப்பரைச் செதுக்கு"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-te-rIN/strings.xml b/WallpaperPicker/res/values-te-rIN/strings.xml
index c26f84e..4c5ad2f 100644
--- a/WallpaperPicker/res/values-te-rIN/strings.xml
+++ b/WallpaperPicker/res/values-te-rIN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$dలో %1$dవ వాల్‌పేపర్"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> ఎంచుకోబడింది"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"తొలగించు"</string>
-    <string name="pick_image" msgid="6704438906027442697">"చిత్రాన్ని ఎంచుకోండి"</string>
+    <string name="pick_image" msgid="3189640419551368385">"నా ఫోటోలు"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"వాల్‌పేపర్‌లు"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"వాల్‌పేపర్‌ను కత్తిరించండి"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-th/strings.xml b/WallpaperPicker/res/values-th/strings.xml
index 6b4c235..b3d7a8b 100644
--- a/WallpaperPicker/res/values-th/strings.xml
+++ b/WallpaperPicker/res/values-th/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"วอลเปเปอร์ %1$d จาก %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"เลือก <xliff:g id="LABEL">%1$s</xliff:g> แล้ว"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"ลบ"</string>
-    <string name="pick_image" msgid="6704438906027442697">"เลือกรูปภาพ"</string>
+    <string name="pick_image" msgid="3189640419551368385">"รูปภาพของฉัน"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"วอลเปเปอร์"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"ครอบตัดวอลเปเปอร์"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-tl/strings.xml b/WallpaperPicker/res/values-tl/strings.xml
index c9fe338..db8f4d5 100644
--- a/WallpaperPicker/res/values-tl/strings.xml
+++ b/WallpaperPicker/res/values-tl/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Wallpaper %1$d ng %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Napili ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Tanggalin"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Pumili ng larawan"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Aking mga larawan"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Mga Wallpaper"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"I-crop ang wallpaper"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-tr/strings.xml b/WallpaperPicker/res/values-tr/strings.xml
index 3d03c6b..d1e57ed 100644
--- a/WallpaperPicker/res/values-tr/strings.xml
+++ b/WallpaperPicker/res/values-tr/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"%2$d duvar kağıdı arasından duvar kağıdı %1$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> seçildi"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Sil"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Resim seç"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Fotoğraflarım"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Duvar kağıtları"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Duvar kağıdını kırp"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-uk/strings.xml b/WallpaperPicker/res/values-uk/strings.xml
index 076c882..756e7cf 100644
--- a/WallpaperPicker/res/values-uk/strings.xml
+++ b/WallpaperPicker/res/values-uk/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Фоновий малюнок %1$d з %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"Вибрано <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Видалити"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Вибрати зображення"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Мої фото"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Фонові малюнки"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Обрізати фоновий малюнок"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-ur-rPK/strings.xml b/WallpaperPicker/res/values-ur-rPK/strings.xml
index 7b12d42..86d8163 100644
--- a/WallpaperPicker/res/values-ur-rPK/strings.xml
+++ b/WallpaperPicker/res/values-ur-rPK/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"‏وال پیپر ‎%1$d از ‎%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> کو منتخب کیا گیا"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"حذف کریں"</string>
-    <string name="pick_image" msgid="6704438906027442697">"تصویر منتخب کریں"</string>
+    <string name="pick_image" msgid="3189640419551368385">"میری تصاویر"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"وال پیپرز"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"وال پیپر کو تراشیں"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-uz-rUZ/strings.xml b/WallpaperPicker/res/values-uz-rUZ/strings.xml
index 807d6b4..97d3938 100644
--- a/WallpaperPicker/res/values-uz-rUZ/strings.xml
+++ b/WallpaperPicker/res/values-uz-rUZ/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Fon rasmi %2$ddan %1$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> tanlandi"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"O‘chirish"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Rasm tanlang"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Mening rasmlarim"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Fon rasmlari"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Fon rasmini kesish"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-v21/styles.xml b/WallpaperPicker/res/values-v21/styles.xml
new file mode 100644
index 0000000..582ab8f
--- /dev/null
+++ b/WallpaperPicker/res/values-v21/styles.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="WallpaperCropperActionBar" parent="@android:style/Widget.DeviceDefault.ActionBar">
+        <item name="android:displayOptions">showCustom</item>
+        <item name="android:background">#88000000</item>
+        <item name="android:contentInsetEnd">0dp</item>
+        <item name="android:contentInsetLeft">0dp</item>
+        <item name="android:contentInsetRight">0dp</item>
+        <item name="android:contentInsetStart">0dp</item>
+    </style>
+
+    <style name="ActionBarSetWallpaperStyle" parent="@android:style/Widget.DeviceDefault.ActionButton">
+        <item name="android:textColor">#ffffffff</item>
+        <item name="android:background">?android:attr/selectableItemBackgroundBorderless</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/WallpaperPicker/res/values-vi/strings.xml b/WallpaperPicker/res/values-vi/strings.xml
index d1efbe9..ae00d58 100644
--- a/WallpaperPicker/res/values-vi/strings.xml
+++ b/WallpaperPicker/res/values-vi/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Hình nền %1$d / %2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"<xliff:g id="LABEL">%1$s</xliff:g> được chọn"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Xóa"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Chọn hình ảnh"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Ảnh của tôi"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Hình nền"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Cắt hình nền"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-zh-rCN/strings.xml b/WallpaperPicker/res/values-zh-rCN/strings.xml
index 1def9ed..8bd5342 100644
--- a/WallpaperPicker/res/values-zh-rCN/strings.xml
+++ b/WallpaperPicker/res/values-zh-rCN/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"第%1$d张壁纸,共%2$d张"</string>
     <string name="announce_selection" msgid="123723511662250539">"已选择<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"删除"</string>
-    <string name="pick_image" msgid="6704438906027442697">"选择图片"</string>
+    <string name="pick_image" msgid="3189640419551368385">"我的照片"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"壁纸"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"剪裁壁纸"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-zh-rHK/strings.xml b/WallpaperPicker/res/values-zh-rHK/strings.xml
index 66ba0af..e51d60a 100644
--- a/WallpaperPicker/res/values-zh-rHK/strings.xml
+++ b/WallpaperPicker/res/values-zh-rHK/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"第 %1$d 張桌布,共 %2$d 張"</string>
     <string name="announce_selection" msgid="123723511662250539">"已選取<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"刪除"</string>
-    <string name="pick_image" msgid="6704438906027442697">"選擇圖片"</string>
+    <string name="pick_image" msgid="3189640419551368385">"我的相片"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"桌布"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"裁剪桌布"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-zh-rTW/strings.xml b/WallpaperPicker/res/values-zh-rTW/strings.xml
index 4184976..c12350a 100644
--- a/WallpaperPicker/res/values-zh-rTW/strings.xml
+++ b/WallpaperPicker/res/values-zh-rTW/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"第 %1$d 張桌布,共 %2$d 張"</string>
     <string name="announce_selection" msgid="123723511662250539">"已選取<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"刪除"</string>
-    <string name="pick_image" msgid="6704438906027442697">"選擇圖片"</string>
+    <string name="pick_image" msgid="3189640419551368385">"我的相片"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"桌布"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"裁剪桌布"</string>
 </resources>
diff --git a/WallpaperPicker/res/values-zu/strings.xml b/WallpaperPicker/res/values-zu/strings.xml
index c7d3f33..537b2f3 100644
--- a/WallpaperPicker/res/values-zu/strings.xml
+++ b/WallpaperPicker/res/values-zu/strings.xml
@@ -30,7 +30,7 @@
     <string name="wallpaper_accessibility_name" msgid="4093221025304876354">"Isithombe sangemuva esingu-%1$d kwezingu-%2$d"</string>
     <string name="announce_selection" msgid="123723511662250539">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhethiwe"</string>
     <string name="wallpaper_delete" msgid="1459353972739215344">"Susa"</string>
-    <string name="pick_image" msgid="6704438906027442697">"Khetha isithombe"</string>
+    <string name="pick_image" msgid="3189640419551368385">"Izithombe zami"</string>
     <string name="pick_wallpaper" msgid="4628969645948454559">"Izithombe zangemuva"</string>
     <string name="crop_wallpaper" msgid="4882870800623585836">"Nqampuna isithombe sangemuva"</string>
 </resources>
diff --git a/WallpaperPicker/res/values/config.xml b/WallpaperPicker/res/values/config.xml
index 71580b5..2f5174c 100644
--- a/WallpaperPicker/res/values/config.xml
+++ b/WallpaperPicker/res/values/config.xml
@@ -14,7 +14,6 @@
      limitations under the License.
 -->
 <resources>
-    <bool name="allow_rotation">false</bool>
     <!-- Specifies whether to expand the cropped area on both sides (rather
          than just to one side) -->
     <bool name="center_crop">false</bool>
diff --git a/WallpaperPicker/res/values/strings.xml b/WallpaperPicker/res/values/strings.xml
index 1ee3513..72b1e15 100644
--- a/WallpaperPicker/res/values/strings.xml
+++ b/WallpaperPicker/res/values/strings.xml
@@ -45,7 +45,7 @@
     <!-- Label on button to delete wallpaper(s) -->
     <string name="wallpaper_delete">Delete</string>
     <!-- Label on button in Wallpaper Picker to pick an image -->
-    <string name="pick_image">Pick image</string>
+    <string name="pick_image">My photos</string>
     <!-- Option in "Select wallpaper from" dialog box -->
     <string name="pick_wallpaper">Wallpapers</string>
     <!-- Title of activity for cropping wallpapers -->
diff --git a/WallpaperPicker/res/values/styles.xml b/WallpaperPicker/res/values/styles.xml
index f4008f1..74aeab9 100644
--- a/WallpaperPicker/res/values/styles.xml
+++ b/WallpaperPicker/res/values/styles.xml
@@ -17,7 +17,7 @@
 */
 -->
 
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
     <style name="Theme.WallpaperCropper" parent="@android:style/Theme.DeviceDefault">
         <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
         <item name="android:windowFullscreen">true</item>
@@ -40,5 +40,6 @@
 
     <style name="ActionBarSetWallpaperStyle" parent="@android:style/Widget.DeviceDefault.ActionButton">
         <item name="android:textColor">#ffffffff</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
     </style>
 </resources>
diff --git a/WallpaperPicker/src/android/util/Pools.java b/WallpaperPicker/src/android/util/Pools.java
deleted file mode 100644
index 40bab1e..0000000
--- a/WallpaperPicker/src/android/util/Pools.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-/**
- * Helper class for crating pools of objects. An example use looks like this:
- * <pre>
- * public class MyPooledClass {
- *
- *     private static final SynchronizedPool<MyPooledClass> sPool =
- *             new SynchronizedPool<MyPooledClass>(10);
- *
- *     public static MyPooledClass obtain() {
- *         MyPooledClass instance = sPool.acquire();
- *         return (instance != null) ? instance : new MyPooledClass();
- *     }
- *
- *     public void recycle() {
- *          // Clear state if needed.
- *          sPool.release(this);
- *     }
- *
- *     . . .
- * }
- * </pre>
- *
- * @hide
- */
-public final class Pools {
-
-    /**
-     * Interface for managing a pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static interface Pool<T> {
-
-        /**
-         * @return An instance from the pool if such, null otherwise.
-         */
-        public T acquire();
-
-        /**
-         * Release an instance to the pool.
-         *
-         * @param instance The instance to release.
-         * @return Whether the instance was put in the pool.
-         *
-         * @throws IllegalStateException If the instance is already in the pool.
-         */
-        public boolean release(T instance);
-    }
-
-    private Pools() {
-        /* do nothing - hiding constructor */
-    }
-
-    /**
-     * Simple (non-synchronized) pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static class SimplePool<T> implements Pool<T> {
-        private final Object[] mPool;
-
-        private int mPoolSize;
-
-        /**
-         * Creates a new instance.
-         *
-         * @param maxPoolSize The max pool size.
-         *
-         * @throws IllegalArgumentException If the max pool size is less than zero.
-         */
-        public SimplePool(int maxPoolSize) {
-            if (maxPoolSize <= 0) {
-                throw new IllegalArgumentException("The max pool size must be > 0");
-            }
-            mPool = new Object[maxPoolSize];
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public T acquire() {
-            if (mPoolSize > 0) {
-                final int lastPooledIndex = mPoolSize - 1;
-                T instance = (T) mPool[lastPooledIndex];
-                mPool[lastPooledIndex] = null;
-                mPoolSize--;
-                return instance;
-            }
-            return null;
-        }
-
-        @Override
-        public boolean release(T instance) {
-            if (isInPool(instance)) {
-                throw new IllegalStateException("Already in the pool!");
-            }
-            if (mPoolSize < mPool.length) {
-                mPool[mPoolSize] = instance;
-                mPoolSize++;
-                return true;
-            }
-            return false;
-        }
-
-        private boolean isInPool(T instance) {
-            for (int i = 0; i < mPoolSize; i++) {
-                if (mPool[i] == instance) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Synchronized) pool of objects.
-     *
-     * @param <T> The pooled type.
-     */
-    public static class SynchronizedPool<T> extends SimplePool<T> {
-        private final Object mLock = new Object();
-
-        /**
-         * Creates a new instance.
-         *
-         * @param maxPoolSize The max pool size.
-         *
-         * @throws IllegalArgumentException If the max pool size is less than zero.
-         */
-        public SynchronizedPool(int maxPoolSize) {
-            super(maxPoolSize);
-        }
-
-        @Override
-        public T acquire() {
-            synchronized (mLock) {
-                return super.acquire();
-            }
-        }
-
-        @Override
-        public boolean release(T element) {
-            synchronized (mLock) {
-                return super.release(element);
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
new file mode 100644
index 0000000..45118bf
--- /dev/null
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapCropTask.java
@@ -0,0 +1,405 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.gallery3d.common;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
+
+    public interface OnBitmapCroppedHandler {
+        public void onBitmapCropped(byte[] imageBytes);
+    }
+
+    private static final int DEFAULT_COMPRESS_QUALITY = 90;
+    private static final String LOGTAG = "BitmapCropTask";
+
+    Uri mInUri = null;
+    Context mContext;
+    String mInFilePath;
+    byte[] mInImageBytes;
+    int mInResId = 0;
+    RectF mCropBounds = null;
+    int mOutWidth, mOutHeight;
+    int mRotation;
+    boolean mSetWallpaper;
+    boolean mSaveCroppedBitmap;
+    Bitmap mCroppedBitmap;
+    Runnable mOnEndRunnable;
+    Resources mResources;
+    BitmapCropTask.OnBitmapCroppedHandler mOnBitmapCroppedHandler;
+    boolean mNoCrop;
+
+    public BitmapCropTask(Context c, String filePath,
+            RectF cropBounds, int rotation, int outWidth, int outHeight,
+            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+        mContext = c;
+        mInFilePath = filePath;
+        init(cropBounds, rotation,
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+    }
+
+    public BitmapCropTask(byte[] imageBytes,
+            RectF cropBounds, int rotation, int outWidth, int outHeight,
+            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+        mInImageBytes = imageBytes;
+        init(cropBounds, rotation,
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+    }
+
+    public BitmapCropTask(Context c, Uri inUri,
+            RectF cropBounds, int rotation, int outWidth, int outHeight,
+            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+        mContext = c;
+        mInUri = inUri;
+        init(cropBounds, rotation,
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+    }
+
+    public BitmapCropTask(Context c, Resources res, int inResId,
+            RectF cropBounds, int rotation, int outWidth, int outHeight,
+            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+        mContext = c;
+        mInResId = inResId;
+        mResources = res;
+        init(cropBounds, rotation,
+                outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
+    }
+
+    private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
+            boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
+        mCropBounds = cropBounds;
+        mRotation = rotation;
+        mOutWidth = outWidth;
+        mOutHeight = outHeight;
+        mSetWallpaper = setWallpaper;
+        mSaveCroppedBitmap = saveCroppedBitmap;
+        mOnEndRunnable = onEndRunnable;
+    }
+
+    public void setOnBitmapCropped(BitmapCropTask.OnBitmapCroppedHandler handler) {
+        mOnBitmapCroppedHandler = handler;
+    }
+
+    public void setNoCrop(boolean value) {
+        mNoCrop = value;
+    }
+
+    public void setOnEndRunnable(Runnable onEndRunnable) {
+        mOnEndRunnable = onEndRunnable;
+    }
+
+    // Helper to setup input stream
+    private InputStream regenerateInputStream() {
+        if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
+            Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
+                    "image byte array given");
+        } else {
+            try {
+                if (mInUri != null) {
+                    return new BufferedInputStream(
+                            mContext.getContentResolver().openInputStream(mInUri));
+                } else if (mInFilePath != null) {
+                    return mContext.openFileInput(mInFilePath);
+                } else if (mInImageBytes != null) {
+                    return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes));
+                } else {
+                    return new BufferedInputStream(mResources.openRawResource(mInResId));
+                }
+            } catch (FileNotFoundException e) {
+                Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
+            }
+        }
+        return null;
+    }
+
+    public Point getImageBounds() {
+        InputStream is = regenerateInputStream();
+        if (is != null) {
+            BitmapFactory.Options options = new BitmapFactory.Options();
+            options.inJustDecodeBounds = true;
+            BitmapFactory.decodeStream(is, null, options);
+            Utils.closeSilently(is);
+            if (options.outWidth != 0 && options.outHeight != 0) {
+                return new Point(options.outWidth, options.outHeight);
+            }
+        }
+        return null;
+    }
+
+    public void setCropBounds(RectF cropBounds) {
+        mCropBounds = cropBounds;
+    }
+
+    public Bitmap getCroppedBitmap() {
+        return mCroppedBitmap;
+    }
+    public boolean cropBitmap() {
+        boolean failure = false;
+
+
+        WallpaperManager wallpaperManager = null;
+        if (mSetWallpaper) {
+            wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
+        }
+
+
+        if (mSetWallpaper && mNoCrop) {
+            try {
+                InputStream is = regenerateInputStream();
+                if (is != null) {
+                    wallpaperManager.setStream(is);
+                    Utils.closeSilently(is);
+                }
+            } catch (IOException e) {
+                Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+                failure = true;
+            }
+            return !failure;
+        } else {
+            // Find crop bounds (scaled to original image size)
+            Rect roundedTrueCrop = new Rect();
+            Matrix rotateMatrix = new Matrix();
+            Matrix inverseRotateMatrix = new Matrix();
+
+            Point bounds = getImageBounds();
+            if (mRotation > 0) {
+                rotateMatrix.setRotate(mRotation);
+                inverseRotateMatrix.setRotate(-mRotation);
+
+                mCropBounds.roundOut(roundedTrueCrop);
+                mCropBounds = new RectF(roundedTrueCrop);
+
+                if (bounds == null) {
+                    Log.w(LOGTAG, "cannot get bounds for image");
+                    failure = true;
+                    return false;
+                }
+
+                float[] rotatedBounds = new float[] { bounds.x, bounds.y };
+                rotateMatrix.mapPoints(rotatedBounds);
+                rotatedBounds[0] = Math.abs(rotatedBounds[0]);
+                rotatedBounds[1] = Math.abs(rotatedBounds[1]);
+
+                mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
+                inverseRotateMatrix.mapRect(mCropBounds);
+                mCropBounds.offset(bounds.x/2, bounds.y/2);
+
+            }
+
+            mCropBounds.roundOut(roundedTrueCrop);
+
+            if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
+                Log.w(LOGTAG, "crop has bad values for full size image");
+                failure = true;
+                return false;
+            }
+
+            // See how much we're reducing the size of the image
+            int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
+                    roundedTrueCrop.height() / mOutHeight));
+            // Attempt to open a region decoder
+            BitmapRegionDecoder decoder = null;
+            InputStream is = null;
+            try {
+                is = regenerateInputStream();
+                if (is == null) {
+                    Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
+                    failure = true;
+                    return false;
+                }
+                decoder = BitmapRegionDecoder.newInstance(is, false);
+                Utils.closeSilently(is);
+            } catch (IOException e) {
+                Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
+            } finally {
+               Utils.closeSilently(is);
+               is = null;
+            }
+
+            Bitmap crop = null;
+            if (decoder != null) {
+                // Do region decoding to get crop bitmap
+                BitmapFactory.Options options = new BitmapFactory.Options();
+                if (scaleDownSampleSize > 1) {
+                    options.inSampleSize = scaleDownSampleSize;
+                }
+                crop = decoder.decodeRegion(roundedTrueCrop, options);
+                decoder.recycle();
+            }
+
+            if (crop == null) {
+                // BitmapRegionDecoder has failed, try to crop in-memory
+                is = regenerateInputStream();
+                Bitmap fullSize = null;
+                if (is != null) {
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    if (scaleDownSampleSize > 1) {
+                        options.inSampleSize = scaleDownSampleSize;
+                    }
+                    fullSize = BitmapFactory.decodeStream(is, null, options);
+                    Utils.closeSilently(is);
+                }
+                if (fullSize != null) {
+                    // Find out the true sample size that was used by the decoder
+                    scaleDownSampleSize = bounds.x / fullSize.getWidth();
+                    mCropBounds.left /= scaleDownSampleSize;
+                    mCropBounds.top /= scaleDownSampleSize;
+                    mCropBounds.bottom /= scaleDownSampleSize;
+                    mCropBounds.right /= scaleDownSampleSize;
+                    mCropBounds.roundOut(roundedTrueCrop);
+
+                    // Adjust values to account for issues related to rounding
+                    if (roundedTrueCrop.width() > fullSize.getWidth()) {
+                        // Adjust the width
+                        roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth();
+                    }
+                    if (roundedTrueCrop.right > fullSize.getWidth()) {
+                        // Adjust the left value
+                        int adjustment = roundedTrueCrop.left -
+                                Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width());
+                        roundedTrueCrop.left -= adjustment;
+                        roundedTrueCrop.right -= adjustment;
+                    }
+                    if (roundedTrueCrop.height() > fullSize.getHeight()) {
+                        // Adjust the height
+                        roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight();
+                    }
+                    if (roundedTrueCrop.bottom > fullSize.getHeight()) {
+                        // Adjust the top value
+                        int adjustment = roundedTrueCrop.top -
+                                Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height());
+                        roundedTrueCrop.top -= adjustment;
+                        roundedTrueCrop.bottom -= adjustment;
+                    }
+
+                    crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
+                            roundedTrueCrop.top, roundedTrueCrop.width(),
+                            roundedTrueCrop.height());
+                }
+            }
+
+            if (crop == null) {
+                Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
+                failure = true;
+                return false;
+            }
+            if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
+                float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
+                rotateMatrix.mapPoints(dimsAfter);
+                dimsAfter[0] = Math.abs(dimsAfter[0]);
+                dimsAfter[1] = Math.abs(dimsAfter[1]);
+
+                if (!(mOutWidth > 0 && mOutHeight > 0)) {
+                    mOutWidth = Math.round(dimsAfter[0]);
+                    mOutHeight = Math.round(dimsAfter[1]);
+                }
+
+                RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
+                RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
+
+                Matrix m = new Matrix();
+                if (mRotation == 0) {
+                    m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+                } else {
+                    Matrix m1 = new Matrix();
+                    m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
+                    Matrix m2 = new Matrix();
+                    m2.setRotate(mRotation);
+                    Matrix m3 = new Matrix();
+                    m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
+                    Matrix m4 = new Matrix();
+                    m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
+
+                    Matrix c1 = new Matrix();
+                    c1.setConcat(m2, m1);
+                    Matrix c2 = new Matrix();
+                    c2.setConcat(m4, m3);
+                    m.setConcat(c2, c1);
+                }
+
+                Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
+                        (int) returnRect.height(), Bitmap.Config.ARGB_8888);
+                if (tmp != null) {
+                    Canvas c = new Canvas(tmp);
+                    Paint p = new Paint();
+                    p.setFilterBitmap(true);
+                    c.drawBitmap(crop, m, p);
+                    crop = tmp;
+                }
+            }
+
+            if (mSaveCroppedBitmap) {
+                mCroppedBitmap = crop;
+            }
+
+            // Compress to byte array
+            ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
+            if (crop.compress(CompressFormat.JPEG, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
+                // If we need to set to the wallpaper, set it
+                if (mSetWallpaper && wallpaperManager != null) {
+                    try {
+                        byte[] outByteArray = tmpOut.toByteArray();
+                        wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
+                        if (mOnBitmapCroppedHandler != null) {
+                            mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
+                        }
+                    } catch (IOException e) {
+                        Log.w(LOGTAG, "cannot write stream to wallpaper", e);
+                        failure = true;
+                    }
+                }
+            } else {
+                Log.w(LOGTAG, "cannot compress bitmap");
+                failure = true;
+            }
+        }
+        return !failure; // True if any of the operations failed
+    }
+
+    @Override
+    protected Boolean doInBackground(Void... params) {
+        return cropBitmap();
+    }
+
+    @Override
+    protected void onPostExecute(Boolean result) {
+        if (mOnEndRunnable != null) {
+            mOnEndRunnable.run();
+        }
+    }
+}
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
index a671ed2..9ac5c1b 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java
@@ -16,87 +16,24 @@
 
 package com.android.gallery3d.common;
 
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.os.Build;
-import android.util.FloatMath;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
 import android.util.Log;
 
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import com.android.gallery3d.exif.ExifInterface;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 
 public class BitmapUtils {
+
     private static final String TAG = "BitmapUtils";
-    private static final int DEFAULT_JPEG_QUALITY = 90;
-    public static final int UNCONSTRAINED = -1;
-
-    private BitmapUtils(){}
-
-    /*
-     * Compute the sample size as a function of minSideLength
-     * and maxNumOfPixels.
-     * minSideLength is used to specify that minimal width or height of a
-     * bitmap.
-     * maxNumOfPixels is used to specify the maximal size in pixels that is
-     * tolerable in terms of memory usage.
-     *
-     * The function returns a sample size based on the constraints.
-     * Both size and minSideLength can be passed in as UNCONSTRAINED,
-     * which indicates no care of the corresponding constraint.
-     * The functions prefers returning a sample size that
-     * generates a smaller bitmap, unless minSideLength = UNCONSTRAINED.
-     *
-     * Also, the function rounds up the sample size to a power of 2 or multiple
-     * of 8 because BitmapFactory only honors sample size this way.
-     * For example, BitmapFactory downsamples an image by 2 even though the
-     * request is 3. So we round up the sample size to avoid OOM.
-     */
-    public static int computeSampleSize(int width, int height,
-            int minSideLength, int maxNumOfPixels) {
-        int initialSize = computeInitialSampleSize(
-                width, height, minSideLength, maxNumOfPixels);
-
-        return initialSize <= 8
-                ? Utils.nextPowerOf2(initialSize)
-                : (initialSize + 7) / 8 * 8;
-    }
-
-    private static int computeInitialSampleSize(int w, int h,
-            int minSideLength, int maxNumOfPixels) {
-        if (maxNumOfPixels == UNCONSTRAINED
-                && minSideLength == UNCONSTRAINED) return 1;
-
-        int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
-                (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels));
-
-        if (minSideLength == UNCONSTRAINED) {
-            return lowerBound;
-        } else {
-            int sampleSize = Math.min(w / minSideLength, h / minSideLength);
-            return Math.max(sampleSize, lowerBound);
-        }
-    }
-
-    // This computes a sample size which makes the longer side at least
-    // minSideLength long. If that's not possible, return 1.
-    public static int computeSampleSizeLarger(int w, int h,
-            int minSideLength) {
-        int initialSize = Math.max(w / minSideLength, h / minSideLength);
-        if (initialSize <= 1) return 1;
-
-        return initialSize <= 8
-                ? Utils.prevPowerOf2(initialSize)
-                : initialSize / 8 * 8;
-    }
 
     // Find the min x that 1 / x >= scale
     public static int computeSampleSizeLarger(float scale) {
-        int initialSize = (int) FloatMath.floor(1f / scale);
+        int initialSize = (int) Math.floor(1f / scale);
         if (initialSize <= 1) return 1;
 
         return initialSize <= 8
@@ -104,157 +41,41 @@
                 : initialSize / 8 * 8;
     }
 
-    // Find the max x that 1 / x <= scale.
-    public static int computeSampleSize(float scale) {
-        Utils.assertTrue(scale > 0);
-        int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale));
-        return initialSize <= 8
-                ? Utils.nextPowerOf2(initialSize)
-                : (initialSize + 7) / 8 * 8;
+    public static int getRotationFromExif(Context context, Uri uri) {
+        return BitmapUtils.getRotationFromExifHelper(null, 0, context, uri);
     }
 
-    public static Bitmap resizeBitmapByScale(
-            Bitmap bitmap, float scale, boolean recycle) {
-        int width = Math.round(bitmap.getWidth() * scale);
-        int height = Math.round(bitmap.getHeight() * scale);
-        if (width == bitmap.getWidth()
-                && height == bitmap.getHeight()) return bitmap;
-        Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
-        Canvas canvas = new Canvas(target);
-        canvas.scale(scale, scale);
-        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
-        canvas.drawBitmap(bitmap, 0, 0, paint);
-        if (recycle) bitmap.recycle();
-        return target;
+    public static int getRotationFromExif(Resources res, int resId) {
+        return BitmapUtils.getRotationFromExifHelper(res, resId, null, null);
     }
 
-    private static Bitmap.Config getConfig(Bitmap bitmap) {
-        Bitmap.Config config = bitmap.getConfig();
-        if (config == null) {
-            config = Bitmap.Config.ARGB_8888;
-        }
-        return config;
-    }
-
-    public static Bitmap resizeDownBySideLength(
-            Bitmap bitmap, int maxLength, boolean recycle) {
-        int srcWidth = bitmap.getWidth();
-        int srcHeight = bitmap.getHeight();
-        float scale = Math.min(
-                (float) maxLength / srcWidth, (float) maxLength / srcHeight);
-        if (scale >= 1.0f) return bitmap;
-        return resizeBitmapByScale(bitmap, scale, recycle);
-    }
-
-    public static Bitmap resizeAndCropCenter(Bitmap bitmap, int size, boolean recycle) {
-        int w = bitmap.getWidth();
-        int h = bitmap.getHeight();
-        if (w == size && h == size) return bitmap;
-
-        // scale the image so that the shorter side equals to the target;
-        // the longer side will be center-cropped.
-        float scale = (float) size / Math.min(w,  h);
-
-        Bitmap target = Bitmap.createBitmap(size, size, getConfig(bitmap));
-        int width = Math.round(scale * bitmap.getWidth());
-        int height = Math.round(scale * bitmap.getHeight());
-        Canvas canvas = new Canvas(target);
-        canvas.translate((size - width) / 2f, (size - height) / 2f);
-        canvas.scale(scale, scale);
-        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
-        canvas.drawBitmap(bitmap, 0, 0, paint);
-        if (recycle) bitmap.recycle();
-        return target;
-    }
-
-    public static void recycleSilently(Bitmap bitmap) {
-        if (bitmap == null) return;
+    private static int getRotationFromExifHelper(Resources res, int resId, Context context, Uri uri) {
+        ExifInterface ei = new ExifInterface();
+        InputStream is = null;
+        BufferedInputStream bis = null;
         try {
-            bitmap.recycle();
-        } catch (Throwable t) {
-            Log.w(TAG, "unable recycle bitmap", t);
-        }
-    }
-
-    public static Bitmap rotateBitmap(Bitmap source, int rotation, boolean recycle) {
-        if (rotation == 0) return source;
-        int w = source.getWidth();
-        int h = source.getHeight();
-        Matrix m = new Matrix();
-        m.postRotate(rotation);
-        Bitmap bitmap = Bitmap.createBitmap(source, 0, 0, w, h, m, true);
-        if (recycle) source.recycle();
-        return bitmap;
-    }
-
-    public static Bitmap createVideoThumbnail(String filePath) {
-        // MediaMetadataRetriever is available on API Level 8
-        // but is hidden until API Level 10
-        Class<?> clazz = null;
-        Object instance = null;
-        try {
-            clazz = Class.forName("android.media.MediaMetadataRetriever");
-            instance = clazz.newInstance();
-
-            Method method = clazz.getMethod("setDataSource", String.class);
-            method.invoke(instance, filePath);
-
-            // The method name changes between API Level 9 and 10.
-            if (Build.VERSION.SDK_INT <= 9) {
-                return (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
+            if (uri != null) {
+                is = context.getContentResolver().openInputStream(uri);
+                bis = new BufferedInputStream(is);
+                ei.readExif(bis);
             } else {
-                byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
-                if (data != null) {
-                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                    if (bitmap != null) return bitmap;
-                }
-                return (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
+                is = res.openRawResource(resId);
+                bis = new BufferedInputStream(is);
+                ei.readExif(bis);
             }
-        } catch (IllegalArgumentException ex) {
-            // Assume this is a corrupt video file
-        } catch (RuntimeException ex) {
-            // Assume this is a corrupt video file.
-        } catch (InstantiationException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (ClassNotFoundException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "createVideoThumbnail", e);
+            Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
+            if (ori != null) {
+                return ExifInterface.getRotationForOrientationValue(ori.shortValue());
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "Getting exif data failed", e);
+        } catch (NullPointerException e) {
+            // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid
+            Log.w(TAG, "Getting exif data failed", e);
         } finally {
-            try {
-                if (instance != null) {
-                    clazz.getMethod("release").invoke(instance);
-                }
-            } catch (Exception ignored) {
-            }
+            Utils.closeSilently(bis);
+            Utils.closeSilently(is);
         }
-        return null;
-    }
-
-    public static byte[] compressToBytes(Bitmap bitmap) {
-        return compressToBytes(bitmap, DEFAULT_JPEG_QUALITY);
-    }
-
-    public static byte[] compressToBytes(Bitmap bitmap, int quality) {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream(65536);
-        bitmap.compress(CompressFormat.JPEG, quality, baos);
-        return baos.toByteArray();
-    }
-
-    public static boolean isSupportedByRegionDecoder(String mimeType) {
-        if (mimeType == null) return false;
-        mimeType = mimeType.toLowerCase();
-        return mimeType.startsWith("image/") &&
-                (!mimeType.equals("image/gif") && !mimeType.endsWith("bmp"));
-    }
-
-    public static boolean isRotationSupported(String mimeType) {
-        if (mimeType == null) return false;
-        mimeType = mimeType.toLowerCase();
-        return mimeType.equals("image/jpeg");
+        return 0;
     }
 }
diff --git a/WallpaperPicker/src/com/android/gallery3d/common/Utils.java b/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
index 614a081..8466c22 100644
--- a/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
+++ b/WallpaperPicker/src/com/android/gallery3d/common/Utils.java
@@ -16,32 +16,16 @@
 
 package com.android.gallery3d.common;
 
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.Cursor;
-import android.os.Build;
+import android.graphics.RectF;
 import android.os.ParcelFileDescriptor;
-import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.Closeable;
 import java.io.IOException;
-import java.io.InterruptedIOException;
 
 public class Utils {
     private static final String TAG = "Utils";
-    private static final String DEBUG_TAG = "GalleryDebug";
-
-    private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
-    private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
-
-    private static long[] sCrcTable = new long[256];
-
-    private static final boolean IS_DEBUG_BUILD =
-            Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug");
-
-    private static final String MASK_STRING = "********************************";
 
     // Throws AssertionError if the input is false.
     public static void assertTrue(boolean cond) {
@@ -50,28 +34,6 @@
         }
     }
 
-    // Throws AssertionError with the message. We had a method having the form
-    //   assertTrue(boolean cond, String message, Object ... args);
-    // However a call to that method will cause memory allocation even if the
-    // condition is false (due to autoboxing generated by "Object ... args"),
-    // so we don't use that anymore.
-    public static void fail(String message, Object ... args) {
-        throw new AssertionError(
-                args.length == 0 ? message : String.format(message, args));
-    }
-
-    // Throws NullPointerException if the input is null.
-    public static <T> T checkNotNull(T object) {
-        if (object == null) throw new NullPointerException();
-        return object;
-    }
-
-    // Returns true if two input Object are both null or equal
-    // to each other.
-    public static boolean equals(Object a, Object b) {
-        return (a == b) || (a == null ? false : a.equals(b));
-    }
-
     // Returns the next power of two.
     // Returns the input if it is already power of 2.
     // Throws IllegalArgumentException if the input is <= 0 or
@@ -102,87 +64,6 @@
         return x;
     }
 
-    // Returns the input value x clamped to the range [min, max].
-    public static float clamp(float x, float min, float max) {
-        if (x > max) return max;
-        if (x < min) return min;
-        return x;
-    }
-
-    // Returns the input value x clamped to the range [min, max].
-    public static long clamp(long x, long min, long max) {
-        if (x > max) return max;
-        if (x < min) return min;
-        return x;
-    }
-
-    public static boolean isOpaque(int color) {
-        return color >>> 24 == 0xFF;
-    }
-
-    public static void swap(int[] array, int i, int j) {
-        int temp = array[i];
-        array[i] = array[j];
-        array[j] = temp;
-    }
-
-    /**
-     * A function thats returns a 64-bit crc for string
-     *
-     * @param in input string
-     * @return a 64-bit crc value
-     */
-    public static final long crc64Long(String in) {
-        if (in == null || in.length() == 0) {
-            return 0;
-        }
-        return crc64Long(getBytes(in));
-    }
-
-    static {
-        // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
-        long part;
-        for (int i = 0; i < 256; i++) {
-            part = i;
-            for (int j = 0; j < 8; j++) {
-                long x = ((int) part & 1) != 0 ? POLY64REV : 0;
-                part = (part >> 1) ^ x;
-            }
-            sCrcTable[i] = part;
-        }
-    }
-
-    public static final long crc64Long(byte[] buffer) {
-        long crc = INITIALCRC;
-        for (int k = 0, n = buffer.length; k < n; ++k) {
-            crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
-        }
-        return crc;
-    }
-
-    public static byte[] getBytes(String in) {
-        byte[] result = new byte[in.length() * 2];
-        int output = 0;
-        for (char ch : in.toCharArray()) {
-            result[output++] = (byte) (ch & 0xFF);
-            result[output++] = (byte) (ch >> 8);
-        }
-        return result;
-    }
-
-    public static void closeSilently(Closeable c) {
-        if (c == null) return;
-        try {
-            c.close();
-        } catch (IOException t) {
-            Log.w(TAG, "close fail ", t);
-        }
-    }
-
-    public static int compare(long a, long b) {
-        return a < b ? -1 : a == b ? 0 : 1;
-    }
-
     public static int ceilLog2(float value) {
         int i;
         for (i = 0; i < 31; i++) {
@@ -199,6 +80,15 @@
         return i - 1;
     }
 
+    public static void closeSilently(Closeable c) {
+        if (c == null) return;
+        try {
+            c.close();
+        } catch (IOException t) {
+            Log.w(TAG, "close fail ", t);
+        }
+    }
+
     public static void closeSilently(ParcelFileDescriptor fd) {
         try {
             if (fd != null) fd.close();
@@ -215,126 +105,25 @@
         }
     }
 
-    public static float interpolateAngle(
-            float source, float target, float progress) {
-        // interpolate the angle from source to target
-        // We make the difference in the range of [-179, 180], this is the
-        // shortest path to change source to target.
-        float diff = target - source;
-        if (diff < 0) diff += 360f;
-        if (diff > 180) diff -= 360f;
-
-        float result = source + diff * progress;
-        return result < 0 ? result + 360f : result;
-    }
-
-    public static float interpolateScale(
-            float source, float target, float progress) {
-        return source + progress * (target - source);
-    }
-
-    public static String ensureNotNull(String value) {
-        return value == null ? "" : value;
-    }
-
-    public static float parseFloatSafely(String content, float defaultValue) {
-        if (content == null) return defaultValue;
-        try {
-            return Float.parseFloat(content);
-        } catch (NumberFormatException e) {
-            return defaultValue;
+    public static RectF getMaxCropRect(
+            int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
+        RectF cropRect = new RectF();
+        // Get a crop rect that will fit this
+        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
+             cropRect.top = 0;
+             cropRect.bottom = inHeight;
+             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
+             cropRect.right = inWidth - cropRect.left;
+             if (leftAligned) {
+                 cropRect.right -= cropRect.left;
+                 cropRect.left = 0;
+             }
+        } else {
+            cropRect.left = 0;
+            cropRect.right = inWidth;
+            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
+            cropRect.bottom = inHeight - cropRect.top;
         }
-    }
-
-    public static int parseIntSafely(String content, int defaultValue) {
-        if (content == null) return defaultValue;
-        try {
-            return Integer.parseInt(content);
-        } catch (NumberFormatException e) {
-            return defaultValue;
-        }
-    }
-
-    public static boolean isNullOrEmpty(String exifMake) {
-        return TextUtils.isEmpty(exifMake);
-    }
-
-    public static void waitWithoutInterrupt(Object object) {
-        try {
-            object.wait();
-        } catch (InterruptedException e) {
-            Log.w(TAG, "unexpected interrupt: " + object);
-        }
-    }
-
-    public static boolean handleInterrruptedException(Throwable e) {
-        // A helper to deal with the interrupt exception
-        // If an interrupt detected, we will setup the bit again.
-        if (e instanceof InterruptedIOException
-                || e instanceof InterruptedException) {
-            Thread.currentThread().interrupt();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @return String with special XML characters escaped.
-     */
-    public static String escapeXml(String s) {
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0, len = s.length(); i < len; ++i) {
-            char c = s.charAt(i);
-            switch (c) {
-                case '<':  sb.append("&lt;"); break;
-                case '>':  sb.append("&gt;"); break;
-                case '\"': sb.append("&quot;"); break;
-                case '\'': sb.append("&#039;"); break;
-                case '&':  sb.append("&amp;"); break;
-                default: sb.append(c);
-            }
-        }
-        return sb.toString();
-    }
-
-    public static String getUserAgent(Context context) {
-        PackageInfo packageInfo;
-        try {
-            packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
-        } catch (NameNotFoundException e) {
-            throw new IllegalStateException("getPackageInfo failed");
-        }
-        return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s",
-                packageInfo.packageName,
-                packageInfo.versionName,
-                Build.BRAND,
-                Build.DEVICE,
-                Build.MODEL,
-                Build.ID,
-                Build.VERSION.SDK_INT,
-                Build.VERSION.RELEASE,
-                Build.VERSION.INCREMENTAL);
-    }
-
-    public static String[] copyOf(String[] source, int newSize) {
-        String[] result = new String[newSize];
-        newSize = Math.min(source.length, newSize);
-        System.arraycopy(source, 0, result, 0, newSize);
-        return result;
-    }
-
-    // Mask information for debugging only. It returns <code>info.toString()</code> directly
-    // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask ("****")
-    // in release build to protect the information (e.g. for privacy issue).
-    public static String maskDebugInfo(Object info) {
-        if (info == null) return null;
-        String s = info.toString();
-        int length = Math.min(s.length(), MASK_STRING.length());
-        return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length);
-    }
-
-    // This method should be ONLY used for debugging.
-    public static void debug(String message, Object ... args) {
-        Log.v(DEBUG_TAG, String.format(message, args));
+        return cropRect;
     }
 }
diff --git a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
index a1cf0fc..9247e87 100644
--- a/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
+++ b/WallpaperPicker/src/com/android/gallery3d/exif/ExifInterface.java
@@ -1247,7 +1247,7 @@
         if (l == null || l.length <= 0) {
             return null;
         }
-        return new Long(l[0]);
+        return Long.valueOf(l[0]);
     }
 
     /**
@@ -1266,7 +1266,7 @@
         if (l == null || l.length <= 0) {
             return null;
         }
-        return new Integer(l[0]);
+        return Integer.valueOf(l[0]);
     }
 
     /**
@@ -1285,7 +1285,7 @@
         if (l == null || l.length <= 0) {
             return null;
         }
-        return new Byte(l[0]);
+        return Byte.valueOf(l[0]);
     }
 
     /**
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
index 2e77b90..0f3efb7 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BasicTexture.java
@@ -27,7 +27,6 @@
 // If a BasicTexture is loaded into GL memory, it has a GL texture id.
 public abstract class BasicTexture implements Texture {
 
-    @SuppressWarnings("unused")
     private static final String TAG = "BasicTexture";
     protected static final int UNSPECIFIED = -1;
 
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index 100b0b3..f8b01cb 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -18,7 +18,7 @@
 
 import android.graphics.Bitmap;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
 
 // BitmapTexture is a texture whose content is specified by a fixed Bitmap.
 //
@@ -34,7 +34,7 @@
 
     public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
         super(hasBorder);
-        Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+        Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
         mContentBitmap = bitmap;
     }
 
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
index 4ead131..933260b 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -23,8 +23,6 @@
 import android.opengl.Matrix;
 import android.util.Log;
 
-import com.android.gallery3d.util.IntArray;
-
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -698,6 +696,7 @@
     }
 
     private void prepareTexture(BasicTexture texture, int program, ShaderParameter[] params) {
+        deleteRecycledResources();
         GLES20.glUseProgram(program);
         checkError();
         enableBlending(!texture.isOpaque() || getAlpha() < OPAQUE_ALPHA);
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
index 16b2206..b26e9ab 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -16,7 +16,7 @@
 
 package com.android.gallery3d.glrenderer;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
 
 public class GLPaint {
     private float mLineWidth = 1f;
@@ -31,7 +31,7 @@
     }
 
     public void setLineWidth(float width) {
-        Assert.assertTrue(width >= 0);
+        Utils.assertTrue(width >= 0);
         mLineWidth = width;
     }
 
diff --git a/WallpaperPicker/src/com/android/gallery3d/util/IntArray.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java
similarity index 97%
rename from WallpaperPicker/src/com/android/gallery3d/util/IntArray.java
rename to WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java
index 2c4dc2c..f123624 100644
--- a/WallpaperPicker/src/com/android/gallery3d/util/IntArray.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/IntArray.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.gallery3d.util;
+package com.android.gallery3d.glrenderer;
 
 public class IntArray {
     private static final int INIT_CAPACITY = 8;
diff --git a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979..8075bf8 100644
--- a/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/WallpaperPicker/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,7 +20,8 @@
 import android.graphics.Bitmap.Config;
 import android.opengl.GLUtils;
 
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
+import com.android.launcher3.util.Thunk;
 
 import java.util.HashMap;
 
@@ -82,7 +83,7 @@
         return mIsUploading;
     }
 
-    private static class BorderKey implements Cloneable {
+    @Thunk static class BorderKey implements Cloneable {
         public boolean vertical;
         public Config config;
         public int length;
@@ -144,7 +145,7 @@
     }
 
     private void freeBitmap() {
-        Assert.assertTrue(mBitmap != null);
+        Utils.assertTrue(mBitmap != null);
         onFreeBitmap(mBitmap);
         mBitmap = null;
     }
@@ -219,7 +220,7 @@
                 int texWidth = getTextureWidth();
                 int texHeight = getTextureHeight();
 
-                Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+                Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
 
                 // Upload the bitmap to a new texture.
                 mId = canvas.getGLId().generateTexture();
diff --git a/WallpaperPicker/src/com/android/launcher3/CropView.java b/WallpaperPicker/src/com/android/launcher3/CropView.java
index 578b8ea..50f779a 100644
--- a/WallpaperPicker/src/com/android/launcher3/CropView.java
+++ b/WallpaperPicker/src/com/android/launcher3/CropView.java
@@ -21,7 +21,6 @@
 import android.graphics.Point;
 import android.graphics.RectF;
 import android.util.AttributeSet;
-import android.util.FloatMath;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
@@ -300,12 +299,12 @@
                     adjustment[0] = (edges.right - getWidth()) / scale;
                 }
                 if (edges.top > 0) {
-                    adjustment[1] = FloatMath.ceil(edges.top / scale);
+                    adjustment[1] = (float) Math.ceil(edges.top / scale);
                 } else if (edges.bottom < getHeight()) {
                     adjustment[1] = (edges.bottom - getHeight()) / scale;
                 }
                 for (int dim = 0; dim <= 1; dim++) {
-                    if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]);
+                    if (coef[dim] > 0) adjustment[dim] = (float) Math.ceil(adjustment[dim]);
                 }
 
                 mInverseRotateMatrix.mapPoints(adjustment);
diff --git a/src/com/android/launcher3/LauncherWallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
similarity index 69%
rename from src/com/android/launcher3/LauncherWallpaperPickerActivity.java
rename to WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
index 10fe013..091c054 100644
--- a/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
@@ -16,15 +16,6 @@
 
 package com.android.launcher3;
 
-import android.content.Intent;
-
+// TODO: Remove this class
 public class LauncherWallpaperPickerActivity extends WallpaperPickerActivity {
-    @Override
-    public void startActivityForResultSafely(Intent intent, int requestCode) {
-        Utilities.startActivityForResultSafely(this, intent, requestCode);
-    }
-    @Override
-    public boolean enableRotation() {
-        return Utilities.isRotationEnabled(this);
-    }
-}
+}
\ No newline at end of file
diff --git a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java b/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
index 88f4461..b53fce1 100644
--- a/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
+++ b/WallpaperPicker/src/com/android/launcher3/LiveWallpaperListAdapter.java
@@ -30,11 +30,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -50,7 +51,7 @@
     private final LayoutInflater mInflater;
     private final PackageManager mPackageManager;
 
-    private List<LiveWallpaperTile> mWallpapers;
+    @Thunk List<LiveWallpaperTile> mWallpapers;
 
     @SuppressWarnings("unchecked")
     public LiveWallpaperListAdapter(Context context) {
@@ -90,8 +91,6 @@
             view = convertView;
         }
 
-        WallpaperPickerActivity.setWallpaperItemPaddingToZero((FrameLayout) view);
-
         LiveWallpaperTile wallpaperInfo = mWallpapers.get(position);
         wallpaperInfo.setView(view);
         ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
@@ -111,8 +110,8 @@
     }
 
     public static class LiveWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
-        private Drawable mThumbnail;
-        private WallpaperInfo mInfo;
+        @Thunk Drawable mThumbnail;
+        @Thunk WallpaperInfo mInfo;
         public LiveWallpaperTile(Drawable thumbnail, WallpaperInfo info, Intent intent) {
             mThumbnail = thumbnail;
             mInfo = info;
@@ -122,8 +121,8 @@
             Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
             preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
                     mInfo.getComponent());
-            a.onLiveWallpaperPickerLaunch(mInfo);
-            a.startActivityForResultSafely(preview, WallpaperPickerActivity.PICK_LIVE_WALLPAPER);
+            a.startActivityForResultSafely(preview,
+                    WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);
         }
     }
 
diff --git a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
index 9f92bc1..64b0ac4 100644
--- a/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
+++ b/WallpaperPicker/src/com/android/launcher3/SavedWallpaperImages.java
@@ -16,7 +16,6 @@
 
 package com.android.launcher3;
 
-import android.app.Activity;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -60,13 +59,13 @@
         }
     }
 
-    public SavedWallpaperImages(Activity context) {
+    public SavedWallpaperImages(Context context) {
         // We used to store the saved images in the cache directory, but that meant they'd get
         // deleted sometimes-- move them to the data directory
         ImageDb.moveFromCacheDirectoryIfNecessary(context);
         mDb = new ImageDb(context);
         mContext = context;
-        mLayoutInflater = context.getLayoutInflater();
+        mLayoutInflater = LayoutInflater.from(context);
     }
 
     public void loadThumbnailsAndImageIdList() {
diff --git a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
index 7a4d48c..f46da53 100644
--- a/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
+++ b/WallpaperPicker/src/com/android/launcher3/ThirdPartyWallpaperPickerListAdapter.java
@@ -28,16 +28,15 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
 import android.widget.ListAdapter;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.List;
 
 public class ThirdPartyWallpaperPickerListAdapter extends BaseAdapter implements ListAdapter {
-    private static final String LOG_TAG = "LiveWallpaperListAdapter";
-
     private final LayoutInflater mInflater;
     private final PackageManager mPackageManager;
     private final int mIconSize;
@@ -46,7 +45,7 @@
             new ArrayList<ThirdPartyWallpaperTile>();
 
     public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
-        private ResolveInfo mResolveInfo;
+        @Thunk ResolveInfo mResolveInfo;
         public ThirdPartyWallpaperTile(ResolveInfo resolveInfo) {
             mResolveInfo = resolveInfo;
         }
@@ -62,7 +61,7 @@
     }
 
     public ThirdPartyWallpaperPickerListAdapter(Context context) {
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mInflater = LayoutInflater.from(context);
         mPackageManager = context.getPackageManager();
         mIconSize = context.getResources().getDimensionPixelSize(R.dimen.wallpaperItemIconSize);
         final PackageManager pm = mPackageManager;
@@ -126,8 +125,6 @@
             view = convertView;
         }
 
-        WallpaperPickerActivity.setWallpaperItemPaddingToZero((FrameLayout) view);
-
         ResolveInfo info = mThirdPartyWallpaperPickers.get(position).mResolveInfo;
         TextView label = (TextView) view.findViewById(R.id.wallpaper_item_label);
         label.setText(info.loadLabel(mPackageManager));
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
index fa8ec64..f2bb509 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.WallpaperManager;
@@ -25,42 +26,41 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapRegionDecoder;
-import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Point;
-import android.graphics.Rect;
 import android.graphics.RectF;
 import android.net.Uri;
-import android.os.AsyncTask;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.Toast;
 
+import com.android.gallery3d.common.BitmapCropTask;
+import com.android.gallery3d.common.BitmapUtils;
 import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.exif.ExifInterface;
+import com.android.launcher3.base.BaseActivity;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.WallpaperUtils;
 import com.android.photos.BitmapRegionTileSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource;
+import com.android.photos.BitmapRegionTileSource.BitmapSource.InBitmapProvider;
+import com.android.photos.views.TiledImageRenderer.TileSource;
 
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
 
-public class WallpaperCropActivity extends Activity {
+public class WallpaperCropActivity extends BaseActivity implements Handler.Callback {
     private static final String LOGTAG = "Launcher3.CropActivity";
 
-    protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
-    protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
-    private static final int DEFAULT_COMPRESS_QUALITY = 90;
+    protected static final String WALLPAPER_WIDTH_KEY = WallpaperUtils.WALLPAPER_WIDTH_KEY;
+    protected static final String WALLPAPER_HEIGHT_KEY = WallpaperUtils.WALLPAPER_HEIGHT_KEY;
+
     /**
      * The maximum bitmap size we allow to be returned through the intent.
      * Intents have a maximum of 1MB in total size. However, the Bitmap seems to
@@ -69,17 +69,31 @@
      * array instead of a Bitmap instance to avoid overhead.
      */
     public static final int MAX_BMAP_IN_INTENT = 750000;
-    private static final float WALLPAPER_SCREENS_SPAN = 2f;
+    public static final float WALLPAPER_SCREENS_SPAN = WallpaperUtils.WALLPAPER_SCREENS_SPAN;
 
-    protected static Point sDefaultWallpaperSize;
+    private static final int MSG_LOAD_IMAGE = 1;
 
     protected CropView mCropView;
+    protected View mProgressView;
     protected Uri mUri;
     protected View mSetWallpaperButton;
 
+    private HandlerThread mLoaderThread;
+    private Handler mLoaderHandler;
+    @Thunk LoadRequest mCurrentLoadRequest;
+    private byte[] mTempStorageForDecoding = new byte[16 * 1024];
+    // A weak-set of reusable bitmaps
+    @Thunk Set<Bitmap> mReusableBitmaps =
+            Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
+
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        mLoaderThread = new HandlerThread("wallpaper_loader");
+        mLoaderThread.start();
+        mLoaderHandler = new Handler(mLoaderThread.getLooper(), this);
+
         init();
         if (!enableRotation()) {
             setRequestedOrientation(Configuration.ORIENTATION_PORTRAIT);
@@ -90,6 +104,7 @@
         setContentView(R.layout.wallpaper_cropper);
 
         mCropView = (CropView) findViewById(R.id.cropView);
+        mProgressView = findViewById(R.id.loading);
 
         Intent cropIntent = getIntent();
         final Uri imageUri = cropIntent.getData();
@@ -116,13 +131,12 @@
 
         // Load image in background
         final BitmapRegionTileSource.UriBitmapSource bitmapSource =
-                new BitmapRegionTileSource.UriBitmapSource(this, imageUri, 1024);
+                new BitmapRegionTileSource.UriBitmapSource(getContext(), imageUri);
         mSetWallpaperButton.setEnabled(false);
         Runnable onLoad = new Runnable() {
             public void run() {
                 if (bitmapSource.getLoadingState() != BitmapSource.State.LOADED) {
-                    Toast.makeText(WallpaperCropActivity.this,
-                            getString(R.string.wallpaper_load_fail),
+                    Toast.makeText(getContext(), R.string.wallpaper_load_fail,
                             Toast.LENGTH_LONG).show();
                     finish();
                 } else {
@@ -130,188 +144,163 @@
                 }
             }
         };
-        setCropViewTileSource(bitmapSource, true, false, onLoad);
+        setCropViewTileSource(bitmapSource, true, false, null, onLoad);
     }
 
     @Override
-    protected void onDestroy() {
+    public void onDestroy() {
         if (mCropView != null) {
             mCropView.destroy();
         }
+        if (mLoaderThread != null) {
+            mLoaderThread.quit();
+        }
         super.onDestroy();
     }
 
-    public void setCropViewTileSource(
-            final BitmapRegionTileSource.BitmapSource bitmapSource, final boolean touchEnabled,
-            final boolean moveToLeft, final Runnable postExecute) {
-        final Context context = WallpaperCropActivity.this;
-        final View progressView = findViewById(R.id.loading);
-        final AsyncTask<Void, Void, Void> loadBitmapTask = new AsyncTask<Void, Void, Void>() {
-            protected Void doInBackground(Void...args) {
-                if (!isCancelled()) {
-                    try {
-                        bitmapSource.loadInBackground();
-                    } catch (SecurityException securityException) {
-                        if (isDestroyed()) {
-                            // Temporarily granted permissions are revoked when the activity
-                            // finishes, potentially resulting in a SecurityException here.
-                            // Even though {@link #isDestroyed} might also return true in different
-                            // situations where the configuration changes, we are fine with
-                            // catching these cases here as well.
-                            cancel(false);
-                        } else {
-                            // otherwise it had a different cause and we throw it further
-                            throw securityException;
+    /**
+     * This is called on {@link #mLoaderThread}
+     */
+    @Override
+    public boolean handleMessage(Message msg) {
+        if (msg.what == MSG_LOAD_IMAGE) {
+            final LoadRequest req = (LoadRequest) msg.obj;
+            try {
+                req.src.loadInBackground(new InBitmapProvider() {
+
+                    @Override
+                    public Bitmap forPixelCount(int count) {
+                        Bitmap bitmapToReuse = null;
+                        // Find the smallest bitmap that satisfies the pixel count limit
+                        synchronized (mReusableBitmaps) {
+                            int currentBitmapSize = Integer.MAX_VALUE;
+                            for (Bitmap b : mReusableBitmaps) {
+                                int bitmapSize = b.getWidth() * b.getHeight();
+                                if ((bitmapSize >= count) && (bitmapSize < currentBitmapSize)) {
+                                    bitmapToReuse = b;
+                                    currentBitmapSize = bitmapSize;
+                                }
+                            }
+
+                            if (bitmapToReuse != null) {
+                                mReusableBitmaps.remove(bitmapToReuse);
+                            }
                         }
+                        return bitmapToReuse;
                     }
-                }
-                return null;
-            }
-            protected void onPostExecute(Void arg) {
-                if (!isCancelled()) {
-                    progressView.setVisibility(View.INVISIBLE);
-                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
-                        mCropView.setTileSource(
-                                new BitmapRegionTileSource(context, bitmapSource), null);
-                        mCropView.setTouchEnabled(touchEnabled);
-                        if (moveToLeft) {
-                            mCropView.moveToLeft();
-                        }
-                    }
-                }
-                if (postExecute != null) {
-                    postExecute.run();
+                });
+            } catch (SecurityException securityException) {
+                if (isActivityDestroyed()) {
+                    // Temporarily granted permissions are revoked when the activity
+                    // finishes, potentially resulting in a SecurityException here.
+                    // Even though {@link #isDestroyed} might also return true in different
+                    // situations where the configuration changes, we are fine with
+                    // catching these cases here as well.
+                    return true;
+                } else {
+                    // otherwise it had a different cause and we throw it further
+                    throw securityException;
                 }
             }
-        };
+
+            req.result = new BitmapRegionTileSource(getContext(), req.src, mTempStorageForDecoding);
+            runOnUiThread(new Runnable() {
+
+                @Override
+                public void run() {
+                    if (req == mCurrentLoadRequest) {
+                        onLoadRequestComplete(req,
+                                req.src.getLoadingState() == BitmapSource.State.LOADED);
+                    } else {
+                        addReusableBitmap(req.result);
+                    }
+                }
+            });
+            return true;
+        }
+        return false;
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    protected boolean isActivityDestroyed() {
+        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
+                && isDestroyed();
+    }
+
+    @Thunk void addReusableBitmap(TileSource src) {
+        synchronized (mReusableBitmaps) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+                    && src instanceof BitmapRegionTileSource) {
+                Bitmap preview = ((BitmapRegionTileSource) src).getBitmap();
+                if (preview != null && preview.isMutable()) {
+                    mReusableBitmaps.add(preview);
+                }
+            }
+        }
+    }
+
+    protected void onLoadRequestComplete(LoadRequest req, boolean success) {
+        mCurrentLoadRequest = null;
+        if (success) {
+            TileSource oldSrc = mCropView.getTileSource();
+            mCropView.setTileSource(req.result, null);
+            mCropView.setTouchEnabled(req.touchEnabled);
+            if (req.moveToLeft) {
+                mCropView.moveToLeft();
+            }
+            if (req.scaleProvider != null) {
+                mCropView.setScale(req.scaleProvider.getScale(req.result));
+            }
+
+            // Free last image
+            if (oldSrc != null) {
+                // Call yield instead of recycle, as we only want to free GL resource.
+                // We can still reuse the bitmap for decoding any other image.
+                oldSrc.getPreview().yield();
+            }
+            addReusableBitmap(oldSrc);
+        }
+        if (req.postExecute != null) {
+            req.postExecute.run();
+        }
+        mProgressView.setVisibility(View.GONE);
+    }
+
+    public final void setCropViewTileSource(BitmapSource bitmapSource, boolean touchEnabled,
+            boolean moveToLeft, CropViewScaleProvider scaleProvider, Runnable postExecute) {
+        final LoadRequest req = new LoadRequest();
+        req.moveToLeft = moveToLeft;
+        req.src = bitmapSource;
+        req.touchEnabled = touchEnabled;
+        req.postExecute = postExecute;
+        req.scaleProvider = scaleProvider;
+        mCurrentLoadRequest = req;
+
+        // Remove any pending requests
+        mLoaderHandler.removeMessages(MSG_LOAD_IMAGE);
+        Message.obtain(mLoaderHandler, MSG_LOAD_IMAGE, req).sendToTarget();
+
         // We don't want to show the spinner every time we load an image, because that would be
         // annoying; instead, only start showing the spinner if loading the image has taken
         // longer than 1 sec (ie 1000 ms)
-        progressView.postDelayed(new Runnable() {
+        mProgressView.postDelayed(new Runnable() {
             public void run() {
-                if (loadBitmapTask.getStatus() != AsyncTask.Status.FINISHED) {
-                    progressView.setVisibility(View.VISIBLE);
+                if (mCurrentLoadRequest == req) {
+                    mProgressView.setVisibility(View.VISIBLE);
                 }
             }
         }, 1000);
-        loadBitmapTask.execute();
     }
 
+
     public boolean enableRotation() {
         return getResources().getBoolean(R.bool.allow_rotation);
     }
 
-    public static String getSharedPreferencesKey() {
-        return LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY;
-    }
-
-    // As a ratio of screen height, the total distance we want the parallax effect to span
-    // horizontally
-    private static float wallpaperTravelToScreenWidthRatio(int width, int height) {
-        float aspectRatio = width / (float) height;
-
-        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
-        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
-        // We will use these two data points to extrapolate how much the wallpaper parallax effect
-        // to span (ie travel) at any aspect ratio:
-
-        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
-        final float ASPECT_RATIO_PORTRAIT = 10/16f;
-        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
-        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
-
-        // To find out the desired width at different aspect ratios, we use the following two
-        // formulas, where the coefficient on x is the aspect ratio (width/height):
-        //   (16/10)x + y = 1.5
-        //   (10/16)x + y = 1.2
-        // We solve for x and y and end up with a final formula:
-        final float x =
-            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
-            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
-        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
-        return x * aspectRatio + y;
-    }
-
-    static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
-        if (sDefaultWallpaperSize == null) {
-            Point minDims = new Point();
-            Point maxDims = new Point();
-            windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
-
-            int maxDim = Math.max(maxDims.x, maxDims.y);
-            int minDim = Math.max(minDims.x, minDims.y);
-
-            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-                Point realSize = new Point();
-                windowManager.getDefaultDisplay().getRealSize(realSize);
-                maxDim = Math.max(realSize.x, realSize.y);
-                minDim = Math.min(realSize.x, realSize.y);
-            }
-
-            // We need to ensure that there is enough extra space in the wallpaper
-            // for the intended parallax effects
-            final int defaultWidth, defaultHeight;
-            if (isScreenLarge(res)) {
-                defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
-                defaultHeight = maxDim;
-            } else {
-                defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
-                defaultHeight = maxDim;
-            }
-            sDefaultWallpaperSize = new Point(defaultWidth, defaultHeight);
-        }
-        return sDefaultWallpaperSize;
-    }
-
-    public static int getRotationFromExif(String path) {
-        return getRotationFromExifHelper(path, null, 0, null, null);
-    }
-
-    public static int getRotationFromExif(Context context, Uri uri) {
-        return getRotationFromExifHelper(null, null, 0, context, uri);
-    }
-
-    public static int getRotationFromExif(Resources res, int resId) {
-        return getRotationFromExifHelper(null, res, resId, null, null);
-    }
-
-    private static int getRotationFromExifHelper(
-            String path, Resources res, int resId, Context context, Uri uri) {
-        ExifInterface ei = new ExifInterface();
-        InputStream is = null;
-        BufferedInputStream bis = null;
-        try {
-            if (path != null) {
-                ei.readExif(path);
-            } else if (uri != null) {
-                is = context.getContentResolver().openInputStream(uri);
-                bis = new BufferedInputStream(is);
-                ei.readExif(bis);
-            } else {
-                is = res.openRawResource(resId);
-                bis = new BufferedInputStream(is);
-                ei.readExif(bis);
-            }
-            Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
-            if (ori != null) {
-                return ExifInterface.getRotationForOrientationValue(ori.shortValue());
-            }
-        } catch (IOException e) {
-            Log.w(LOGTAG, "Getting exif data failed", e);
-        } catch (NullPointerException e) {
-            // Sometimes the ExifInterface has an internal NPE if Exif data isn't valid
-            Log.w(LOGTAG, "Getting exif data failed", e);
-        } finally {
-            Utils.closeSilently(bis);
-            Utils.closeSilently(is);
-        }
-        return 0;
-    }
-
     protected void setWallpaper(Uri uri, final boolean finishActivityWhenDone) {
-        int rotation = getRotationFromExif(this, uri);
+        int rotation = BitmapUtils.getRotationFromExif(getContext(), uri);
         BitmapCropTask cropTask = new BitmapCropTask(
-                this, uri, null, rotation, 0, 0, true, false, null);
+                getContext(), uri, null, rotation, 0, 0, true, false, null);
         final Point bounds = cropTask.getImageBounds();
         Runnable onEndCrop = new Runnable() {
             public void run() {
@@ -331,11 +320,11 @@
             Resources res, int resId, final boolean finishActivityWhenDone) {
         // crop this image and scale it down to the default wallpaper size for
         // this device
-        int rotation = getRotationFromExif(res, resId);
+        int rotation = BitmapUtils.getRotationFromExif(res, resId);
         Point inSize = mCropView.getSourceDimensions();
-        Point outSize = getDefaultWallpaperSize(getResources(),
+        Point outSize = WallpaperUtils.getDefaultWallpaperSize(getResources(),
                 getWindowManager());
-        RectF crop = getMaxCropRect(
+        RectF crop = Utils.getMaxCropRect(
                 inSize.x, inSize.y, outSize.x, outSize.y, false);
         Runnable onEndCrop = new Runnable() {
             public void run() {
@@ -348,18 +337,14 @@
                 }
             }
         };
-        BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
+        BitmapCropTask cropTask = new BitmapCropTask(getContext(), res, resId,
                 crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
         cropTask.execute();
     }
 
-    private static boolean isScreenLarge(Resources res) {
-        Configuration config = res.getConfiguration();
-        return config.smallestScreenWidthDp >= 720;
-    }
-
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     protected void cropImageAndSetWallpaper(Uri uri,
-            OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
+            BitmapCropTask.OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) {
         boolean centerCrop = getResources().getBoolean(R.bool.center_crop);
         // Get the crop
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
@@ -370,7 +355,7 @@
         d.getSize(displaySize);
         boolean isPortrait = displaySize.x < displaySize.y;
 
-        Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
+        Point defaultWallpaperSize = WallpaperUtils.getDefaultWallpaperSize(getResources(),
                 getWindowManager());
         // Get the crop
         RectF cropRect = mCropView.getCrop();
@@ -444,7 +429,7 @@
                 }
             }
         };
-        BitmapCropTask cropTask = new BitmapCropTask(this, uri,
+        BitmapCropTask cropTask = new BitmapCropTask(getContext(), uri,
                 cropRect, cropRotation, outWidth, outHeight, true, false, onEndCrop);
         if (onBitmapCroppedHandler != null) {
             cropTask.setOnBitmapCropped(onBitmapCroppedHandler);
@@ -452,375 +437,9 @@
         cropTask.execute();
     }
 
-    public interface OnBitmapCroppedHandler {
-        public void onBitmapCropped(byte[] imageBytes);
-    }
-
-    protected static class BitmapCropTask extends AsyncTask<Void, Void, Boolean> {
-        Uri mInUri = null;
-        Context mContext;
-        String mInFilePath;
-        byte[] mInImageBytes;
-        int mInResId = 0;
-        RectF mCropBounds = null;
-        int mOutWidth, mOutHeight;
-        int mRotation;
-        String mOutputFormat = "jpg"; // for now
-        boolean mSetWallpaper;
-        boolean mSaveCroppedBitmap;
-        Bitmap mCroppedBitmap;
-        Runnable mOnEndRunnable;
-        Resources mResources;
-        OnBitmapCroppedHandler mOnBitmapCroppedHandler;
-        boolean mNoCrop;
-
-        public BitmapCropTask(Context c, String filePath,
-                RectF cropBounds, int rotation, int outWidth, int outHeight,
-                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
-            mContext = c;
-            mInFilePath = filePath;
-            init(cropBounds, rotation,
-                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
-        }
-
-        public BitmapCropTask(byte[] imageBytes,
-                RectF cropBounds, int rotation, int outWidth, int outHeight,
-                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
-            mInImageBytes = imageBytes;
-            init(cropBounds, rotation,
-                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
-        }
-
-        public BitmapCropTask(Context c, Uri inUri,
-                RectF cropBounds, int rotation, int outWidth, int outHeight,
-                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
-            mContext = c;
-            mInUri = inUri;
-            init(cropBounds, rotation,
-                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
-        }
-
-        public BitmapCropTask(Context c, Resources res, int inResId,
-                RectF cropBounds, int rotation, int outWidth, int outHeight,
-                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
-            mContext = c;
-            mInResId = inResId;
-            mResources = res;
-            init(cropBounds, rotation,
-                    outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable);
-        }
-
-        private void init(RectF cropBounds, int rotation, int outWidth, int outHeight,
-                boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) {
-            mCropBounds = cropBounds;
-            mRotation = rotation;
-            mOutWidth = outWidth;
-            mOutHeight = outHeight;
-            mSetWallpaper = setWallpaper;
-            mSaveCroppedBitmap = saveCroppedBitmap;
-            mOnEndRunnable = onEndRunnable;
-        }
-
-        public void setOnBitmapCropped(OnBitmapCroppedHandler handler) {
-            mOnBitmapCroppedHandler = handler;
-        }
-
-        public void setNoCrop(boolean value) {
-            mNoCrop = value;
-        }
-
-        public void setOnEndRunnable(Runnable onEndRunnable) {
-            mOnEndRunnable = onEndRunnable;
-        }
-
-        // Helper to setup input stream
-        private InputStream regenerateInputStream() {
-            if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) {
-                Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " +
-                        "image byte array given");
-            } else {
-                try {
-                    if (mInUri != null) {
-                        return new BufferedInputStream(
-                                mContext.getContentResolver().openInputStream(mInUri));
-                    } else if (mInFilePath != null) {
-                        return mContext.openFileInput(mInFilePath);
-                    } else if (mInImageBytes != null) {
-                        return new BufferedInputStream(new ByteArrayInputStream(mInImageBytes));
-                    } else {
-                        return new BufferedInputStream(mResources.openRawResource(mInResId));
-                    }
-                } catch (FileNotFoundException e) {
-                    Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e);
-                }
-            }
-            return null;
-        }
-
-        public Point getImageBounds() {
-            InputStream is = regenerateInputStream();
-            if (is != null) {
-                BitmapFactory.Options options = new BitmapFactory.Options();
-                options.inJustDecodeBounds = true;
-                BitmapFactory.decodeStream(is, null, options);
-                Utils.closeSilently(is);
-                if (options.outWidth != 0 && options.outHeight != 0) {
-                    return new Point(options.outWidth, options.outHeight);
-                }
-            }
-            return null;
-        }
-
-        public void setCropBounds(RectF cropBounds) {
-            mCropBounds = cropBounds;
-        }
-
-        public Bitmap getCroppedBitmap() {
-            return mCroppedBitmap;
-        }
-        public boolean cropBitmap() {
-            boolean failure = false;
-
-
-            WallpaperManager wallpaperManager = null;
-            if (mSetWallpaper) {
-                wallpaperManager = WallpaperManager.getInstance(mContext.getApplicationContext());
-            }
-
-
-            if (mSetWallpaper && mNoCrop) {
-                try {
-                    InputStream is = regenerateInputStream();
-                    if (is != null) {
-                        wallpaperManager.setStream(is);
-                        Utils.closeSilently(is);
-                    }
-                } catch (IOException e) {
-                    Log.w(LOGTAG, "cannot write stream to wallpaper", e);
-                    failure = true;
-                }
-                return !failure;
-            } else {
-                // Find crop bounds (scaled to original image size)
-                Rect roundedTrueCrop = new Rect();
-                Matrix rotateMatrix = new Matrix();
-                Matrix inverseRotateMatrix = new Matrix();
-
-                Point bounds = getImageBounds();
-                if (mRotation > 0) {
-                    rotateMatrix.setRotate(mRotation);
-                    inverseRotateMatrix.setRotate(-mRotation);
-
-                    mCropBounds.roundOut(roundedTrueCrop);
-                    mCropBounds = new RectF(roundedTrueCrop);
-
-                    if (bounds == null) {
-                        Log.w(LOGTAG, "cannot get bounds for image");
-                        failure = true;
-                        return false;
-                    }
-
-                    float[] rotatedBounds = new float[] { bounds.x, bounds.y };
-                    rotateMatrix.mapPoints(rotatedBounds);
-                    rotatedBounds[0] = Math.abs(rotatedBounds[0]);
-                    rotatedBounds[1] = Math.abs(rotatedBounds[1]);
-
-                    mCropBounds.offset(-rotatedBounds[0]/2, -rotatedBounds[1]/2);
-                    inverseRotateMatrix.mapRect(mCropBounds);
-                    mCropBounds.offset(bounds.x/2, bounds.y/2);
-
-                }
-
-                mCropBounds.roundOut(roundedTrueCrop);
-
-                if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
-                    Log.w(LOGTAG, "crop has bad values for full size image");
-                    failure = true;
-                    return false;
-                }
-
-                // See how much we're reducing the size of the image
-                int scaleDownSampleSize = Math.max(1, Math.min(roundedTrueCrop.width() / mOutWidth,
-                        roundedTrueCrop.height() / mOutHeight));
-                // Attempt to open a region decoder
-                BitmapRegionDecoder decoder = null;
-                InputStream is = null;
-                try {
-                    is = regenerateInputStream();
-                    if (is == null) {
-                        Log.w(LOGTAG, "cannot get input stream for uri=" + mInUri.toString());
-                        failure = true;
-                        return false;
-                    }
-                    decoder = BitmapRegionDecoder.newInstance(is, false);
-                    Utils.closeSilently(is);
-                } catch (IOException e) {
-                    Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e);
-                } finally {
-                   Utils.closeSilently(is);
-                   is = null;
-                }
-
-                Bitmap crop = null;
-                if (decoder != null) {
-                    // Do region decoding to get crop bitmap
-                    BitmapFactory.Options options = new BitmapFactory.Options();
-                    if (scaleDownSampleSize > 1) {
-                        options.inSampleSize = scaleDownSampleSize;
-                    }
-                    crop = decoder.decodeRegion(roundedTrueCrop, options);
-                    decoder.recycle();
-                }
-
-                if (crop == null) {
-                    // BitmapRegionDecoder has failed, try to crop in-memory
-                    is = regenerateInputStream();
-                    Bitmap fullSize = null;
-                    if (is != null) {
-                        BitmapFactory.Options options = new BitmapFactory.Options();
-                        if (scaleDownSampleSize > 1) {
-                            options.inSampleSize = scaleDownSampleSize;
-                        }
-                        fullSize = BitmapFactory.decodeStream(is, null, options);
-                        Utils.closeSilently(is);
-                    }
-                    if (fullSize != null) {
-                        // Find out the true sample size that was used by the decoder
-                        scaleDownSampleSize = bounds.x / fullSize.getWidth();
-                        mCropBounds.left /= scaleDownSampleSize;
-                        mCropBounds.top /= scaleDownSampleSize;
-                        mCropBounds.bottom /= scaleDownSampleSize;
-                        mCropBounds.right /= scaleDownSampleSize;
-                        mCropBounds.roundOut(roundedTrueCrop);
-
-                        // Adjust values to account for issues related to rounding
-                        if (roundedTrueCrop.width() > fullSize.getWidth()) {
-                            // Adjust the width
-                            roundedTrueCrop.right = roundedTrueCrop.left + fullSize.getWidth();
-                        }
-                        if (roundedTrueCrop.right > fullSize.getWidth()) {
-                            // Adjust the left value
-                            int adjustment = roundedTrueCrop.left -
-                                    Math.max(0, roundedTrueCrop.right - roundedTrueCrop.width());
-                            roundedTrueCrop.left -= adjustment;
-                            roundedTrueCrop.right -= adjustment;
-                        }
-                        if (roundedTrueCrop.height() > fullSize.getHeight()) {
-                            // Adjust the height
-                            roundedTrueCrop.bottom = roundedTrueCrop.top + fullSize.getHeight();
-                        }
-                        if (roundedTrueCrop.bottom > fullSize.getHeight()) {
-                            // Adjust the top value
-                            int adjustment = roundedTrueCrop.top -
-                                    Math.max(0, roundedTrueCrop.bottom - roundedTrueCrop.height());
-                            roundedTrueCrop.top -= adjustment;
-                            roundedTrueCrop.bottom -= adjustment;
-                        }
-
-                        crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left,
-                                roundedTrueCrop.top, roundedTrueCrop.width(),
-                                roundedTrueCrop.height());
-                    }
-                }
-
-                if (crop == null) {
-                    Log.w(LOGTAG, "cannot decode file: " + mInUri.toString());
-                    failure = true;
-                    return false;
-                }
-                if (mOutWidth > 0 && mOutHeight > 0 || mRotation > 0) {
-                    float[] dimsAfter = new float[] { crop.getWidth(), crop.getHeight() };
-                    rotateMatrix.mapPoints(dimsAfter);
-                    dimsAfter[0] = Math.abs(dimsAfter[0]);
-                    dimsAfter[1] = Math.abs(dimsAfter[1]);
-
-                    if (!(mOutWidth > 0 && mOutHeight > 0)) {
-                        mOutWidth = Math.round(dimsAfter[0]);
-                        mOutHeight = Math.round(dimsAfter[1]);
-                    }
-
-                    RectF cropRect = new RectF(0, 0, dimsAfter[0], dimsAfter[1]);
-                    RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight);
-
-                    Matrix m = new Matrix();
-                    if (mRotation == 0) {
-                        m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
-                    } else {
-                        Matrix m1 = new Matrix();
-                        m1.setTranslate(-crop.getWidth() / 2f, -crop.getHeight() / 2f);
-                        Matrix m2 = new Matrix();
-                        m2.setRotate(mRotation);
-                        Matrix m3 = new Matrix();
-                        m3.setTranslate(dimsAfter[0] / 2f, dimsAfter[1] / 2f);
-                        Matrix m4 = new Matrix();
-                        m4.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
-
-                        Matrix c1 = new Matrix();
-                        c1.setConcat(m2, m1);
-                        Matrix c2 = new Matrix();
-                        c2.setConcat(m4, m3);
-                        m.setConcat(c2, c1);
-                    }
-
-                    Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(),
-                            (int) returnRect.height(), Bitmap.Config.ARGB_8888);
-                    if (tmp != null) {
-                        Canvas c = new Canvas(tmp);
-                        Paint p = new Paint();
-                        p.setFilterBitmap(true);
-                        c.drawBitmap(crop, m, p);
-                        crop = tmp;
-                    }
-                }
-
-                if (mSaveCroppedBitmap) {
-                    mCroppedBitmap = crop;
-                }
-
-                // Get output compression format
-                CompressFormat cf =
-                        convertExtensionToCompressFormat(getFileExtension(mOutputFormat));
-
-                // Compress to byte array
-                ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048);
-                if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) {
-                    // If we need to set to the wallpaper, set it
-                    if (mSetWallpaper && wallpaperManager != null) {
-                        try {
-                            byte[] outByteArray = tmpOut.toByteArray();
-                            wallpaperManager.setStream(new ByteArrayInputStream(outByteArray));
-                            if (mOnBitmapCroppedHandler != null) {
-                                mOnBitmapCroppedHandler.onBitmapCropped(outByteArray);
-                            }
-                        } catch (IOException e) {
-                            Log.w(LOGTAG, "cannot write stream to wallpaper", e);
-                            failure = true;
-                        }
-                    }
-                } else {
-                    Log.w(LOGTAG, "cannot compress bitmap");
-                    failure = true;
-                }
-            }
-            return !failure; // True if any of the operations failed
-        }
-
-        @Override
-        protected Boolean doInBackground(Void... params) {
-            return cropBitmap();
-        }
-
-        @Override
-        protected void onPostExecute(Boolean result) {
-            if (mOnEndRunnable != null) {
-                mOnEndRunnable.run();
-            }
-        }
-    }
-
     protected void updateWallpaperDimensions(int width, int height) {
-        String spKey = getSharedPreferencesKey();
-        SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
+        String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY;
+        SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
         SharedPreferences.Editor editor = sp.edit();
         if (width != 0 && height != 0) {
             editor.putInt(WALLPAPER_WIDTH_KEY, width);
@@ -830,69 +449,21 @@
             editor.remove(WALLPAPER_HEIGHT_KEY);
         }
         editor.commit();
-
-        suggestWallpaperDimension(getResources(),
-                sp, getWindowManager(), WallpaperManager.getInstance(this), true);
+        WallpaperUtils.suggestWallpaperDimension(getResources(),
+                sp, getWindowManager(), WallpaperManager.getInstance(getContext()), true);
     }
 
-    static public void suggestWallpaperDimension(Resources res,
-            final SharedPreferences sharedPrefs,
-            WindowManager windowManager,
-            final WallpaperManager wallpaperManager, boolean fallBackToDefaults) {
-        final Point defaultWallpaperSize = getDefaultWallpaperSize(res, windowManager);
-        // If we have saved a wallpaper width/height, use that instead
+    static class LoadRequest {
+        BitmapSource src;
+        boolean touchEnabled;
+        boolean moveToLeft;
+        Runnable postExecute;
+        CropViewScaleProvider scaleProvider;
 
-        int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, -1);
-        int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, -1);
-
-        if (savedWidth == -1 || savedHeight == -1) {
-            if (!fallBackToDefaults) {
-                return;
-            } else {
-                savedWidth = defaultWallpaperSize.x;
-                savedHeight = defaultWallpaperSize.y;
-            }
-        }
-
-        if (savedWidth != wallpaperManager.getDesiredMinimumWidth() ||
-                savedHeight != wallpaperManager.getDesiredMinimumHeight()) {
-            wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
-        }
+        TileSource result;
     }
 
-    protected static RectF getMaxCropRect(
-            int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) {
-        RectF cropRect = new RectF();
-        // Get a crop rect that will fit this
-        if (inWidth / (float) inHeight > outWidth / (float) outHeight) {
-             cropRect.top = 0;
-             cropRect.bottom = inHeight;
-             cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2;
-             cropRect.right = inWidth - cropRect.left;
-             if (leftAligned) {
-                 cropRect.right -= cropRect.left;
-                 cropRect.left = 0;
-             }
-        } else {
-            cropRect.left = 0;
-            cropRect.right = inWidth;
-            cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2;
-            cropRect.bottom = inHeight - cropRect.top;
-        }
-        return cropRect;
-    }
-
-    protected static CompressFormat convertExtensionToCompressFormat(String extension) {
-        return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG;
-    }
-
-    protected static String getFileExtension(String requestFormat) {
-        String outputFormat = (requestFormat == null)
-                ? "jpg"
-                : requestFormat;
-        outputFormat = outputFormat.toLowerCase();
-        return (outputFormat.equals("png") || outputFormat.equals("gif"))
-                ? "png" // We don't support gif compression.
-                : "jpg";
+    interface CropViewScaleProvider {
+        float getScale(TileSource src);
     }
 }
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
index 09e0963..88dc3e2 100644
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
+++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java
@@ -16,11 +16,11 @@
 
 package com.android.launcher3;
 
+import android.Manifest.permission;
 import android.animation.LayoutTransition;
 import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.app.Activity;
-import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.Intent;
@@ -35,15 +35,15 @@
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
-import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
+import android.Manifest;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Process;
 import android.provider.MediaStore;
 import android.util.Log;
 import android.util.Pair;
@@ -52,6 +52,7 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLayoutChangeListener;
@@ -70,8 +71,14 @@
 import android.widget.LinearLayout;
 import android.widget.Toast;
 
+import com.android.gallery3d.common.BitmapCropTask;
+import com.android.gallery3d.common.BitmapUtils;
+import com.android.gallery3d.common.Utils;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.WallpaperUtils;
 import com.android.photos.BitmapRegionTileSource;
 import com.android.photos.BitmapRegionTileSource.BitmapSource;
+import com.android.photos.views.TiledImageRenderer.TileSource;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -83,28 +90,25 @@
 
     public static final int IMAGE_PICK = 5;
     public static final int PICK_WALLPAPER_THIRD_PARTY_ACTIVITY = 6;
-    public static final int PICK_LIVE_WALLPAPER = 7;
     private static final String TEMP_WALLPAPER_TILES = "TEMP_WALLPAPER_TILES";
     private static final String SELECTED_INDEX = "SELECTED_INDEX";
     private static final int FLAG_POST_DELAY_MILLIS = 200;
 
-    private View mSelectedTile;
-    private boolean mIgnoreNextTap;
-    private OnClickListener mThumbnailOnClickListener;
+    @Thunk View mSelectedTile;
+    @Thunk boolean mIgnoreNextTap;
+    @Thunk OnClickListener mThumbnailOnClickListener;
 
-    private LinearLayout mWallpapersView;
-    private View mWallpaperStrip;
+    @Thunk LinearLayout mWallpapersView;
+    @Thunk HorizontalScrollView mWallpaperScrollContainer;
 
-    private ActionMode.Callback mActionModeCallback;
-    private ActionMode mActionMode;
+    @Thunk ActionMode.Callback mActionModeCallback;
+    @Thunk ActionMode mActionMode;
 
-    private View.OnLongClickListener mLongClickListener;
+    @Thunk View.OnLongClickListener mLongClickListener;
 
     ArrayList<Uri> mTempWallpaperTiles = new ArrayList<Uri>();
     private SavedWallpaperImages mSavedImages;
-    private WallpaperInfo mLiveWallpaperInfoOnPickerLaunch;
-    private int mSelectedIndex = -1;
-    private WallpaperInfo mLastClickedLiveWallpaperInfo;
+    @Thunk int mSelectedIndex = -1;
 
     public static abstract class WallpaperTileInfo {
         protected View mView;
@@ -136,45 +140,36 @@
 
     public static class UriWallpaperInfo extends WallpaperTileInfo {
         private Uri mUri;
-        private boolean mFirstClick = true;
-        private BitmapRegionTileSource.UriBitmapSource mBitmapSource;
         public UriWallpaperInfo(Uri uri) {
             mUri = uri;
         }
         @Override
         public void onClick(final WallpaperPickerActivity a) {
-            final Runnable onLoad;
-            if (!mFirstClick) {
-                onLoad = null;
-            } else {
-                mFirstClick = false;
-                a.mSetWallpaperButton.setEnabled(false);
-                onLoad = new Runnable() {
-                    public void run() {
-                        if (mBitmapSource != null &&
-                                mBitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
-                            a.selectTile(mView);
-                            a.mSetWallpaperButton.setEnabled(true);
-                        } else {
-                            ViewGroup parent = (ViewGroup) mView.getParent();
-                            if (parent != null) {
-                                parent.removeView(mView);
-                                Toast.makeText(a,
-                                        a.getString(R.string.image_load_fail),
-                                        Toast.LENGTH_SHORT).show();
-                            }
+            a.setWallpaperButtonEnabled(false);
+            final BitmapRegionTileSource.UriBitmapSource bitmapSource =
+                    new BitmapRegionTileSource.UriBitmapSource(a.getContext(), mUri);
+            a.setCropViewTileSource(bitmapSource, true, false, null, new Runnable() {
+
+                @Override
+                public void run() {
+                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+                        a.selectTile(mView);
+                        a.setWallpaperButtonEnabled(true);
+                    } else {
+                        ViewGroup parent = (ViewGroup) mView.getParent();
+                        if (parent != null) {
+                            parent.removeView(mView);
+                            Toast.makeText(a.getContext(), R.string.image_load_fail,
+                                    Toast.LENGTH_SHORT).show();
                         }
                     }
-                };
-            }
-            mBitmapSource = new BitmapRegionTileSource.UriBitmapSource(
-                    a, mUri, BitmapRegionTileSource.MAX_PREVIEW_SIZE);
-            a.setCropViewTileSource(mBitmapSource, true, false, onLoad);
+                }
+            });
         }
         @Override
         public void onSave(final WallpaperPickerActivity a) {
             boolean finishActivityWhenDone = true;
-            OnBitmapCroppedHandler h = new OnBitmapCroppedHandler() {
+            BitmapCropTask.OnBitmapCroppedHandler h = new BitmapCropTask.OnBitmapCroppedHandler() {
                 public void onBitmapCropped(byte[] imageBytes) {
                     Point thumbSize = getDefaultThumbnailSize(a.getResources());
                     // rotation is set to 0 since imageBytes has already been correctly rotated
@@ -203,10 +198,19 @@
             mThumb = thumb;
         }
         @Override
-        public void onClick(WallpaperPickerActivity a) {
-            BitmapRegionTileSource.UriBitmapSource bitmapSource =
-                    new BitmapRegionTileSource.UriBitmapSource(a, Uri.fromFile(mFile), 1024);
-            a.setCropViewTileSource(bitmapSource, false, true, null);
+        public void onClick(final WallpaperPickerActivity a) {
+            a.setWallpaperButtonEnabled(false);
+            final BitmapRegionTileSource.UriBitmapSource bitmapSource =
+                    new BitmapRegionTileSource.UriBitmapSource(a.getContext(), Uri.fromFile(mFile));
+            a.setCropViewTileSource(bitmapSource, false, true, null, new Runnable() {
+
+                @Override
+                public void run() {
+                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) { 
+                        a.setWallpaperButtonEnabled(true);
+                    }
+                }
+            });
         }
         @Override
         public void onSave(WallpaperPickerActivity a) {
@@ -232,22 +236,30 @@
             mThumb = thumb;
         }
         @Override
-        public void onClick(WallpaperPickerActivity a) {
-            BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
-                    new BitmapRegionTileSource.ResourceBitmapSource(
-                            mResources, mResId, BitmapRegionTileSource.MAX_PREVIEW_SIZE);
-            bitmapSource.loadInBackground();
-            BitmapRegionTileSource source = new BitmapRegionTileSource(a, bitmapSource);
-            CropView v = a.getCropView();
-            v.setTileSource(source, null);
-            Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
-                    a.getResources(), a.getWindowManager());
-            RectF crop = WallpaperCropActivity.getMaxCropRect(
-                    source.getImageWidth(), source.getImageHeight(),
-                    wallpaperSize.x, wallpaperSize.y, false);
-            v.setScale(wallpaperSize.x / crop.width());
-            v.setTouchEnabled(false);
-            a.setSystemWallpaperVisiblity(false);
+        public void onClick(final WallpaperPickerActivity a) {
+            a.setWallpaperButtonEnabled(false);
+            final BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
+                    new BitmapRegionTileSource.ResourceBitmapSource(mResources, mResId);
+            a.setCropViewTileSource(bitmapSource, false, false, new CropViewScaleProvider() {
+
+                @Override
+                public float getScale(TileSource src) {
+                    Point wallpaperSize = WallpaperUtils.getDefaultWallpaperSize(
+                            a.getResources(), a.getWindowManager());
+                    RectF crop = Utils.getMaxCropRect(
+                            src.getImageWidth(), src.getImageHeight(),
+                            wallpaperSize.x, wallpaperSize.y, false);
+                    return wallpaperSize.x / crop.width();
+                }
+            }, new Runnable() {
+
+                @Override
+                public void run() {
+                    if (bitmapSource.getLoadingState() == BitmapSource.State.LOADED) {
+                        a.setWallpaperButtonEnabled(true);
+                    }
+                }
+            });
         }
         @Override
         public void onSave(WallpaperPickerActivity a) {
@@ -272,27 +284,33 @@
         @Override
         public void onClick(WallpaperPickerActivity a) {
             CropView c = a.getCropView();
-
-            Drawable defaultWallpaper = WallpaperManager.getInstance(a).getBuiltInDrawable(
-                    c.getWidth(), c.getHeight(), false, 0.5f, 0.5f);
-
+            Drawable defaultWallpaper = WallpaperManager.getInstance(a.getContext())
+                    .getBuiltInDrawable(c.getWidth(), c.getHeight(), false, 0.5f, 0.5f);
             if (defaultWallpaper == null) {
                 Log.w(TAG, "Null default wallpaper encountered.");
                 c.setTileSource(null, null);
                 return;
             }
 
-            c.setTileSource(
-                    new DrawableTileSource(a, defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE), null);
-            c.setScale(1f);
-            c.setTouchEnabled(false);
-            a.setSystemWallpaperVisiblity(false);
+            LoadRequest req = new LoadRequest();
+            req.moveToLeft = false;
+            req.touchEnabled = false;
+            req.scaleProvider = new CropViewScaleProvider() {
+
+                @Override
+                public float getScale(TileSource src) {
+                    return 1f;
+                }
+            };
+            req.result = new DrawableTileSource(a.getContext(),
+                    defaultWallpaper, DrawableTileSource.MAX_PREVIEW_SIZE);
+            a.onLoadRequestComplete(req, true);
         }
         @Override
         public void onSave(WallpaperPickerActivity a) {
             try {
-                WallpaperManager.getInstance(a).clear();
-                a.setResult(RESULT_OK);
+                WallpaperManager.getInstance(a.getContext()).clear();
+                a.setResult(Activity.RESULT_OK);
             } catch (IOException e) {
                 Log.w("Setting wallpaper to default threw exception", e);
             }
@@ -308,10 +326,6 @@
         }
     }
 
-    public void setWallpaperStripYOffset(float offset) {
-        mWallpaperStrip.setPadding(0, 0, 0, (int) offset);
-    }
-
     /**
      * shows the system wallpaper behind the window and hides the {@link
      * #mCropView} if visible
@@ -338,7 +352,7 @@
         }, FLAG_POST_DELAY_MILLIS);
     }
 
-    private void changeWallpaperFlags(boolean visible) {
+    @Thunk void changeWallpaperFlags(boolean visible) {
         int desiredWallpaperFlag = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
         int currentWallpaperFlag = getWindow().getAttributes().flags
                 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -349,24 +363,11 @@
     }
 
     @Override
-    public void setCropViewTileSource(BitmapSource bitmapSource,
-                                      boolean touchEnabled,
-                                      boolean moveToLeft,
-                                      final Runnable postExecute) {
-        // we also want to show our own wallpaper instead of the one in the background
-        Runnable showPostExecuteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if(postExecute != null) {
-                    postExecute.run();
-                }
-                setSystemWallpaperVisiblity(false);
-            }
-        };
-        super.setCropViewTileSource(bitmapSource,
-                touchEnabled,
-                moveToLeft,
-                showPostExecuteRunnable);
+    protected void onLoadRequestComplete(LoadRequest req, boolean success) {
+        super.onLoadRequestComplete(req, success);
+        if (success) {
+            setSystemWallpaperVisiblity(false);
+        }
     }
 
     // called by onCreate; this is subclassed to overwrite WallpaperCropActivity
@@ -376,7 +377,8 @@
         mCropView = (CropView) findViewById(R.id.cropView);
         mCropView.setVisibility(View.INVISIBLE);
 
-        mWallpaperStrip = findViewById(R.id.wallpaper_strip);
+        mProgressView = findViewById(R.id.loading);
+        mWallpaperScrollContainer = (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container);
         mCropView.setTouchCallback(new CropView.TouchCallback() {
             ViewPropertyAnimator mAnim;
             @Override
@@ -384,15 +386,15 @@
                 if (mAnim != null) {
                     mAnim.cancel();
                 }
-                if (mWallpaperStrip.getAlpha() == 1f) {
+                if (mWallpaperScrollContainer.getAlpha() == 1f) {
                     mIgnoreNextTap = true;
                 }
-                mAnim = mWallpaperStrip.animate();
+                mAnim = mWallpaperScrollContainer.animate();
                 mAnim.alpha(0f)
                     .setDuration(150)
                     .withEndAction(new Runnable() {
                         public void run() {
-                            mWallpaperStrip.setVisibility(View.INVISIBLE);
+                            mWallpaperScrollContainer.setVisibility(View.INVISIBLE);
                         }
                     });
                 mAnim.setInterpolator(new AccelerateInterpolator(0.75f));
@@ -410,8 +412,8 @@
                     if (mAnim != null) {
                         mAnim.cancel();
                     }
-                    mWallpaperStrip.setVisibility(View.VISIBLE);
-                    mAnim = mWallpaperStrip.animate();
+                    mWallpaperScrollContainer.setVisibility(View.VISIBLE);
+                    mAnim = mWallpaperScrollContainer.animate();
                     mAnim.alpha(1f)
                          .setDuration(150)
                          .setInterpolator(new DecelerateInterpolator(0.75f));
@@ -429,7 +431,7 @@
                     }
                     return;
                 }
-                mSetWallpaperButton.setEnabled(true);
+                setWallpaperButtonEnabled(true);
                 WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
                 if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
                     selectTile(v);
@@ -460,18 +462,18 @@
         // Populate the built-in wallpapers
         ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
         mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
-        SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(this, wallpapers);
+        SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(getContext(), wallpapers);
         populateWallpapersFromAdapter(mWallpapersView, ia, false);
 
         // Populate the saved wallpapers
-        mSavedImages = new SavedWallpaperImages(this);
+        mSavedImages = new SavedWallpaperImages(getContext());
         mSavedImages.loadThumbnailsAndImageIdList();
         populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
 
         // Populate the live wallpapers
         final LinearLayout liveWallpapersView =
                 (LinearLayout) findViewById(R.id.live_wallpaper_list);
-        final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(this);
+        final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(getContext());
         a.registerDataSetObserver(new DataSetObserver() {
             public void onChanged() {
                 liveWallpapersView.removeAllViews();
@@ -485,14 +487,13 @@
         final LinearLayout thirdPartyWallpapersView =
                 (LinearLayout) findViewById(R.id.third_party_wallpaper_list);
         final ThirdPartyWallpaperPickerListAdapter ta =
-                new ThirdPartyWallpaperPickerListAdapter(this);
+                new ThirdPartyWallpaperPickerListAdapter(getContext());
         populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false);
 
         // Add a tile for the Gallery
         LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
         FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
                 inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);
-        setWallpaperItemPaddingToZero(pickImageTile);
         masterWallpaperList.addView(pickImageTile, 0);
 
         // Make its background the last photo taken on external storage
@@ -500,10 +501,9 @@
         if (lastPhoto != null) {
             ImageView galleryThumbnailBg =
                     (ImageView) pickImageTile.findViewById(R.id.wallpaper_image);
-            galleryThumbnailBg.setImageBitmap(getThumbnailOfLastPhoto());
+            galleryThumbnailBg.setImageBitmap(lastPhoto);
             int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray);
             galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);
-
         }
 
         PickImageInfo pickImageInfo = new PickImageInfo();
@@ -650,7 +650,11 @@
         };
     }
 
-    private void selectTile(View v) {
+    public void setWallpaperButtonEnabled(boolean enabled) {
+        mSetWallpaperButton.setEnabled(enabled);
+    }
+
+    @Thunk void selectTile(View v) {
         if (mSelectedTile != null) {
             mSelectedTile.setSelected(false);
             mSelectedTile = null;
@@ -661,28 +665,35 @@
         // TODO: Remove this once the accessibility framework and
         // services have better support for selection state.
         v.announceForAccessibility(
-                getString(R.string.announce_selection, v.getContentDescription()));
+                getContext().getString(R.string.announce_selection, v.getContentDescription()));
     }
 
-    private void initializeScrollForRtl() {
-        final HorizontalScrollView scroll =
-                (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container);
-
-        if (scroll.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-            final ViewTreeObserver observer = scroll.getViewTreeObserver();
+    @Thunk void initializeScrollForRtl() {
+        if (Utilities.isRtl(getResources())) {
+            final ViewTreeObserver observer = mWallpaperScrollContainer.getViewTreeObserver();
             observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                 public void onGlobalLayout() {
                     LinearLayout masterWallpaperList =
                             (LinearLayout) findViewById(R.id.master_wallpaper_list);
-                    scroll.scrollTo(masterWallpaperList.getWidth(), 0);
-                    scroll.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    mWallpaperScrollContainer.scrollTo(masterWallpaperList.getWidth(), 0);
+                    mWallpaperScrollContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                 }
             });
         }
     }
 
     protected Bitmap getThumbnailOfLastPhoto() {
-        Cursor cursor = MediaStore.Images.Media.query(getContentResolver(),
+        boolean canReadExternalStorage = getActivity().checkPermission(
+                Manifest.permission.READ_EXTERNAL_STORAGE, Process.myPid(), Process.myUid()) ==
+                PackageManager.PERMISSION_GRANTED;
+
+        if (!canReadExternalStorage) {
+            // MediaStore.Images.Media.EXTERNAL_CONTENT_URI requires
+            // the READ_EXTERNAL_STORAGE permission
+            return null;
+        }
+
+        Cursor cursor = MediaStore.Images.Media.query(getContext().getContentResolver(),
                 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                 new String[] { MediaStore.Images.ImageColumns._ID,
                     MediaStore.Images.ImageColumns.DATE_TAKEN},
@@ -692,7 +703,7 @@
         if (cursor != null) {
             if (cursor.moveToNext()) {
                 int id = cursor.getInt(0);
-                thumb = MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(),
+                thumb = MediaStore.Images.Thumbnails.getThumbnail(getContext().getContentResolver(),
                         id, MediaStore.Images.Thumbnails.MINI_KIND, null);
             }
             cursor.close();
@@ -700,16 +711,16 @@
         return thumb;
     }
 
-    protected void onStop() {
+    public void onStop() {
         super.onStop();
-        mWallpaperStrip = findViewById(R.id.wallpaper_strip);
-        if (mWallpaperStrip.getAlpha() < 1f) {
-            mWallpaperStrip.setAlpha(1f);
-            mWallpaperStrip.setVisibility(View.VISIBLE);
+        mWallpaperScrollContainer = (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container);
+        if (mWallpaperScrollContainer.getAlpha() < 1f) {
+            mWallpaperScrollContainer.setAlpha(1f);
+            mWallpaperScrollContainer.setVisibility(View.VISIBLE);
         }
     }
 
-    protected void onSaveInstanceState(Bundle outState) {
+    public void onSaveInstanceState(Bundle outState) {
         outState.putParcelableArrayList(TEMP_WALLPAPER_TILES, mTempWallpaperTiles);
         outState.putInt(SELECTED_INDEX, mSelectedIndex);
     }
@@ -722,7 +733,7 @@
         mSelectedIndex = savedInstanceState.getInt(SELECTED_INDEX, -1);
     }
 
-    private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
+    @Thunk void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
             boolean addLongPressHandler) {
         for (int i = 0; i < adapter.getCount(); i++) {
             FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
@@ -737,7 +748,7 @@
         }
     }
 
-    private void updateTileIndices() {
+    @Thunk void updateTileIndices() {
         LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
         final int childCount = masterWallpaperList.getChildCount();
         final Resources res = getResources();
@@ -778,13 +789,13 @@
         }
     }
 
-    private static Point getDefaultThumbnailSize(Resources res) {
+    @Thunk static Point getDefaultThumbnailSize(Resources res) {
         return new Point(res.getDimensionPixelSize(R.dimen.wallpaperThumbnailWidth),
                 res.getDimensionPixelSize(R.dimen.wallpaperThumbnailHeight));
 
     }
 
-    private static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
+    @Thunk static Bitmap createThumbnail(Point size, Context context, Uri uri, byte[] imageBytes,
             Resources res, int resId, int rotation, boolean leftAligned) {
         int width = size.x;
         int height = size.y;
@@ -812,7 +823,7 @@
         rotatedBounds[0] = Math.abs(rotatedBounds[0]);
         rotatedBounds[1] = Math.abs(rotatedBounds[1]);
 
-        RectF cropRect = WallpaperCropActivity.getMaxCropRect(
+        RectF cropRect = Utils.getMaxCropRect(
                 (int) rotatedBounds[0], (int) rotatedBounds[1], width, height, leftAligned);
         cropTask.setCropBounds(cropRect);
 
@@ -829,20 +840,19 @@
         final FrameLayout pickedImageThumbnail = (FrameLayout) getLayoutInflater().
                 inflate(R.layout.wallpaper_picker_item, mWallpapersView, false);
         pickedImageThumbnail.setVisibility(View.GONE);
-        setWallpaperItemPaddingToZero(pickedImageThumbnail);
         mWallpapersView.addView(pickedImageThumbnail, 0);
 
         // Load the thumbnail
         final ImageView image = (ImageView) pickedImageThumbnail.findViewById(R.id.wallpaper_image);
         final Point defaultSize = getDefaultThumbnailSize(this.getResources());
-        final Context context = this;
+        final Context context = getContext();
         new AsyncTask<Void, Bitmap, Bitmap>() {
             protected Bitmap doInBackground(Void...args) {
                 try {
-                    int rotation = WallpaperCropActivity.getRotationFromExif(context, uri);
+                    int rotation = BitmapUtils.getRotationFromExif(context, uri);
                     return createThumbnail(defaultSize, context, uri, null, null, 0, rotation, false);
                 } catch (SecurityException securityException) {
-                    if (isDestroyed()) {
+                    if (isActivityDestroyed()) {
                         // Temporarily granted permissions are revoked when the activity
                         // finishes, potentially resulting in a SecurityException here.
                         // Even though {@link #isDestroyed} might also return true in different
@@ -879,45 +889,35 @@
         }
     }
 
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == IMAGE_PICK && resultCode == RESULT_OK) {
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == IMAGE_PICK && resultCode == Activity.RESULT_OK) {
             if (data != null && data.getData() != null) {
                 Uri uri = data.getData();
                 addTemporaryWallpaperTile(uri, false);
             }
-        } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY) {
-            setResult(RESULT_OK);
+        } else if (requestCode == PICK_WALLPAPER_THIRD_PARTY_ACTIVITY
+                && resultCode == Activity.RESULT_OK) {
+            // Something was set on the third-party activity.
+            setResult(Activity.RESULT_OK);
             finish();
-        } else if (requestCode == PICK_LIVE_WALLPAPER) {
-            WallpaperManager wm = WallpaperManager.getInstance(this);
-            final WallpaperInfo oldLiveWallpaper = mLiveWallpaperInfoOnPickerLaunch;
-            final WallpaperInfo clickedWallpaper = mLastClickedLiveWallpaperInfo;
-            WallpaperInfo newLiveWallpaper = wm.getWallpaperInfo();
-            // Try to figure out if a live wallpaper was set;
-            if (newLiveWallpaper != null &&
-                    (oldLiveWallpaper == null
-                            || !oldLiveWallpaper.getComponent()
-                                    .equals(newLiveWallpaper.getComponent())
-                            || clickedWallpaper.getComponent()
-                                    .equals(oldLiveWallpaper.getComponent()))) {
-                // Return if a live wallpaper was set
-                setResult(RESULT_OK);
-                finish();
-            }
         }
     }
 
-    static void setWallpaperItemPaddingToZero(FrameLayout frameLayout) {
-        frameLayout.setPadding(0, 0, 0, 0);
-        frameLayout.setForeground(new ZeroPaddingDrawable(frameLayout.getForeground()));
-    }
-
     private void addLongPressHandler(View v) {
         v.setOnLongClickListener(mLongClickListener);
+
+        // Enable stylus button to also trigger long click.
+        final StylusEventHelper stylusEventHelper = new StylusEventHelper(v);
+        v.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                return stylusEventHelper.checkAndPerformStylusEvent(event);
+            }
+        });
     }
 
     private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
-        final PackageManager pm = getPackageManager();
+        final PackageManager pm = getContext().getPackageManager();
         final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24);
 
         Partner partner = Partner.get(pm);
@@ -961,7 +961,8 @@
         Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId();
         if (r != null) {
             try {
-                Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first);
+                Resources wallpaperRes = getContext().getPackageManager()
+                        .getResourcesForApplication(r.first);
                 addWallpapers(bundled, wallpaperRes, r.first.packageName, r.second);
             } catch (PackageManager.NameNotFoundException e) {
             }
@@ -984,7 +985,7 @@
         try {
             f.createNewFile();
             FileOutputStream thumbFileStream =
-                    openFileOutput(f.getName(), Context.MODE_PRIVATE);
+                    getContext().openFileOutput(f.getName(), Context.MODE_PRIVATE);
             b.compress(Bitmap.CompressFormat.JPEG, 95, thumbFileStream);
             thumbFileStream.close();
             return true;
@@ -996,17 +997,18 @@
     }
 
     private File getDefaultThumbFile() {
-        return new File(getFilesDir(), Build.VERSION.SDK_INT
+        return new File(getContext().getFilesDir(), Build.VERSION.SDK_INT
                 + "_" + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL);
     }
 
     private boolean saveDefaultWallpaperThumb(Bitmap b) {
         // Delete old thumbnails.
-        new File(getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL_OLD).delete();
-        new File(getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
+        new File(getContext().getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL_OLD).delete();
+        new File(getContext().getFilesDir(), LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
 
         for (int i = Build.VERSION_CODES.JELLY_BEAN; i < Build.VERSION.SDK_INT; i++) {
-            new File(getFilesDir(), i + "_" + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
+            new File(getContext().getFilesDir(), i + "_"
+                    + LauncherFiles.DEFAULT_WALLPAPER_THUMBNAIL).delete();
         }
         return writeImageToFileAsJpeg(getDefaultThumbFile(), b);
     }
@@ -1024,9 +1026,9 @@
         } else {
             Resources res = getResources();
             Point defaultThumbSize = getDefaultThumbnailSize(res);
-            int rotation = WallpaperCropActivity.getRotationFromExif(res, resId);
+            int rotation = BitmapUtils.getRotationFromExif(res, resId);
             thumb = createThumbnail(
-                    defaultThumbSize, this, null, null, sysRes, resId, rotation, false);
+                    defaultThumbSize, getContext(), null, null, sysRes, resId, rotation, false);
             if (thumb != null) {
                 defaultWallpaperExists = saveDefaultWallpaperThumb(thumb);
             }
@@ -1048,7 +1050,7 @@
         } else {
             Resources res = getResources();
             Point defaultThumbSize = getDefaultThumbnailSize(res);
-            Drawable wallpaperDrawable = WallpaperManager.getInstance(this).getBuiltInDrawable(
+            Drawable wallpaperDrawable = WallpaperManager.getInstance(getContext()).getBuiltInDrawable(
                     defaultThumbSize.x, defaultThumbSize.y, true, 0.5f, 0.5f);
             if (wallpaperDrawable != null) {
                 thumb = Bitmap.createBitmap(
@@ -1075,7 +1077,7 @@
         // package name should be.
         final String packageName = getResources().getResourcePackageName(R.array.wallpapers);
         try {
-            ApplicationInfo info = getPackageManager().getApplicationInfo(packageName, 0);
+            ApplicationInfo info = getContext().getPackageManager().getApplicationInfo(packageName, 0);
             return new Pair<ApplicationInfo, Integer>(info, R.array.wallpapers);
         } catch (PackageManager.NameNotFoundException e) {
             return null;
@@ -1110,31 +1112,12 @@
         return mSavedImages;
     }
 
-    public void onLiveWallpaperPickerLaunch(WallpaperInfo info) {
-        mLastClickedLiveWallpaperInfo = info;
-        mLiveWallpaperInfoOnPickerLaunch = WallpaperManager.getInstance(this).getWallpaperInfo();
-    }
-
-    static class ZeroPaddingDrawable extends LevelListDrawable {
-        public ZeroPaddingDrawable(Drawable d) {
-            super();
-            addLevel(0, 0, d);
-            setLevel(0);
-        }
-
-        @Override
-        public boolean getPadding(Rect padding) {
-            padding.set(0, 0, 0, 0);
-            return true;
-        }
-    }
-
     private static class SimpleWallpapersAdapter extends ArrayAdapter<WallpaperTileInfo> {
         private final LayoutInflater mLayoutInflater;
 
-        SimpleWallpapersAdapter(Activity activity, ArrayList<WallpaperTileInfo> wallpapers) {
-            super(activity, R.layout.wallpaper_picker_item, wallpapers);
-            mLayoutInflater = activity.getLayoutInflater();
+        SimpleWallpapersAdapter(Context context, ArrayList<WallpaperTileInfo> wallpapers) {
+            super(context, R.layout.wallpaper_picker_item, wallpapers);
+            mLayoutInflater = LayoutInflater.from(context);
         }
 
         public View getView(int position, View convertView, ViewGroup parent) {
@@ -1156,8 +1139,6 @@
             view = convertView;
         }
 
-        setWallpaperItemPaddingToZero((FrameLayout) view);
-
         ImageView image = (ImageView) view.findViewById(R.id.wallpaper_image);
 
         if (thumb != null) {
@@ -1168,9 +1149,17 @@
         return view;
     }
 
-    // In Launcher3, we override this with a method that catches exceptions
-    // from starting activities; didn't want to copy and paste code into here
     public void startActivityForResultSafely(Intent intent, int requestCode) {
-        startActivityForResult(intent, requestCode);
+        Utilities.startActivityForResultSafely(getActivity(), intent, requestCode);
+    }
+
+    @Override
+    public boolean enableRotation() {
+        // Check if rotation is enabled for this device.
+        if (Utilities.isRotationAllowedForDevice(getContext()))
+            return true;
+
+        // Check if the user has specifically enabled rotation via preferences.
+        return Utilities.isAllowRotationPrefEnabled(getApplicationContext(), true);
     }
 }
diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperRootView.java b/WallpaperPicker/src/com/android/launcher3/WallpaperRootView.java
deleted file mode 100644
index ceaa043..0000000
--- a/WallpaperPicker/src/com/android/launcher3/WallpaperRootView.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.graphics.Rect;
-import android.util.AttributeSet;
-import android.widget.RelativeLayout;
-
-public class WallpaperRootView extends RelativeLayout {
-    private final WallpaperPickerActivity a;
-    public WallpaperRootView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        a = (WallpaperPickerActivity) context;
-    }
-    public WallpaperRootView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        a = (WallpaperPickerActivity) context;
-    }
-
-    protected boolean fitSystemWindows(Rect insets) {
-        a.setWallpaperStripYOffset(insets.bottom);
-        return true;
-    }
-}
diff --git a/WallpaperPicker/src/com/android/launcher3/base/BaseActivity.java b/WallpaperPicker/src/com/android/launcher3/base/BaseActivity.java
new file mode 100644
index 0000000..f854118
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/base/BaseActivity.java
@@ -0,0 +1,21 @@
+package com.android.launcher3.base;
+
+import android.app.Activity;
+import android.content.Context;
+
+/**
+ * A wrapper over {@link Activity} which allows to override some methods.
+ * The base implementation can change from an Activity to a Fragment (or any other custom
+ * implementation), Callers should not assume that the base class extends Context, instead use
+ * either {@link #getContext} or {@link #getActivity}
+ */
+public class BaseActivity extends Activity {
+
+    public Context getContext() {
+        return this;
+    }
+
+    public Activity getActivity() {
+        return this;
+    }
+}
diff --git a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
index 66ece4f..2d496a5 100644
--- a/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
+++ b/WallpaperPicker/src/com/android/photos/BitmapRegionTileSource.java
@@ -20,15 +20,14 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapRegionDecoder;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.net.Uri;
+import android.opengl.GLUtils;
 import android.os.Build;
-import android.os.Build.VERSION_CODES;
 import android.util.Log;
 
 import com.android.gallery3d.common.BitmapUtils;
@@ -148,24 +147,19 @@
 
     private static final String TAG = "BitmapRegionTileSource";
 
-    private static final boolean REUSE_BITMAP =
-            Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
     private static final int GL_SIZE_LIMIT = 2048;
     // This must be no larger than half the size of the GL_SIZE_LIMIT
     // due to decodePreview being allowed to be up to 2x the size of the target
-    public static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2;
+    private static final int MAX_PREVIEW_SIZE = GL_SIZE_LIMIT / 2;
 
     public static abstract class BitmapSource {
         private SimpleBitmapRegionDecoder mDecoder;
         private Bitmap mPreview;
-        private int mPreviewSize;
         private int mRotation;
         public enum State { NOT_LOADED, LOADED, ERROR_LOADING };
         private State mState = State.NOT_LOADED;
-        public BitmapSource(int previewSize) {
-            mPreviewSize = previewSize;
-        }
-        public boolean loadInBackground() {
+
+        public boolean loadInBackground(InBitmapProvider bitmapProvider) {
             ExifInterface ei = new ExifInterface();
             if (readExif(ei)) {
                 Integer ori = ei.getTagIntValue(ExifInterface.TAG_ORIENTATION);
@@ -180,18 +174,44 @@
             } else {
                 int width = mDecoder.getWidth();
                 int height = mDecoder.getHeight();
-                if (mPreviewSize != 0) {
-                    int previewSize = Math.min(mPreviewSize, MAX_PREVIEW_SIZE);
-                    BitmapFactory.Options opts = new BitmapFactory.Options();
-                    opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
-                    opts.inPreferQualityOverSpeed = true;
 
-                    float scale = (float) previewSize / Math.max(width, height);
-                    opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
-                    opts.inJustDecodeBounds = false;
+                BitmapFactory.Options opts = new BitmapFactory.Options();
+                opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                opts.inPreferQualityOverSpeed = true;
+
+                float scale = (float) MAX_PREVIEW_SIZE / Math.max(width, height);
+                opts.inSampleSize = BitmapUtils.computeSampleSizeLarger(scale);
+                opts.inJustDecodeBounds = false;
+                opts.inMutable = true;
+
+                if (bitmapProvider != null) {
+                    int expectedPixles = (width / opts.inSampleSize) * (height / opts.inSampleSize);
+                    Bitmap reusableBitmap = bitmapProvider.forPixelCount(expectedPixles);
+                    if (reusableBitmap != null) {
+                        // Try loading with reusable bitmap
+                        opts.inBitmap = reusableBitmap;
+                        try {
+                            mPreview = loadPreviewBitmap(opts);
+                        } catch (IllegalArgumentException e) {
+                            Log.d(TAG, "Unable to reusage bitmap", e);
+                            opts.inBitmap = null;
+                            mPreview = null;
+                        }
+                    }
+                }
+                if (mPreview == null) {
                     mPreview = loadPreviewBitmap(opts);
                 }
-                mState = State.LOADED;
+
+                // Verify that the bitmap can be used on GL surface
+                try {
+                    GLUtils.getInternalFormat(mPreview);
+                    GLUtils.getType(mPreview);
+                    mState = State.LOADED;
+                } catch (IllegalArgumentException e) {
+                    Log.d(TAG, "Image cannot be rendered on a GL surface", e);
+                    mState = State.ERROR_LOADING;
+                }
                 return true;
             }
         }
@@ -208,10 +228,6 @@
             return mPreview;
         }
 
-        public int getPreviewSize() {
-            return mPreviewSize;
-        }
-
         public int getRotation() {
             return mRotation;
         }
@@ -219,12 +235,15 @@
         public abstract boolean readExif(ExifInterface ei);
         public abstract SimpleBitmapRegionDecoder loadBitmapRegionDecoder();
         public abstract Bitmap loadPreviewBitmap(BitmapFactory.Options options);
+
+        public interface InBitmapProvider {
+            Bitmap forPixelCount(int count);
+        }
     }
 
     public static class FilePathBitmapSource extends BitmapSource {
         private String mPath;
-        public FilePathBitmapSource(String path, int previewSize) {
-            super(previewSize);
+        public FilePathBitmapSource(String path) {
             mPath = path;
         }
         @Override
@@ -258,8 +277,7 @@
     public static class UriBitmapSource extends BitmapSource {
         private Context mContext;
         private Uri mUri;
-        public UriBitmapSource(Context context, Uri uri, int previewSize) {
-            super(previewSize);
+        public UriBitmapSource(Context context, Uri uri) {
             mContext = context;
             mUri = uri;
         }
@@ -306,13 +324,13 @@
                 Utils.closeSilently(is);
                 return true;
             } catch (FileNotFoundException e) {
-                Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
+                Log.d("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return false;
             } catch (IOException e) {
-                Log.e("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
+                Log.d("BitmapRegionTileSource", "Failed to load URI " + mUri, e);
                 return false;
             } catch (NullPointerException e) {
-                Log.e("BitmapRegionTileSource", "Failed to read EXIF for URI " + mUri, e);
+                Log.d("BitmapRegionTileSource", "Failed to read EXIF for URI " + mUri, e);
                 return false;
             } finally {
                 Utils.closeSilently(is);
@@ -323,8 +341,7 @@
     public static class ResourceBitmapSource extends BitmapSource {
         private Resources mRes;
         private int mResId;
-        public ResourceBitmapSource(Resources res, int resId, int previewSize) {
-            super(previewSize);
+        public ResourceBitmapSource(Resources res, int resId) {
             mRes = res;
             mResId = resId;
         }
@@ -372,11 +389,9 @@
 
     // For use only by getTile
     private Rect mWantRegion = new Rect();
-    private Rect mOverlapRegion = new Rect();
     private BitmapFactory.Options mOptions;
-    private Canvas mCanvas;
 
-    public BitmapRegionTileSource(Context context, BitmapSource source) {
+    public BitmapRegionTileSource(Context context, BitmapSource source, byte[] tempStorage) {
         mTileSize = TiledImageRenderer.suggestedTileSize(context);
         mRotation = source.getRotation();
         mDecoder = source.getBitmapRegionDecoder();
@@ -386,27 +401,26 @@
             mOptions = new BitmapFactory.Options();
             mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
             mOptions.inPreferQualityOverSpeed = true;
-            mOptions.inTempStorage = new byte[16 * 1024];
-            int previewSize = source.getPreviewSize();
-            if (previewSize != 0) {
-                previewSize = Math.min(previewSize, MAX_PREVIEW_SIZE);
-                // Although this is the same size as the Bitmap that is likely already
-                // loaded, the lifecycle is different and interactions are on a different
-                // thread. Thus to simplify, this source will decode its own bitmap.
-                Bitmap preview = decodePreview(source, previewSize);
-                if (preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
+            mOptions.inTempStorage = tempStorage;
+
+            Bitmap preview = source.getPreviewBitmap();
+            if (preview != null &&
+                    preview.getWidth() <= GL_SIZE_LIMIT && preview.getHeight() <= GL_SIZE_LIMIT) {
                     mPreview = new BitmapTexture(preview);
-                } else {
-                    Log.w(TAG, String.format(
-                            "Failed to create preview of apropriate size! "
-                            + " in: %dx%d, out: %dx%d",
-                            mWidth, mHeight,
-                            preview.getWidth(), preview.getHeight()));
-                }
+            } else {
+                Log.w(TAG, String.format(
+                        "Failed to create preview of apropriate size! "
+                        + " in: %dx%d, out: %dx%d",
+                        mWidth, mHeight,
+                        preview.getWidth(), preview.getHeight()));
             }
         }
     }
 
+    public Bitmap getBitmap() {
+        return mPreview instanceof BitmapTexture ? ((BitmapTexture) mPreview).getBitmap() : null;
+    }
+
     @Override
     public int getTileSize() {
         return mTileSize;
@@ -435,10 +449,6 @@
     @Override
     public Bitmap getTile(int level, int x, int y, Bitmap bitmap) {
         int tileSize = getTileSize();
-        if (!REUSE_BITMAP) {
-            return getTileWithoutReusingBitmap(level, x, y, tileSize);
-        }
-
         int t = tileSize << level;
         mWantRegion.set(x, y, x + t, y + t);
 
@@ -462,64 +472,4 @@
         }
         return bitmap;
     }
-
-    private Bitmap getTileWithoutReusingBitmap(
-            int level, int x, int y, int tileSize) {
-
-        int t = tileSize << level;
-        mWantRegion.set(x, y, x + t, y + t);
-
-        mOverlapRegion.set(0, 0, mWidth, mHeight);
-
-        mOptions.inSampleSize = (1 << level);
-        Bitmap bitmap = mDecoder.decodeRegion(mOverlapRegion, mOptions);
-
-        if (bitmap == null) {
-            Log.w(TAG, "fail in decoding region");
-        }
-
-        if (mWantRegion.equals(mOverlapRegion)) {
-            return bitmap;
-        }
-
-        Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888);
-        if (mCanvas == null) {
-            mCanvas = new Canvas();
-        }
-        mCanvas.setBitmap(result);
-        mCanvas.drawBitmap(bitmap,
-                (mOverlapRegion.left - mWantRegion.left) >> level,
-                (mOverlapRegion.top - mWantRegion.top) >> level, null);
-        mCanvas.setBitmap(null);
-        return result;
-    }
-
-    /**
-     * Note that the returned bitmap may have a long edge that's longer
-     * than the targetSize, but it will always be less than 2x the targetSize
-     */
-    private Bitmap decodePreview(BitmapSource source, int targetSize) {
-        Bitmap result = source.getPreviewBitmap();
-        if (result == null) {
-            return null;
-        }
-
-        // We need to resize down if the decoder does not support inSampleSize
-        // or didn't support the specified inSampleSize (some decoders only do powers of 2)
-        float scale = (float) targetSize / (float) (Math.max(result.getWidth(), result.getHeight()));
-
-        if (scale <= 0.5) {
-            result = BitmapUtils.resizeBitmapByScale(result, scale, true);
-        }
-        return ensureGLCompatibleBitmap(result);
-    }
-
-    private static Bitmap ensureGLCompatibleBitmap(Bitmap bitmap) {
-        if (bitmap == null || bitmap.getConfig() != null) {
-            return bitmap;
-        }
-        Bitmap newBitmap = bitmap.copy(Config.ARGB_8888, false);
-        bitmap.recycle();
-        return newBitmap;
-    }
 }
diff --git a/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java b/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java
deleted file mode 100644
index 8a05051..0000000
--- a/WallpaperPicker/src/com/android/photos/views/BlockingGLTextureView.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.photos.views;
-
-import android.content.Context;
-import android.graphics.SurfaceTexture;
-import android.opengl.GLSurfaceView.Renderer;
-import android.opengl.GLUtils;
-import android.util.Log;
-import android.view.TextureView;
-import android.view.TextureView.SurfaceTextureListener;
-
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * A TextureView that supports blocking rendering for synchronous drawing
- */
-public class BlockingGLTextureView extends TextureView
-        implements SurfaceTextureListener {
-
-    private RenderThread mRenderThread;
-
-    public BlockingGLTextureView(Context context) {
-        super(context);
-        setSurfaceTextureListener(this);
-    }
-
-    public void setRenderer(Renderer renderer) {
-        if (mRenderThread != null) {
-            throw new IllegalArgumentException("Renderer already set");
-        }
-        mRenderThread = new RenderThread(renderer);
-    }
-
-    public void render() {
-        mRenderThread.render();
-    }
-
-    public void destroy() {
-        if (mRenderThread != null) {
-            mRenderThread.finish();
-            mRenderThread = null;
-        }
-    }
-
-    @Override
-    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
-            int height) {
-        mRenderThread.setSurface(surface);
-        mRenderThread.setSize(width, height);
-    }
-
-    @Override
-    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,
-            int height) {
-        mRenderThread.setSize(width, height);
-    }
-
-    @Override
-    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-        if (mRenderThread != null) {
-            mRenderThread.setSurface(null);
-        }
-        return false;
-    }
-
-    @Override
-    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            destroy();
-        } catch (Throwable t) {
-            // Ignore
-        }
-        super.finalize();
-    }
-
-    /**
-     * An EGL helper class.
-     */
-
-    private static class EglHelper {
-        private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
-        private static final int EGL_OPENGL_ES2_BIT = 4;
-
-        EGL10 mEgl;
-        EGLDisplay mEglDisplay;
-        EGLSurface mEglSurface;
-        EGLConfig mEglConfig;
-        EGLContext mEglContext;
-
-        private EGLConfig chooseEglConfig() {
-            int[] configsCount = new int[1];
-            EGLConfig[] configs = new EGLConfig[1];
-            int[] configSpec = getConfig();
-            if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
-                throw new IllegalArgumentException("eglChooseConfig failed " +
-                        GLUtils.getEGLErrorString(mEgl.eglGetError()));
-            } else if (configsCount[0] > 0) {
-                return configs[0];
-            }
-            return null;
-        }
-
-        private static int[] getConfig() {
-            return new int[] {
-                    EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                    EGL10.EGL_RED_SIZE, 8,
-                    EGL10.EGL_GREEN_SIZE, 8,
-                    EGL10.EGL_BLUE_SIZE, 8,
-                    EGL10.EGL_ALPHA_SIZE, 8,
-                    EGL10.EGL_DEPTH_SIZE, 0,
-                    EGL10.EGL_STENCIL_SIZE, 0,
-                    EGL10.EGL_NONE
-            };
-        }
-
-        EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
-            int[] attribList = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
-            return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attribList);
-        }
-
-        /**
-         * Initialize EGL for a given configuration spec.
-         */
-        public void start() {
-            /*
-             * Get an EGL instance
-             */
-            mEgl = (EGL10) EGLContext.getEGL();
-
-            /*
-             * Get to the default display.
-             */
-            mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
-
-            if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
-                throw new RuntimeException("eglGetDisplay failed");
-            }
-
-            /*
-             * We can now initialize EGL for that display
-             */
-            int[] version = new int[2];
-            if (!mEgl.eglInitialize(mEglDisplay, version)) {
-                throw new RuntimeException("eglInitialize failed");
-            }
-            mEglConfig = chooseEglConfig();
-
-            /*
-            * Create an EGL context. We want to do this as rarely as we can, because an
-            * EGL context is a somewhat heavy object.
-            */
-            mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
-
-            if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
-                mEglContext = null;
-                throwEglException("createContext");
-            }
-
-            mEglSurface = null;
-        }
-
-        /**
-         * Create an egl surface for the current SurfaceTexture surface. If a surface
-         * already exists, destroy it before creating the new surface.
-         *
-         * @return true if the surface was created successfully.
-         */
-        public boolean createSurface(SurfaceTexture surface) {
-            /*
-             * Check preconditions.
-             */
-            if (mEgl == null) {
-                throw new RuntimeException("egl not initialized");
-            }
-            if (mEglDisplay == null) {
-                throw new RuntimeException("eglDisplay not initialized");
-            }
-            if (mEglConfig == null) {
-                throw new RuntimeException("mEglConfig not initialized");
-            }
-
-            /*
-             *  The window size has changed, so we need to create a new
-             *  surface.
-             */
-            destroySurfaceImp();
-
-            /*
-             * Create an EGL surface we can render into.
-             */
-            if (surface != null) {
-                mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surface, null);
-            } else {
-                mEglSurface = null;
-            }
-
-            if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
-                int error = mEgl.eglGetError();
-                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
-                    Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
-                }
-                return false;
-            }
-
-            /*
-             * Before we can issue GL commands, we need to make sure
-             * the context is current and bound to a surface.
-             */
-            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-                /*
-                 * Could not make the context current, probably because the underlying
-                 * SurfaceView surface has been destroyed.
-                 */
-                logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
-                return false;
-            }
-
-            return true;
-        }
-
-        /**
-         * Create a GL object for the current EGL context.
-         */
-        public GL10 createGL() {
-            return (GL10) mEglContext.getGL();
-        }
-
-        /**
-         * Display the current render surface.
-         * @return the EGL error code from eglSwapBuffers.
-         */
-        public int swap() {
-            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
-                return mEgl.eglGetError();
-            }
-            return EGL10.EGL_SUCCESS;
-        }
-
-        public void destroySurface() {
-            destroySurfaceImp();
-        }
-
-        private void destroySurfaceImp() {
-            if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE) {
-                mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
-                        EGL10.EGL_NO_SURFACE,
-                        EGL10.EGL_NO_CONTEXT);
-                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
-                mEglSurface = null;
-            }
-        }
-
-        public void finish() {
-            if (mEglContext != null) {
-                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
-                mEglContext = null;
-            }
-            if (mEglDisplay != null) {
-                mEgl.eglTerminate(mEglDisplay);
-                mEglDisplay = null;
-            }
-        }
-
-        private void throwEglException(String function) {
-            throwEglException(function, mEgl.eglGetError());
-        }
-
-        public static void throwEglException(String function, int error) {
-            String message = formatEglError(function, error);
-            throw new RuntimeException(message);
-        }
-
-        public static void logEglErrorAsWarning(String tag, String function, int error) {
-            Log.w(tag, formatEglError(function, error));
-        }
-
-        public static String formatEglError(String function, int error) {
-            return function + " failed: " + error;
-        }
-
-    }
-
-    private static class RenderThread extends Thread {
-        private static final int INVALID = -1;
-        private static final int RENDER = 1;
-        private static final int CHANGE_SURFACE = 2;
-        private static final int RESIZE_SURFACE = 3;
-        private static final int FINISH = 4;
-
-        private EglHelper mEglHelper = new EglHelper();
-
-        private Object mLock = new Object();
-        private int mExecMsgId = INVALID;
-        private SurfaceTexture mSurface;
-        private Renderer mRenderer;
-        private int mWidth, mHeight;
-
-        private boolean mFinished = false;
-        private GL10 mGL;
-
-        public RenderThread(Renderer renderer) {
-            super("RenderThread");
-            mRenderer = renderer;
-            start();
-        }
-
-        private void checkRenderer() {
-            if (mRenderer == null) {
-                throw new IllegalArgumentException("Renderer is null!");
-            }
-        }
-
-        private void checkSurface() {
-            if (mSurface == null) {
-                throw new IllegalArgumentException("surface is null!");
-            }
-        }
-
-        public void setSurface(SurfaceTexture surface) {
-            // If the surface is null we're being torn down, don't need a
-            // renderer then
-            if (surface != null) {
-                checkRenderer();
-            }
-            mSurface = surface;
-            exec(CHANGE_SURFACE);
-        }
-
-        public void setSize(int width, int height) {
-            checkRenderer();
-            checkSurface();
-            mWidth = width;
-            mHeight = height;
-            exec(RESIZE_SURFACE);
-        }
-
-        public void render() {
-            checkRenderer();
-            if (mSurface != null) {
-                exec(RENDER);
-                mSurface.updateTexImage();
-            }
-        }
-
-        public void finish() {
-            mSurface = null;
-            exec(FINISH);
-            try {
-                join();
-            } catch (InterruptedException e) {
-                // Ignore
-            }
-        }
-
-        private void exec(int msgid) {
-            synchronized (mLock) {
-                if (mExecMsgId != INVALID) {
-                    throw new IllegalArgumentException(
-                            "Message already set - multithreaded access?");
-                }
-                mExecMsgId = msgid;
-                mLock.notify();
-                try {
-                    mLock.wait();
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
-
-        private void handleMessageLocked(int what) {
-            switch (what) {
-            case CHANGE_SURFACE:
-                if (mEglHelper.createSurface(mSurface)) {
-                    mGL = mEglHelper.createGL();
-                    mRenderer.onSurfaceCreated(mGL, mEglHelper.mEglConfig);
-                }
-                break;
-            case RESIZE_SURFACE:
-                mRenderer.onSurfaceChanged(mGL, mWidth, mHeight);
-                break;
-            case RENDER:
-                mRenderer.onDrawFrame(mGL);
-                mEglHelper.swap();
-                break;
-            case FINISH:
-                mEglHelper.destroySurface();
-                mEglHelper.finish();
-                mFinished = true;
-                break;
-            }
-        }
-
-        @Override
-        public void run() {
-            synchronized (mLock) {
-                mEglHelper.start();
-                while (!mFinished) {
-                    while (mExecMsgId == INVALID) {
-                        try {
-                            mLock.wait();
-                        } catch (InterruptedException e) {
-                            // Ignore
-                        }
-                    }
-                    handleMessageLocked(mExecMsgId);
-                    mExecMsgId = INVALID;
-                    mLock.notify();
-                }
-                mExecMsgId = FINISH;
-            }
-        }
-    }
-}
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
index c4e493b..e57ce70 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageRenderer.java
@@ -20,11 +20,11 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.support.v4.util.LongSparseArray;
+import android.support.v4.util.Pools.Pool;
+import android.support.v4.util.Pools.SynchronizedPool;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.Pools.Pool;
-import android.util.Pools.SynchronizedPool;
+import android.util.LongSparseArray;
 import android.view.View;
 import android.view.WindowManager;
 
@@ -32,6 +32,7 @@
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLCanvas;
 import com.android.gallery3d.glrenderer.UploadedTexture;
+import com.android.launcher3.util.Thunk;
 
 /**
  * Handles laying out, decoding, and drawing of tiles in GL
@@ -67,12 +68,12 @@
     private static final int STATE_RECYCLING = 0x20;
     private static final int STATE_RECYCLED = 0x40;
 
-    private static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
+    @Thunk static Pool<Bitmap> sTilePool = new SynchronizedPool<Bitmap>(64);
 
     // TILE_SIZE must be 2^N
-    private int mTileSize;
+    @Thunk int mTileSize;
 
-    private TileSource mModel;
+    @Thunk TileSource mModel;
     private BasicTexture mPreview;
     protected int mLevelCount;  // cache the value of mScaledBitmaps.length
 
@@ -82,7 +83,7 @@
     // half size of the previous one). If the value is in [0, mLevelCount), we
     // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value
     // is mLevelCount
-    private int mLevel = 0;
+    @Thunk int mLevel = 0;
 
     private int mOffsetX;
     private int mOffsetY;
@@ -96,10 +97,10 @@
     private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>();
 
     // The following three queue are guarded by mQueueLock
-    private final Object mQueueLock = new Object();
+    @Thunk final Object mQueueLock = new Object();
     private final TileQueue mRecycledQueue = new TileQueue();
     private final TileQueue mUploadQueue = new TileQueue();
-    private final TileQueue mDecodeQueue = new TileQueue();
+    @Thunk final TileQueue mDecodeQueue = new TileQueue();
 
     // The width and height of the full-sized bitmap
     protected int mImageWidth = SIZE_UNKNOWN;
@@ -489,7 +490,7 @@
        }
     }
 
-    private void decodeTile(Tile tile) {
+    @Thunk void decodeTile(Tile tile) {
         synchronized (mQueueLock) {
             if (tile.mTileState != STATE_IN_QUEUE) {
                 return;
@@ -556,7 +557,7 @@
         mActiveTiles.put(key, tile);
     }
 
-    private Tile getTile(int x, int y, int level) {
+    @Thunk Tile getTile(int x, int y, int level) {
         return mActiveTiles.get(makeTileKey(x, y, level));
     }
 
@@ -748,7 +749,7 @@
         }
     }
 
-    private static class TileQueue {
+    @Thunk static class TileQueue {
         private Tile mHead;
 
         public Tile pop() {
@@ -786,7 +787,7 @@
         }
     }
 
-    private class TileDecoder extends Thread {
+    @Thunk class TileDecoder extends Thread {
 
         public void finishAndWait() {
             interrupt();
diff --git a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
index 94063b0..7e3e1a9 100644
--- a/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
+++ b/WallpaperPicker/src/com/android/photos/views/TiledImageView.java
@@ -16,8 +16,6 @@
 
 package com.android.photos.views;
 
-import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -28,35 +26,26 @@
 import android.graphics.RectF;
 import android.opengl.GLSurfaceView;
 import android.opengl.GLSurfaceView.Renderer;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.Choreographer;
 import android.view.Choreographer.FrameCallback;
-import android.view.View;
 import android.widget.FrameLayout;
 
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLES20Canvas;
+import com.android.launcher3.util.Thunk;
 import com.android.photos.views.TiledImageRenderer.TileSource;
 
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
 /**
- * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}
- * or {@link BlockingGLTextureView}.
+ * Shows an image using {@link TiledImageRenderer} using either {@link GLSurfaceView}.
  */
 public class TiledImageView extends FrameLayout {
 
-    private static final boolean USE_TEXTURE_VIEW = false;
-    private static final boolean IS_SUPPORTED =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
-    private static final boolean USE_CHOREOGRAPHER =
-            Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
-
-    private BlockingGLTextureView mTextureView;
-    private GLSurfaceView mGLSurfaceView;
-    private boolean mInvalPending = false;
+    @Thunk GLSurfaceView mGLSurfaceView;
+    @Thunk boolean mInvalPending = false;
     private FrameCallback mFrameCallback;
 
     protected static class ImageRendererWrapper {
@@ -79,35 +68,19 @@
     protected Object mLock = new Object();
     protected ImageRendererWrapper mRenderer;
 
-    public static boolean isTilingSupported() {
-        return IS_SUPPORTED;
-    }
-
     public TiledImageView(Context context) {
         this(context, null);
     }
 
     public TiledImageView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        if (!IS_SUPPORTED) {
-            return;
-        }
-
         mRenderer = new ImageRendererWrapper();
         mRenderer.image = new TiledImageRenderer(this);
-        View view;
-        if (USE_TEXTURE_VIEW) {
-            mTextureView = new BlockingGLTextureView(context);
-            mTextureView.setRenderer(new TileRenderer());
-            view = mTextureView;
-        } else {
-            mGLSurfaceView = new GLSurfaceView(context);
-            mGLSurfaceView.setEGLContextClientVersion(2);
-            mGLSurfaceView.setRenderer(new TileRenderer());
-            mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
-            view = mGLSurfaceView;
-        }
-        addView(view, new LayoutParams(
+        mGLSurfaceView = new GLSurfaceView(context);
+        mGLSurfaceView.setEGLContextClientVersion(2);
+        mGLSurfaceView.setRenderer(new TileRenderer());
+        mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+        addView(mGLSurfaceView, new LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
         //setTileSource(new ColoredTiles());
     }
@@ -117,22 +90,11 @@
         super.setVisibility(visibility);
         // need to update inner view's visibility because it seems like we're causing it to draw
         // from {@link #dispatchDraw} or {@link #invalidate} even if we are invisible.
-        if (USE_TEXTURE_VIEW) {
-            mTextureView.setVisibility(visibility);
-        } else {
-            mGLSurfaceView.setVisibility(visibility);
-        }
+        mGLSurfaceView.setVisibility(visibility);
     }
 
     public void destroy() {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        if (USE_TEXTURE_VIEW) {
-            mTextureView.destroy();
-        } else {
-            mGLSurfaceView.queueEvent(mFreeTextures);
-        }
+        mGLSurfaceView.queueEvent(mFreeTextures);
     }
 
     private Runnable mFreeTextures = new Runnable() {
@@ -144,27 +106,14 @@
     };
 
     public void onPause() {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        if (!USE_TEXTURE_VIEW) {
-            mGLSurfaceView.onPause();
-        }
+        mGLSurfaceView.onPause();
     }
 
     public void onResume() {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        if (!USE_TEXTURE_VIEW) {
-            mGLSurfaceView.onResume();
-        }
+        mGLSurfaceView.onResume();
     }
 
     public void setTileSource(TileSource source, Runnable isReadyCallback) {
-        if (!IS_SUPPORTED) {
-            return;
-        }
         synchronized (mLock) {
             mRenderer.source = source;
             mRenderer.isReadyCallback = isReadyCallback;
@@ -177,13 +126,14 @@
         invalidate();
     }
 
+    public TileSource getTileSource() {
+        return mRenderer.source;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right,
             int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (!IS_SUPPORTED) {
-            return;
-        }
         synchronized (mLock) {
             updateScaleIfNecessaryLocked(mRenderer);
         }
@@ -200,43 +150,10 @@
     }
 
     @Override
-    protected void dispatchDraw(Canvas canvas) {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        if (USE_TEXTURE_VIEW) {
-            mTextureView.render();
-        }
-        super.dispatchDraw(canvas);
-    }
-
-    @SuppressLint("NewApi")
-    @Override
-    public void setTranslationX(float translationX) {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        super.setTranslationX(translationX);
-    }
-
-    @Override
     public void invalidate() {
-        if (!IS_SUPPORTED) {
-            return;
-        }
-        if (USE_TEXTURE_VIEW) {
-            super.invalidate();
-            mTextureView.invalidate();
-        } else {
-            if (USE_CHOREOGRAPHER) {
-                invalOnVsync();
-            } else {
-                mGLSurfaceView.requestRender();
-            }
-        }
+        invalOnVsync();
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
     private void invalOnVsync() {
         if (!mInvalPending) {
             mInvalPending = true;
@@ -255,9 +172,6 @@
 
     private RectF mTempRectF = new RectF();
     public void positionFromMatrix(Matrix matrix) {
-        if (!IS_SUPPORTED) {
-            return;
-        }
         if (mRenderer.source != null) {
             final int rotation = mRenderer.source.getRotation();
             final boolean swap = !(rotation % 180 == 0);
@@ -290,7 +204,7 @@
         }
     }
 
-    private class TileRenderer implements Renderer {
+    @Thunk class TileRenderer implements Renderer {
 
         private GLES20Canvas mCanvas;
 
diff --git a/proguard.flags b/proguard.flags
index 83a491d..6a9d6f3 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -1,18 +1,22 @@
--keep class com.android.launcher3.Launcher {
-  public void previousScreen(android.view.View);
-  public void nextScreen(android.view.View);
-  public void launchHotSeat(android.view.View);
-  public void onClickSearchButton(android.view.View);
-  public void onClickVoiceButton(android.view.View);
-  public void onClickConfigureButton(android.view.View);
-  public void onClickAllAppsButton(android.view.View);
-  public void onClickAppMarketButton(android.view.View);
-  public void dismissFirstRunCling(android.view.View);
-  public void dismissMigrationClingCopyApps(android.view.View);
-  public void dismissMigrationClingUseDefault(android.view.View);
-  public void dismissMigrationWorkspaceCling(android.view.View);
-  public void dismissWorkspaceCling(android.view.View);
-  public void dismissAllAppsCling(android.view.View);
+-keep class com.android.launcher3.BaseRecyclerViewFastScrollBar {
+  public void setWidth(int);
+  public int getWidth();
+  public void setTrackAlpha(int);
+  public int getTrackAlpha();
+}
+
+-keep class com.android.launcher3.BaseRecyclerViewFastScrollPopup {
+  public void setAlpha(float);
+  public float getAlpha();
+}
+
+-keep class com.android.launcher3.BubbleTextView {
+  public void setFastScrollFocus(float);
+  public float getFastScrollFocus();
+}
+
+-keep class com.android.launcher3.ButtonDropTarget {
+  public int getTextColor();
 }
 
 -keep class com.android.launcher3.CellLayout {
@@ -20,17 +24,6 @@
   public void setBackgroundAlpha(float);
 }
 
--keep class com.android.launcher3.DragLayer$LayoutParams {
-  public void setWidth(int);
-  public int getWidth();
-  public void setHeight(int);
-  public int getHeight();
-  public void setX(int);
-  public int getX();
-  public void setY(int);
-  public int getY();
-}
-
 -keep class com.android.launcher3.CellLayout$LayoutParams {
   public void setWidth(int);
   public int getWidth();
@@ -42,11 +35,20 @@
   public int getY();
 }
 
--keep class com.android.launcher3.Workspace {
-  public float getBackgroundAlpha();
-  public void setBackgroundAlpha(float);
-  public float getChildrenOutlineAlpha();
-  public void setChildrenOutlineAlpha(float);
+-keep class com.android.launcher3.DragLayer$LayoutParams {
+  public void setWidth(int);
+  public int getWidth();
+  public void setHeight(int);
+  public int getHeight();
+  public void setX(int);
+  public int getX();
+  public void setY(int);
+  public int getY();
+}
+
+-keep class com.android.launcher3.FastBitmapDrawable {
+  public int getBrightness();
+  public void setBrightness(int);
 }
 
 -keep class com.android.launcher3.MemoryDumpActivity {
@@ -58,7 +60,7 @@
   public void setAnimationProgress(float);
 }
 
--keep class com.android.launcher3.FastBitmapDrawable {
-  public int getBrightness();
-  public void setBrightness(int);
-}
+-keep class com.android.launcher3.Workspace {
+  public float getBackgroundAlpha();
+  public void setBackgroundAlpha(float);
+}
\ No newline at end of file
diff --git a/protos/backup.proto b/protos/backup.proto
index 8ae1752..d8d94e8 100644
--- a/protos/backup.proto
+++ b/protos/backup.proto
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
- package launcher_backup;
+syntax = "proto2";
+
+package launcher_backup;
 
 option java_package = "com.android.launcher3.backup";
 option java_outer_classname = "BackupProtos";
@@ -70,6 +72,17 @@
 }
 
 message Favorite {
+  // Type of the app, this target represents
+  enum TargetType {
+    TARGET_NONE = 0;
+    TARGET_PHONE = 1;
+    TARGET_MESSENGER = 2;
+    TARGET_EMAIL = 3;
+    TARGET_BROWSER = 4;
+    TARGET_GALLERY = 5;
+    TARGET_CAMERA = 6;
+  }
+
   required int64 id = 1;
   required int32 itemType = 2;
   optional string title = 3;
@@ -88,17 +101,18 @@
   optional string iconPackage = 16;
   optional string iconResource = 17;
   optional bytes icon = 18;
- }
+  optional TargetType targetType = 19 [default = TARGET_NONE];
+}
 
 message Screen {
   required int64 id = 1;
   optional int32 rank = 2;
- }
+}
 
 message Resource {
   required int32 dpi = 1;
   required bytes data = 2;
- }
+}
 
 message Widget {
   required string provider = 1;
@@ -106,4 +120,8 @@
   optional bool configure = 3;
   optional Resource icon = 4;
   optional Resource preview = 5;
- }
+
+  // Assume that a widget is resizable upto 2x2 if no data is available
+  optional int32 minSpanX = 6 [default = 2];
+  optional int32 minSpanY = 7 [default = 2];
+}
diff --git a/res/anim/fade_in_fast.xml b/res/anim/fade_in_fast.xml
deleted file mode 100644
index 4fa9847..0000000
--- a/res/anim/fade_in_fast.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
-
-    android:fromAlpha="0.0"
-    android:toAlpha="1.0"
-
-    android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/res/drawable-hdpi/apps_customize_bg.png b/res/drawable-hdpi/apps_customize_bg.png
deleted file mode 100644
index 2847467..0000000
--- a/res/drawable-hdpi/apps_customize_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/bg_appwidget_error.9.png b/res/drawable-hdpi/bg_appwidget_error.9.png
deleted file mode 100644
index 4da3195..0000000
--- a/res/drawable-hdpi/bg_appwidget_error.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/home_press.9.png b/res/drawable-hdpi/home_press.9.png
deleted file mode 100644
index ef07011..0000000
--- a/res/drawable-hdpi/home_press.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_back_grey.png b/res/drawable-hdpi/ic_arrow_back_grey.png
new file mode 100755
index 0000000..ccd3900
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_home_all_apps_holo_dark.png b/res/drawable-hdpi/ic_home_all_apps_holo_dark.png
deleted file mode 100644
index 1dc02d5..0000000
--- a/res/drawable-hdpi/ic_home_all_apps_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_info_launcher.png b/res/drawable-hdpi/ic_info_launcher.png
new file mode 100644
index 0000000..ec0cdd1
--- /dev/null
+++ b/res/drawable-hdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_clear_active_holo.png b/res/drawable-hdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index cdd0052..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png b/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 84549ff..0000000
--- a/res/drawable-hdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_active_holo.png b/res/drawable-hdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index c534e56..0000000
--- a/res/drawable-hdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_info_normal_holo.png b/res/drawable-hdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index c9bcd7f..0000000
--- a/res/drawable-hdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_market_holo.png b/res/drawable-hdpi/ic_launcher_market_holo.png
deleted file mode 100644
index dc78251..0000000
--- a/res/drawable-hdpi/ic_launcher_market_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 82b1b59..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 3fc2e83..0000000
--- a/res/drawable-hdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_current.png b/res/drawable-hdpi/ic_pageindicator_current.png
index 283f44d..423ca2b 100644
--- a/res/drawable-hdpi/ic_pageindicator_current.png
+++ b/res/drawable-hdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_current_folder.png b/res/drawable-hdpi/ic_pageindicator_current_folder.png
new file mode 100644
index 0000000..43fbb0e
--- /dev/null
+++ b/res/drawable-hdpi/ic_pageindicator_current_folder.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_default.png b/res/drawable-hdpi/ic_pageindicator_default.png
index 47b9989..83fa73f 100644
--- a/res/drawable-hdpi/ic_pageindicator_default.png
+++ b/res/drawable-hdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pageindicator_default_folder.png b/res/drawable-hdpi/ic_pageindicator_default_folder.png
new file mode 100644
index 0000000..55cab1c
--- /dev/null
+++ b/res/drawable-hdpi/ic_pageindicator_default_folder.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_remove_launcher.png b/res/drawable-hdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..c081457
--- /dev/null
+++ b/res/drawable-hdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_search_grey.png b/res/drawable-hdpi/ic_search_grey.png
new file mode 100755
index 0000000..f4c5e27
--- /dev/null
+++ b/res/drawable-hdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_uninstall_launcher.png b/res/drawable-hdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..3d8f726
--- /dev/null
+++ b/res/drawable-hdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_widget_resize_handle.png b/res/drawable-hdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..844f3cf
--- /dev/null
+++ b/res/drawable-hdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-hdpi/on_boarding_welcome.png b/res/drawable-hdpi/on_boarding_welcome.png
deleted file mode 100644
index 852a0cb..0000000
--- a/res/drawable-hdpi/on_boarding_welcome.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/overscroll_glow_left.9.png b/res/drawable-hdpi/overscroll_glow_left.9.png
deleted file mode 100644
index aaf43c7..0000000
--- a/res/drawable-hdpi/overscroll_glow_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/overscroll_glow_right.9.png b/res/drawable-hdpi/overscroll_glow_right.9.png
deleted file mode 100644
index d034864..0000000
--- a/res/drawable-hdpi/overscroll_glow_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/paged_view_indicator.9.png b/res/drawable-hdpi/paged_view_indicator.9.png
deleted file mode 100644
index 5b47f44..0000000
--- a/res/drawable-hdpi/paged_view_indicator.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_container_holo.9.png b/res/drawable-hdpi/portal_container_holo.9.png
deleted file mode 100644
index ba8a4a8..0000000
--- a/res/drawable-hdpi/portal_container_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner.png b/res/drawable-hdpi/portal_ring_inner.png
new file mode 100644
index 0000000..c29b4aa
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_holo.png b/res/drawable-hdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 857a01e..0000000
--- a/res/drawable-hdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_nolip.png b/res/drawable-hdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..e2f06fe
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_inner_nolip_holo.png b/res/drawable-hdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index 53df36a..0000000
--- a/res/drawable-hdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_outer.png b/res/drawable-hdpi/portal_ring_outer.png
new file mode 100644
index 0000000..e7b436b
--- /dev/null
+++ b/res/drawable-hdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_outer_holo.png b/res/drawable-hdpi/portal_ring_outer_holo.png
deleted file mode 100644
index b711cf3..0000000
--- a/res/drawable-hdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/portal_ring_rest.png b/res/drawable-hdpi/portal_ring_rest.png
index 2979b73..e3b1339 100644
--- a/res/drawable-hdpi/portal_ring_rest.png
+++ b/res/drawable-hdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel.9.png b/res/drawable-hdpi/quantum_panel.9.png
deleted file mode 100644
index b4ac9c0..0000000
--- a/res/drawable-hdpi/quantum_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel_bitmap.9.png b/res/drawable-hdpi/quantum_panel_bitmap.9.png
new file mode 100644
index 0000000..c331929
--- /dev/null
+++ b/res/drawable-hdpi/quantum_panel_bitmap.9.png
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel_dark.9.png b/res/drawable-hdpi/quantum_panel_dark.9.png
deleted file mode 100644
index abaf230..0000000
--- a/res/drawable-hdpi/quantum_panel_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png
new file mode 100644
index 0000000..0145d36
--- /dev/null
+++ b/res/drawable-hdpi/quantum_panel_dark_bitmap.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_frame.9.png b/res/drawable-hdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..b0a7403
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_frame_holo.9.png b/res/drawable-hdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 2d6fcf5..0000000
--- a/res/drawable-hdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_bottom.png b/res/drawable-hdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index f0afd61..0000000
--- a/res/drawable-hdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_left.png b/res/drawable-hdpi/widget_resize_handle_left.png
deleted file mode 100644
index 47613b2..0000000
--- a/res/drawable-hdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_right.png b/res/drawable-hdpi/widget_resize_handle_right.png
deleted file mode 100644
index acc28be..0000000
--- a/res/drawable-hdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_handle_top.png b/res/drawable-hdpi/widget_resize_handle_top.png
deleted file mode 100644
index 2c60be0..0000000
--- a/res/drawable-hdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/widget_resize_shadow.9.png b/res/drawable-hdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..6e2932d
--- /dev/null
+++ b/res/drawable-hdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-ldrtl/container_fastscroll_popup_bg.xml b/res/drawable-ldrtl/container_fastscroll_popup_bg.xml
new file mode 100644
index 0000000..d790968
--- /dev/null
+++ b/res/drawable-ldrtl/container_fastscroll_popup_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/container_fastscroll_thumb_active_color" />
+    <size
+        android:width="64dp"
+        android:height="64dp" />
+    <corners
+        android:topLeftRadius="64dp"
+        android:topRightRadius="64dp"
+        android:bottomRightRadius="64dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable-mdpi/apps_customize_bg.png b/res/drawable-mdpi/apps_customize_bg.png
deleted file mode 100644
index 2847467..0000000
--- a/res/drawable-mdpi/apps_customize_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/bg_appwidget_error.9.png b/res/drawable-mdpi/bg_appwidget_error.9.png
deleted file mode 100644
index 493c0d4..0000000
--- a/res/drawable-mdpi/bg_appwidget_error.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/home_press.9.png b/res/drawable-mdpi/home_press.9.png
deleted file mode 100644
index 679a1f6..0000000
--- a/res/drawable-mdpi/home_press.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_grey.png b/res/drawable-mdpi/ic_arrow_back_grey.png
new file mode 100755
index 0000000..11996ef
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_home_all_apps_holo_dark.png b/res/drawable-mdpi/ic_home_all_apps_holo_dark.png
deleted file mode 100644
index 84fa594..0000000
--- a/res/drawable-mdpi/ic_home_all_apps_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_info_launcher.png b/res/drawable-mdpi/ic_info_launcher.png
new file mode 100644
index 0000000..c72d0c2
--- /dev/null
+++ b/res/drawable-mdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_active_holo.png b/res/drawable-mdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 2683bea..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png b/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index 219f3e5..0000000
--- a/res/drawable-mdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active_holo.png b/res/drawable-mdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index f84b4a6..0000000
--- a/res/drawable-mdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_normal_holo.png b/res/drawable-mdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index eac578f..0000000
--- a/res/drawable-mdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_market_holo.png b/res/drawable-mdpi/ic_launcher_market_holo.png
deleted file mode 100644
index cacb374..0000000
--- a/res/drawable-mdpi/ic_launcher_market_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 0350e55..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 799b62f..0000000
--- a/res/drawable-mdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_current.png b/res/drawable-mdpi/ic_pageindicator_current.png
index b41e1bb..ca889c4 100644
--- a/res/drawable-mdpi/ic_pageindicator_current.png
+++ b/res/drawable-mdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_current_folder.png b/res/drawable-mdpi/ic_pageindicator_current_folder.png
new file mode 100644
index 0000000..5bbba91
--- /dev/null
+++ b/res/drawable-mdpi/ic_pageindicator_current_folder.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_default.png b/res/drawable-mdpi/ic_pageindicator_default.png
index e36c25c..34493b1 100644
--- a/res/drawable-mdpi/ic_pageindicator_default.png
+++ b/res/drawable-mdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pageindicator_default_folder.png b/res/drawable-mdpi/ic_pageindicator_default_folder.png
new file mode 100644
index 0000000..0a987a4
--- /dev/null
+++ b/res/drawable-mdpi/ic_pageindicator_default_folder.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_remove_launcher.png b/res/drawable-mdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..4a2c319
--- /dev/null
+++ b/res/drawable-mdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_search_grey.png b/res/drawable-mdpi/ic_search_grey.png
new file mode 100755
index 0000000..e83891c
--- /dev/null
+++ b/res/drawable-mdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_setting_icn.png b/res/drawable-mdpi/ic_setting_icn.png
deleted file mode 100644
index 5c32c54..0000000
--- a/res/drawable-mdpi/ic_setting_icn.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_uninstall_launcher.png b/res/drawable-mdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..af45669
--- /dev/null
+++ b/res/drawable-mdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_widget_resize_handle.png b/res/drawable-mdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..c3b287f
--- /dev/null
+++ b/res/drawable-mdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-mdpi/on_boarding_welcome.png b/res/drawable-mdpi/on_boarding_welcome.png
deleted file mode 100644
index 1d12e83..0000000
--- a/res/drawable-mdpi/on_boarding_welcome.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/overscroll_glow_left.9.png b/res/drawable-mdpi/overscroll_glow_left.9.png
deleted file mode 100644
index b79cdcd..0000000
--- a/res/drawable-mdpi/overscroll_glow_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/overscroll_glow_right.9.png b/res/drawable-mdpi/overscroll_glow_right.9.png
deleted file mode 100644
index 1321303..0000000
--- a/res/drawable-mdpi/overscroll_glow_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/paged_view_indicator.9.png b/res/drawable-mdpi/paged_view_indicator.9.png
deleted file mode 100644
index 647b60f..0000000
--- a/res/drawable-mdpi/paged_view_indicator.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_container_holo.9.png b/res/drawable-mdpi/portal_container_holo.9.png
deleted file mode 100644
index 1e4afae..0000000
--- a/res/drawable-mdpi/portal_container_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner.png b/res/drawable-mdpi/portal_ring_inner.png
new file mode 100644
index 0000000..99aaa60
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_holo.png b/res/drawable-mdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 72e0af8..0000000
--- a/res/drawable-mdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_nolip.png b/res/drawable-mdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..f981778
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_inner_nolip_holo.png b/res/drawable-mdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index 483f0eb..0000000
--- a/res/drawable-mdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_outer.png b/res/drawable-mdpi/portal_ring_outer.png
new file mode 100644
index 0000000..c98f64b
--- /dev/null
+++ b/res/drawable-mdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_outer_holo.png b/res/drawable-mdpi/portal_ring_outer_holo.png
deleted file mode 100644
index e9b35f3..0000000
--- a/res/drawable-mdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/portal_ring_rest.png b/res/drawable-mdpi/portal_ring_rest.png
index d0a976e..5c33b42 100644
--- a/res/drawable-mdpi/portal_ring_rest.png
+++ b/res/drawable-mdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel.9.png b/res/drawable-mdpi/quantum_panel.9.png
deleted file mode 100644
index c5a6eb7..0000000
--- a/res/drawable-mdpi/quantum_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel_bitmap.9.png b/res/drawable-mdpi/quantum_panel_bitmap.9.png
new file mode 100644
index 0000000..86be568
--- /dev/null
+++ b/res/drawable-mdpi/quantum_panel_bitmap.9.png
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel_dark.9.png b/res/drawable-mdpi/quantum_panel_dark.9.png
deleted file mode 100644
index 7728a72..0000000
--- a/res/drawable-mdpi/quantum_panel_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png
new file mode 100644
index 0000000..70429b9
--- /dev/null
+++ b/res/drawable-mdpi/quantum_panel_dark_bitmap.9.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame.9.png b/res/drawable-mdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..856cec6
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_frame_holo.9.png b/res/drawable-mdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 028bd62..0000000
--- a/res/drawable-mdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_bottom.png b/res/drawable-mdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index c838bf4..0000000
--- a/res/drawable-mdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_left.png b/res/drawable-mdpi/widget_resize_handle_left.png
deleted file mode 100644
index ff0b0d3..0000000
--- a/res/drawable-mdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_right.png b/res/drawable-mdpi/widget_resize_handle_right.png
deleted file mode 100644
index fc4808e..0000000
--- a/res/drawable-mdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_handle_top.png b/res/drawable-mdpi/widget_resize_handle_top.png
deleted file mode 100644
index 3b1df01..0000000
--- a/res/drawable-mdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/widget_resize_shadow.9.png b/res/drawable-mdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..02522f3
--- /dev/null
+++ b/res/drawable-mdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-v21/quantum_panel.xml b/res/drawable-v21/quantum_panel.xml
new file mode 100644
index 0000000..d1c0783
--- /dev/null
+++ b/res/drawable-v21/quantum_panel.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/quantum_panel_shape"
+    android:insetBottom="@dimen/quantum_panel_outer_padding"
+    android:insetLeft="@dimen/quantum_panel_outer_padding"
+    android:insetRight="@dimen/quantum_panel_outer_padding"
+    android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/drawable-v21/quantum_panel_dark.xml b/res/drawable-v21/quantum_panel_dark.xml
new file mode 100644
index 0000000..405ad51
--- /dev/null
+++ b/res/drawable-v21/quantum_panel_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/quantum_panel_shape_dark"
+    android:insetBottom="@dimen/quantum_panel_outer_padding"
+    android:insetLeft="@dimen/quantum_panel_outer_padding"
+    android:insetRight="@dimen/quantum_panel_outer_padding"
+    android:insetTop="@dimen/quantum_panel_outer_padding" />
diff --git a/res/drawable-xhdpi/apps_customize_bg.png b/res/drawable-xhdpi/apps_customize_bg.png
deleted file mode 100644
index a51cc11..0000000
--- a/res/drawable-xhdpi/apps_customize_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/bg_appwidget_error.9.png b/res/drawable-xhdpi/bg_appwidget_error.9.png
deleted file mode 100644
index b792cc8..0000000
--- a/res/drawable-xhdpi/bg_appwidget_error.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/home_press.9.png b/res/drawable-xhdpi/home_press.9.png
deleted file mode 100644
index d9abfd3..0000000
--- a/res/drawable-xhdpi/home_press.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_back_grey.png b/res/drawable-xhdpi/ic_arrow_back_grey.png
new file mode 100755
index 0000000..79b9b48
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_home_all_apps_holo_dark.png b/res/drawable-xhdpi/ic_home_all_apps_holo_dark.png
deleted file mode 100644
index 81228d4..0000000
--- a/res/drawable-xhdpi/ic_home_all_apps_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_info_launcher.png b/res/drawable-xhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..076b59b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 1a7e53d..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index d4965d9..0000000
--- a/res/drawable-xhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active_holo.png b/res/drawable-xhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index b8cdbc4..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index f503fb8..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_market_holo.png b/res/drawable-xhdpi/ic_launcher_market_holo.png
deleted file mode 100644
index 958f0de..0000000
--- a/res/drawable-xhdpi/ic_launcher_market_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index c155274..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 2ec7ad9..0000000
--- a/res/drawable-xhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_current.png b/res/drawable-xhdpi/ic_pageindicator_current.png
index 8fa774d..3054f2f 100644
--- a/res/drawable-xhdpi/ic_pageindicator_current.png
+++ b/res/drawable-xhdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_current_folder.png b/res/drawable-xhdpi/ic_pageindicator_current_folder.png
new file mode 100644
index 0000000..cd92e9f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_pageindicator_current_folder.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_default.png b/res/drawable-xhdpi/ic_pageindicator_default.png
index 8eb5eb0..38538dc 100644
--- a/res/drawable-xhdpi/ic_pageindicator_default.png
+++ b/res/drawable-xhdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pageindicator_default_folder.png b/res/drawable-xhdpi/ic_pageindicator_default_folder.png
new file mode 100644
index 0000000..e7c46e3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_pageindicator_default_folder.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_remove_launcher.png b/res/drawable-xhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..de05889
--- /dev/null
+++ b/res/drawable-xhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_search_grey.png b/res/drawable-xhdpi/ic_search_grey.png
new file mode 100755
index 0000000..bd5fdf4
--- /dev/null
+++ b/res/drawable-xhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_uninstall_launcher.png b/res/drawable-xhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..dd50e88
--- /dev/null
+++ b/res/drawable-xhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_widget_resize_handle.png b/res/drawable-xhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..f445a1c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xhdpi/on_boarding_welcome.png b/res/drawable-xhdpi/on_boarding_welcome.png
deleted file mode 100644
index 8c101e0..0000000
--- a/res/drawable-xhdpi/on_boarding_welcome.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/overscroll_glow_left.9.png b/res/drawable-xhdpi/overscroll_glow_left.9.png
deleted file mode 100644
index 4f248f7..0000000
--- a/res/drawable-xhdpi/overscroll_glow_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/overscroll_glow_right.9.png b/res/drawable-xhdpi/overscroll_glow_right.9.png
deleted file mode 100644
index 818a70d..0000000
--- a/res/drawable-xhdpi/overscroll_glow_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/paged_view_indicator.9.png b/res/drawable-xhdpi/paged_view_indicator.9.png
deleted file mode 100644
index fb8a228..0000000
--- a/res/drawable-xhdpi/paged_view_indicator.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_container_holo.9.png b/res/drawable-xhdpi/portal_container_holo.9.png
deleted file mode 100644
index cedbdc4..0000000
--- a/res/drawable-xhdpi/portal_container_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner.png b/res/drawable-xhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..7b6a8a0
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_holo.png b/res/drawable-xhdpi/portal_ring_inner_holo.png
deleted file mode 100644
index f9acfa2..0000000
--- a/res/drawable-xhdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_nolip.png b/res/drawable-xhdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..4b84436
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png b/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png
deleted file mode 100644
index eb2cf5f..0000000
--- a/res/drawable-xhdpi/portal_ring_inner_nolip_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_outer.png b/res/drawable-xhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..79c1888
--- /dev/null
+++ b/res/drawable-xhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_outer_holo.png b/res/drawable-xhdpi/portal_ring_outer_holo.png
deleted file mode 100644
index f32051d..0000000
--- a/res/drawable-xhdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/portal_ring_rest.png b/res/drawable-xhdpi/portal_ring_rest.png
index ff0369a..544a74f 100644
--- a/res/drawable-xhdpi/portal_ring_rest.png
+++ b/res/drawable-xhdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel.9.png b/res/drawable-xhdpi/quantum_panel.9.png
deleted file mode 100644
index 1797ad5..0000000
--- a/res/drawable-xhdpi/quantum_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel_bitmap.9.png b/res/drawable-xhdpi/quantum_panel_bitmap.9.png
new file mode 100644
index 0000000..13bdf09
--- /dev/null
+++ b/res/drawable-xhdpi/quantum_panel_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel_dark.9.png b/res/drawable-xhdpi/quantum_panel_dark.9.png
deleted file mode 100644
index 4c1868b..0000000
--- a/res/drawable-xhdpi/quantum_panel_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png
new file mode 100644
index 0000000..ac2e423
--- /dev/null
+++ b/res/drawable-xhdpi/quantum_panel_dark_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_frame.9.png b/res/drawable-xhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..bf7cc6b
--- /dev/null
+++ b/res/drawable-xhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_frame_holo.9.png b/res/drawable-xhdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 76cec60..0000000
--- a/res/drawable-xhdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_bottom.png b/res/drawable-xhdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index 19437d7..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_left.png b/res/drawable-xhdpi/widget_resize_handle_left.png
deleted file mode 100644
index 28c5487..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_right.png b/res/drawable-xhdpi/widget_resize_handle_right.png
deleted file mode 100644
index 4f672a6..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_handle_top.png b/res/drawable-xhdpi/widget_resize_handle_top.png
deleted file mode 100644
index e866c00..0000000
--- a/res/drawable-xhdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/widget_resize_shadow.9.png b/res/drawable-xhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..96dee7f
--- /dev/null
+++ b/res/drawable-xhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/apps_customize_bg.png b/res/drawable-xxhdpi/apps_customize_bg.png
deleted file mode 100644
index a51cc11..0000000
--- a/res/drawable-xxhdpi/apps_customize_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/arrow_dashed.png b/res/drawable-xxhdpi/arrow_dashed.png
deleted file mode 100644
index b64f4d0..0000000
--- a/res/drawable-xxhdpi/arrow_dashed.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/default_widget_preview_holo.9.png b/res/drawable-xxhdpi/default_widget_preview_holo.9.png
deleted file mode 100644
index 0f62097..0000000
--- a/res/drawable-xxhdpi/default_widget_preview_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/hotseat_bg_panel.9.png b/res/drawable-xxhdpi/hotseat_bg_panel.9.png
deleted file mode 100644
index 40fc076..0000000
--- a/res/drawable-xxhdpi/hotseat_bg_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/hotseat_scrubber_holo.9.png b/res/drawable-xxhdpi/hotseat_scrubber_holo.9.png
deleted file mode 100644
index 8a77536..0000000
--- a/res/drawable-xxhdpi/hotseat_scrubber_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/hotseat_track_holo.9.png b/res/drawable-xxhdpi/hotseat_track_holo.9.png
deleted file mode 100644
index dd2216f..0000000
--- a/res/drawable-xxhdpi/hotseat_track_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_grey.png b/res/drawable-xxhdpi/ic_arrow_back_grey.png
new file mode 100755
index 0000000..8e42e09
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_home_all_apps_holo_dark.png b/res/drawable-xxhdpi/ic_home_all_apps_holo_dark.png
deleted file mode 100644
index 0b8e88c..0000000
--- a/res/drawable-xxhdpi/ic_home_all_apps_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_home_google_logo_normal_holo.png b/res/drawable-xxhdpi/ic_home_google_logo_normal_holo.png
deleted file mode 100644
index a47b2ba..0000000
--- a/res/drawable-xxhdpi/ic_home_google_logo_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_home_google_logo_pressed_holo.png b/res/drawable-xxhdpi/ic_home_google_logo_pressed_holo.png
deleted file mode 100644
index 75625d1..0000000
--- a/res/drawable-xxhdpi/ic_home_google_logo_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_home_search_pressed_holo.png b/res/drawable-xxhdpi/ic_home_search_pressed_holo.png
deleted file mode 100644
index 800d994..0000000
--- a/res/drawable-xxhdpi/ic_home_search_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_home_voice_search_pressed_holo.png b/res/drawable-xxhdpi/ic_home_voice_search_pressed_holo.png
deleted file mode 100644
index 27a5897..0000000
--- a/res/drawable-xxhdpi/ic_home_voice_search_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_info_launcher.png b/res/drawable-xxhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..386d091
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
deleted file mode 100644
index 95cf841..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
deleted file mode 100644
index b0f5a27..0000000
--- a/res/drawable-xxhdpi/ic_launcher_clear_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png b/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
deleted file mode 100644
index 57f332a..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
deleted file mode 100644
index 94f0955..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
deleted file mode 100644
index 3bb098c..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_active_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png b/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
deleted file mode 100644
index 550cc5b..0000000
--- a/res/drawable-xxhdpi/ic_launcher_trashcan_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_current.png b/res/drawable-xxhdpi/ic_pageindicator_current.png
index 22b290e..5941c8e 100644
--- a/res/drawable-xxhdpi/ic_pageindicator_current.png
+++ b/res/drawable-xxhdpi/ic_pageindicator_current.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_current_folder.png b/res/drawable-xxhdpi/ic_pageindicator_current_folder.png
new file mode 100644
index 0000000..602b89a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_pageindicator_current_folder.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_default.png b/res/drawable-xxhdpi/ic_pageindicator_default.png
index e608cae..3fa9e5f 100644
--- a/res/drawable-xxhdpi/ic_pageindicator_default.png
+++ b/res/drawable-xxhdpi/ic_pageindicator_default.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_pageindicator_default_folder.png b/res/drawable-xxhdpi/ic_pageindicator_default_folder.png
new file mode 100644
index 0000000..bbcd7f9
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_pageindicator_default_folder.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_qs_remote_display.png b/res/drawable-xxhdpi/ic_qs_remote_display.png
deleted file mode 100644
index 25ea9fa..0000000
--- a/res/drawable-xxhdpi/ic_qs_remote_display.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_qs_remote_display_connected.png b/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
deleted file mode 100644
index 33a8d2d..0000000
--- a/res/drawable-xxhdpi/ic_qs_remote_display_connected.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_remove_launcher.png b/res/drawable-xxhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..7c28bb0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_search_grey.png b/res/drawable-xxhdpi/ic_search_grey.png
new file mode 100755
index 0000000..1d5c913
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_uninstall_launcher.png b/res/drawable-xxhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..872e829
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_widget_resize_handle.png b/res/drawable-xxhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..144cac9
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xxhdpi/overscroll_glow_left.9.png b/res/drawable-xxhdpi/overscroll_glow_left.9.png
deleted file mode 100644
index 1a895cd..0000000
--- a/res/drawable-xxhdpi/overscroll_glow_left.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/overscroll_glow_right.9.png b/res/drawable-xxhdpi/overscroll_glow_right.9.png
deleted file mode 100644
index 5766761..0000000
--- a/res/drawable-xxhdpi/overscroll_glow_right.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_container_holo.9.png b/res/drawable-xxhdpi/portal_container_holo.9.png
deleted file mode 100644
index 599a076..0000000
--- a/res/drawable-xxhdpi/portal_container_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner.png b/res/drawable-xxhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..d088a17
--- /dev/null
+++ b/res/drawable-xxhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner_holo.png b/res/drawable-xxhdpi/portal_ring_inner_holo.png
deleted file mode 100644
index 8cd6a59..0000000
--- a/res/drawable-xxhdpi/portal_ring_inner_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_inner_nolip_holo.png b/res/drawable-xxhdpi/portal_ring_inner_nolip.png
similarity index 100%
rename from res/drawable-xxhdpi/portal_ring_inner_nolip_holo.png
rename to res/drawable-xxhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_outer.png b/res/drawable-xxhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..45ac040
--- /dev/null
+++ b/res/drawable-xxhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xxhdpi/portal_ring_outer_holo.png b/res/drawable-xxhdpi/portal_ring_outer_holo.png
deleted file mode 100644
index 0aee4f0..0000000
--- a/res/drawable-xxhdpi/portal_ring_outer_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel.9.png b/res/drawable-xxhdpi/quantum_panel.9.png
deleted file mode 100644
index d7ba874..0000000
--- a/res/drawable-xxhdpi/quantum_panel.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel_bitmap.9.png b/res/drawable-xxhdpi/quantum_panel_bitmap.9.png
new file mode 100644
index 0000000..b44269e
--- /dev/null
+++ b/res/drawable-xxhdpi/quantum_panel_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel_dark.9.png b/res/drawable-xxhdpi/quantum_panel_dark.9.png
deleted file mode 100644
index 17ba0f1..0000000
--- a/res/drawable-xxhdpi/quantum_panel_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png
new file mode 100644
index 0000000..7979cf7
--- /dev/null
+++ b/res/drawable-xxhdpi/quantum_panel_dark_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_frame.9.png b/res/drawable-xxhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..7e189d4
--- /dev/null
+++ b/res/drawable-xxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_frame_holo.9.png b/res/drawable-xxhdpi/widget_resize_frame_holo.9.png
deleted file mode 100644
index 1681387..0000000
--- a/res/drawable-xxhdpi/widget_resize_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_bottom.png b/res/drawable-xxhdpi/widget_resize_handle_bottom.png
deleted file mode 100644
index d549fcd..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_bottom.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_left.png b/res/drawable-xxhdpi/widget_resize_handle_left.png
deleted file mode 100644
index dd56dad..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_left.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_right.png b/res/drawable-xxhdpi/widget_resize_handle_right.png
deleted file mode 100644
index 296a1c1..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_right.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_handle_top.png b/res/drawable-xxhdpi/widget_resize_handle_top.png
deleted file mode 100644
index e86270a..0000000
--- a/res/drawable-xxhdpi/widget_resize_handle_top.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/widget_resize_shadow.9.png b/res/drawable-xxhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..41c448b
--- /dev/null
+++ b/res/drawable-xxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_arrow_back_grey.png b/res/drawable-xxxhdpi/ic_arrow_back_grey.png
new file mode 100755
index 0000000..854a9bd
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_arrow_back_grey.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_info_launcher.png b/res/drawable-xxxhdpi/ic_info_launcher.png
new file mode 100644
index 0000000..bf39e5b
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_info_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_remove_launcher.png b/res/drawable-xxxhdpi/ic_remove_launcher.png
new file mode 100644
index 0000000..7043be0
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_remove_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_search_grey.png b/res/drawable-xxxhdpi/ic_search_grey.png
new file mode 100755
index 0000000..28519fd
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_search_grey.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_uninstall_launcher.png b/res/drawable-xxxhdpi/ic_uninstall_launcher.png
new file mode 100644
index 0000000..77a3302
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_uninstall_launcher.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_widget_resize_handle.png b/res/drawable-xxxhdpi/ic_widget_resize_handle.png
new file mode 100644
index 0000000..4bde6b9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_widget_resize_handle.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner.png b/res/drawable-xxxhdpi/portal_ring_inner.png
new file mode 100644
index 0000000..34a3599
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_inner.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_inner_nolip.png b/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
new file mode 100644
index 0000000..8cebb35
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_inner_nolip.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_outer.png b/res/drawable-xxxhdpi/portal_ring_outer.png
new file mode 100644
index 0000000..d2df322
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_outer.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/portal_ring_rest.png b/res/drawable-xxxhdpi/portal_ring_rest.png
new file mode 100644
index 0000000..11e92ee
--- /dev/null
+++ b/res/drawable-xxxhdpi/portal_ring_rest.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png b/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png
new file mode 100644
index 0000000..bc887fe
--- /dev/null
+++ b/res/drawable-xxxhdpi/quantum_panel_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png b/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png
new file mode 100644
index 0000000..7cfd6e4
--- /dev/null
+++ b/res/drawable-xxxhdpi/quantum_panel_dark_bitmap.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_frame.9.png b/res/drawable-xxxhdpi/widget_resize_frame.9.png
new file mode 100644
index 0000000..cb609ce
--- /dev/null
+++ b/res/drawable-xxxhdpi/widget_resize_frame.9.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/widget_resize_shadow.9.png b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
new file mode 100644
index 0000000..82c8b9c
--- /dev/null
+++ b/res/drawable-xxxhdpi/widget_resize_shadow.9.png
Binary files differ
diff --git a/res/anim/fade_out_fast.xml b/res/drawable/all_apps_search_bg.xml
similarity index 64%
copy from res/anim/fade_out_fast.xml
copy to res/drawable/all_apps_search_bg.xml
index a061a6c..a09f88f 100644
--- a/res/anim/fade_out_fast.xml
+++ b/res/drawable/all_apps_search_bg.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,11 +14,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
-
-    android:fromAlpha="1.0"
-    android:toAlpha="0.0"
-
-    android:duration="@android:integer/config_mediumAnimTime" />
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/quantum_panel"
+    android:insetTop="@dimen/container_bounds_minus_quantum_panel_padding_inset"
+    android:insetBottom="@dimen/container_bounds_minus_quantum_panel_padding_inset" />
\ No newline at end of file
diff --git a/res/drawable/info_target_selector.xml b/res/drawable/bg_screenpanel.xml
similarity index 77%
rename from res/drawable/info_target_selector.xml
rename to res/drawable/bg_screenpanel.xml
index f3a7016..cdb71df 100644
--- a/res/drawable/info_target_selector.xml
+++ b/res/drawable/bg_screenpanel.xml
@@ -2,7 +2,7 @@
 <!--
 /*
 **
-** Copyright 2011, The Android Open Source Project
+** Copyright 2015, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@
 */
 -->
 
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_info_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_info_active_holo"  />
-</transition>
+<transition xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item android:drawable="@drawable/screenpanel"/>
+    <item android:drawable="@drawable/screenpanel_hover"/>
+
+</transition>
\ No newline at end of file
diff --git a/res/drawable/container_fastscroll_popup_bg.xml b/res/drawable/container_fastscroll_popup_bg.xml
new file mode 100644
index 0000000..2ef07ab
--- /dev/null
+++ b/res/drawable/container_fastscroll_popup_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/container_fastscroll_thumb_active_color" />
+    <size
+        android:width="64dp"
+        android:height="64dp" />
+    <corners
+        android:topLeftRadius="64dp"
+        android:topRightRadius="64dp"
+        android:bottomLeftRadius="64dp" />
+</shape>
\ No newline at end of file
diff --git a/res/values-sw340dp-port/config.xml b/res/drawable/quantum_panel.xml
similarity index 76%
rename from res/values-sw340dp-port/config.xml
rename to res/drawable/quantum_panel.xml
index 5f71077..1f4fb71 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/drawable/quantum_panel.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,6 +14,5 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-</resources>
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/quantum_panel_bitmap" />
diff --git a/res/values-sw340dp-port/config.xml b/res/drawable/quantum_panel_dark.xml
similarity index 75%
copy from res/values-sw340dp-port/config.xml
copy to res/drawable/quantum_panel_dark.xml
index 5f71077..6642e78 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/drawable/quantum_panel_dark.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,6 +14,5 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-</resources>
+<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/quantum_panel_dark_bitmap" />
diff --git a/res/values-sw340dp-port/config.xml b/res/drawable/quantum_panel_shape.xml
similarity index 68%
copy from res/values-sw340dp-port/config.xml
copy to res/drawable/quantum_panel_shape.xml
index 5f71077..1083615 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/drawable/quantum_panel_shape.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,6 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/quantum_panel_bg_color" />
+    <corners
+        android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/values-sw340dp-port/config.xml b/res/drawable/quantum_panel_shape_dark.xml
similarity index 68%
copy from res/values-sw340dp-port/config.xml
copy to res/drawable/quantum_panel_shape_dark.xml
index 5f71077..c3821c4 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/drawable/quantum_panel_shape_dark.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,6 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/quantum_panel_bg_color_dark" />
+    <corners
+        android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/remove_target_selector.xml b/res/drawable/remove_target_selector.xml
deleted file mode 100644
index 5e071fb..0000000
--- a/res/drawable/remove_target_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_clear_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_clear_active_holo"  />
-</transition>
diff --git a/res/drawable/uninstall_target_selector.xml b/res/drawable/uninstall_target_selector.xml
deleted file mode 100644
index 229942e..0000000
--- a/res/drawable/uninstall_target_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/ic_launcher_trashcan_normal_holo"  />
-    <item android:drawable="@drawable/ic_launcher_trashcan_active_holo"  />
-</transition>
diff --git a/res/values-sw340dp-port/config.xml b/res/drawable/widgets_row_divider.xml
similarity index 70%
copy from res/values-sw340dp-port/config.xml
copy to res/drawable/widgets_row_divider.xml
index 5f71077..bb5b6b5 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/drawable/widgets_row_divider.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<resources>
-</resources>
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size android:width="@dimen/widget_row_divider" />
+    <solid android:color="@color/quantum_panel_bg_color_dark" />
+</shape>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 6f95bd5..6500ebc 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -18,11 +18,9 @@
 <com.android.launcher3.LauncherRootView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/workspace_bg"
     android:fitsSystemWindows="true">
 
     <com.android.launcher3.DragLayer
@@ -36,6 +34,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -43,11 +42,12 @@
             android:layout_gravity="center"
             launcher:defaultScreen="@integer/config_workspaceDefaultScreen" />
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="end" />
+            android:layout_gravity="right" />
 
         <include
             android:id="@+id/search_drop_target_bar"
@@ -57,8 +57,14 @@
             android:id="@+id/overview_panel"
             android:visibility="gone" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="invisible" />
+
+        <include layout="@layout/all_apps"
+            android:id="@+id/apps_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout-land/migration_cling.xml b/res/layout-land/migration_cling.xml
index db93da8..269c1ae 100644
--- a/res/layout-land/migration_cling.xml
+++ b/res/layout-land/migration_cling.xml
@@ -46,6 +46,7 @@
         android:layout_width="@dimen/cling_migration_content_width"
         android:layout_height="wrap_content"
         android:layout_marginEnd="@dimen/cling_migration_content_margin"
+        android:layout_marginRight="@dimen/cling_migration_content_margin"
         android:orientation="vertical"
         android:paddingLeft="24dp"
         android:paddingRight="24dp" >
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index af30a32..d0772ee 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -22,7 +22,6 @@
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/workspace_bg"
     android:fitsSystemWindows="true">
 
     <com.android.launcher3.DragLayer
@@ -36,6 +35,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -44,6 +44,7 @@
             launcher:pageIndicator="@+id/page_indicator">
         </com.android.launcher3.Workspace>
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
@@ -66,8 +67,14 @@
             android:id="@+id/search_drop_target_bar"
             layout="@layout/search_drop_target_bar" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="invisible" />
+
+        <include layout="@layout/all_apps"
+            android:id="@+id/apps_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout-port/migration_cling.xml b/res/layout-port/migration_cling.xml
index 81689d3..3f696a2 100644
--- a/res/layout-port/migration_cling.xml
+++ b/res/layout-port/migration_cling.xml
@@ -48,6 +48,7 @@
             android:layout_height="wrap_content"
             android:layout_below="@+id/ic_cling_migration"
             android:layout_marginStart="@dimen/cling_migration_content_margin"
+            android:layout_marginLeft="@dimen/cling_migration_content_margin"
             android:orientation="vertical"
             android:paddingLeft="24dp"
             android:paddingRight="24dp" >
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index 960ccf3..802922e 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -18,11 +18,9 @@
 <com.android.launcher3.LauncherRootView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
     android:id="@+id/launcher"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/workspace_bg"
     android:fitsSystemWindows="true">
 
     <com.android.launcher3.DragLayer
@@ -36,6 +34,7 @@
             android:layout_height="52dp" />
 
         <!-- The workspace contains 5 screens of cells -->
+        <!-- DO NOT CHANGE THE ID -->
         <com.android.launcher3.Workspace
             android:id="@+id/workspace"
             android:layout_width="match_parent"
@@ -44,6 +43,7 @@
             launcher:pageIndicator="@id/page_indicator">
         </com.android.launcher3.Workspace>
 
+        <!-- DO NOT CHANGE THE ID -->
         <include layout="@layout/hotseat"
             android:id="@+id/hotseat"
             android:layout_width="match_parent"
@@ -59,15 +59,20 @@
 
         <!-- Keep these behind the workspace so that they are not visible when
              we go into AllApps -->
-        <include
-            android:id="@+id/page_indicator"
+        <include android:id="@+id/page_indicator"
             layout="@layout/page_indicator"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="invisible" />
+
+        <include layout="@layout/all_apps"
+            android:id="@+id/apps_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout/add_list_item.xml b/res/layout/add_list_item.xml
deleted file mode 100644
index e937d7b..0000000
--- a/res/layout/add_list_item.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:minHeight="?android:attr/listPreferredItemHeight"
-    android:textAppearance="?android:attr/textAppearanceLarge"
-    android:gravity="center_vertical"
-    android:drawablePadding="14dip"
-    android:paddingLeft="15dip"
-    android:paddingRight="15dip" />
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
new file mode 100644
index 0000000..1bf54ee
--- /dev/null
+++ b/res/layout/all_apps.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- The top and bottom paddings are defined in this container, but since we want
+     the list view to span the full width (for touch interception purposes), we
+     will bake the left/right padding into that view's background itself. -->
+<com.android.launcher3.allapps.AllAppsContainerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/apps_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <!-- Both android:focusable and android:focusableInTouchMode are needed for
+         the view to get focus change events. -->
+    <FrameLayout
+        android:id="@+id/search_box_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:visibility="gone" />
+
+    <FrameLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <FrameLayout
+            android:id="@+id/all_apps_reveal"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:focusable="false"
+            android:elevation="2dp"
+            android:visibility="invisible" />
+        <include
+            layout="@layout/all_apps_container"
+            android:id="@+id/all_apps_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:visibility="gone" />
+    </FrameLayout>
+</com.android.launcher3.allapps.AllAppsContainerView>
\ No newline at end of file
diff --git a/res/layout/all_apps_button.xml b/res/layout/all_apps_button.xml
index 9d6d82b..68cc109 100644
--- a/res/layout/all_apps_button.xml
+++ b/res/layout/all_apps_button.xml
@@ -15,5 +15,5 @@
 -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon"
+   style="@style/Icon"
    android:focusable="true" />
diff --git a/res/layout/all_apps_container.xml b/res/layout/all_apps_container.xml
new file mode 100644
index 0000000..626edaf
--- /dev/null
+++ b/res/layout/all_apps_container.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Both android:focusable and android:focusableInTouchMode are needed for
+     the view to get focus change events. -->
+<com.android.launcher3.allapps.AllAppsRecyclerViewContainerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:elevation="15dp"
+    android:focusable="true"
+    android:focusableInTouchMode="true">
+
+    <!-- DO NOT CHANGE THE ID -->
+    <com.android.launcher3.allapps.AllAppsRecyclerView
+        android:id="@+id/apps_list_view"
+        android:theme="@style/Theme.Light.CustomOverscroll"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_horizontal|top"
+        android:clipToPadding="false"
+        android:focusable="true"
+        android:descendantFocusability="afterDescendants" />
+
+</com.android.launcher3.allapps.AllAppsRecyclerViewContainerView>
\ No newline at end of file
diff --git a/res/layout/apps_customize_application.xml b/res/layout/all_apps_empty_search.xml
similarity index 61%
rename from res/layout/apps_customize_application.xml
rename to res/layout/all_apps_empty_search.xml
index c56cdf3..f60c4a0 100644
--- a/res/layout/apps_customize_application.xml
+++ b/res/layout/all_apps_empty_search.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,9 +13,16 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<com.android.launcher3.BubbleTextView
+<TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/WorkspaceIcon.AppsCustomize"
-    android:id="@+id/application_icon"
-    android:focusable="true" />
+    android:id="@+id/empty_text"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:paddingTop="24dp"
+    android:paddingBottom="24dp"
+    android:paddingRight="@dimen/all_apps_grid_view_start_margin"
+    android:textSize="16sp"
+    android:textColor="#4c4c4c"
+    android:focusable="false" />
+
diff --git a/res/layout/all_apps_icon.xml b/res/layout/all_apps_icon.xml
new file mode 100644
index 0000000..0985e95
--- /dev/null
+++ b/res/layout/all_apps_icon.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.BubbleTextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    style="@style/Icon.AllApps"
+    android:id="@+id/icon"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:paddingTop="@dimen/all_apps_icon_top_bottom_padding"
+    android:paddingBottom="@dimen/all_apps_icon_top_bottom_padding"
+    android:focusable="true"
+    android:background="@drawable/focusable_view_bg"
+    launcher:iconDisplay="all_apps" />
+
diff --git a/res/layout/all_apps_prediction_bar_icon.xml b/res/layout/all_apps_prediction_bar_icon.xml
new file mode 100644
index 0000000..341d8ef
--- /dev/null
+++ b/res/layout/all_apps_prediction_bar_icon.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.BubbleTextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    style="@style/Icon.AllApps"
+    android:id="@+id/icon"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:paddingTop="@dimen/all_apps_prediction_icon_top_padding"
+    android:paddingBottom="@dimen/all_apps_prediction_icon_bottom_padding"
+    android:focusable="true"
+    android:background="@drawable/focusable_view_bg"
+    launcher:iconDisplay="all_apps" />
+
diff --git a/res/layout/all_apps_search_bar.xml b/res/layout/all_apps_search_bar.xml
new file mode 100644
index 0000000..cf30eac
--- /dev/null
+++ b/res/layout/all_apps_search_bar.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/all_apps_search_bg" >
+
+    <LinearLayout
+        android:id="@+id/search_container"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/all_apps_search_bar_height"
+        android:layout_gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:visibility="invisible" >
+
+        <ImageView
+            android:id="@+id/dismiss_search_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="4dp"
+            android:layout_marginStart="4dp"
+            android:contentDescription="@string/all_apps_button_label"
+            android:paddingBottom="13dp"
+            android:paddingTop="13dp"
+            android:src="@drawable/ic_arrow_back_grey" />
+
+        <com.android.launcher3.allapps.AllAppsSearchEditView
+            android:id="@+id/search_box_input"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@android:color/transparent"
+            android:focusableInTouchMode="true"
+            android:gravity="fill_horizontal|center_vertical"
+            android:hint="@string/all_apps_search_bar_hint"
+            android:inputType="text|textNoSuggestions|textCapWords"
+            android:imeOptions="actionDone|flagNoExtractUi"
+            android:maxLines="1"
+            android:paddingLeft="8dp"
+            android:scrollHorizontally="true"
+            android:singleLine="true"
+            android:textColor="#4c4c4c"
+            android:textColorHint="#9c9c9c"
+            android:textSize="16sp" />
+    </LinearLayout>
+
+    <ImageView
+        android:id="@+id/search_button"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/all_apps_search_bar_height"
+        android:layout_gravity="end|center_vertical"
+        android:layout_marginEnd="4dp"
+        android:layout_marginRight="4dp"
+        android:contentDescription="@string/all_apps_search_bar_hint"
+        android:paddingBottom="13dp"
+        android:paddingTop="13dp"
+        android:src="@drawable/ic_search_grey" />
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/application.xml b/res/layout/app_icon.xml
similarity index 95%
rename from res/layout/application.xml
rename to res/layout/app_icon.xml
index c21dea0..831cee5 100644
--- a/res/layout/application.xml
+++ b/res/layout/app_icon.xml
@@ -15,5 +15,5 @@
 -->
 
 <com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon"
+   style="@style/Icon"
    android:focusable="true" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
deleted file mode 100644
index e42576f..0000000
--- a/res/layout/apps_customize_pane.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.AppsCustomizeTabHost
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:clipChildren="false">
-
-    <LinearLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:orientation="vertical">
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:clipChildren="false">
-            <FrameLayout
-                android:id="@+id/fake_page_container"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false">
-                <FrameLayout
-                    android:id="@+id/fake_page"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:visibility="invisible"
-                    android:clipToPadding="false" />
-            </FrameLayout>
-            <com.android.launcher3.AppsCustomizePagedView
-                android:id="@+id/apps_customize_pane_content"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
-                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
-                launcher:maxGap="@dimen/workspace_max_gap"
-                launcher:pageIndicator="@+id/apps_customize_page_indicator" />
-        </FrameLayout>
-        <include
-            android:id="@+id/apps_customize_page_indicator"
-            layout="@layout/page_indicator"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center" />
-    </LinearLayout>
-</com.android.launcher3.AppsCustomizeTabHost>
diff --git a/res/layout/apps_customize_progressbar.xml b/res/layout/apps_customize_progressbar.xml
deleted file mode 100644
index 6aa9099..0000000
--- a/res/layout/apps_customize_progressbar.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<ProgressBar
-   xmlns:android="http://schemas.android.com/apk/res/android"
-   style="?android:attr/progressBarStyleLarge"
-   android:id="@+id/apps_customize_progress_bar"
-   android:layout_width="wrap_content"
-   android:layout_height="wrap_content"
-   android:layout_gravity="center" />
diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml
deleted file mode 100644
index a8344e3..0000000
--- a/res/layout/apps_customize_widget.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.PagedViewWidget
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_weight="1"
-    android:orientation="vertical"
-
-    android:background="@drawable/focusable_view_bg"
-    android:focusable="true">
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1">
-        <FrameLayout
-            android:id="@+id/left_border"
-            android:layout_width="1dp"
-            android:layout_height="match_parent"
-            android:background="@color/widget_text_panel"
-            android:visibility="gone" />
-
-        <!-- The preview of the widget or shortcut. -->
-        <com.android.launcher3.PagedViewWidgetImageView
-            android:id="@+id/widget_preview"
-            style="@style/PagedViewWidgetImageView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:paddingTop="@dimen/app_widget_preview_padding_top"
-            android:paddingEnd="@dimen/app_widget_preview_padding_right"
-            android:paddingRight="@dimen/app_widget_preview_padding_right"
-            android:scaleType="matrix" />
-        <FrameLayout
-            android:id="@+id/right_border"
-            android:layout_width="1dp"
-            android:layout_height="match_parent"
-            android:background="@color/widget_text_panel"
-            android:visibility="gone" />
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="@dimen/app_widget_preview_label_vertical_padding"
-        android:paddingBottom="@dimen/app_widget_preview_label_vertical_padding"
-        android:paddingLeft="@dimen/app_widget_preview_label_horizontal_padding"
-        android:paddingRight="@dimen/app_widget_preview_label_horizontal_padding"
-        android:background="@color/widget_text_panel"
-        android:orientation="horizontal">
-        <!-- The name of the widget. -->
-        <TextView
-            android:id="@+id/widget_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:gravity="start"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-
-            android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
-            android:textAlignment="viewStart"
-            android:fontFamily="sans-serif-condensed"
-            android:shadowRadius="2.0"
-            android:shadowColor="#B0000000" />
-
-        <!-- The original dimensions of the widget (can't be the same text as above due to different
-             style. -->
-        <TextView
-            android:id="@+id/widget_dims"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:layout_marginStart="5dp"
-            android:layout_weight="0"
-            android:gravity="start"
-
-            android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
-            android:fontFamily="sans-serif-condensed"
-            android:shadowRadius="2.0"
-            android:shadowColor="#B0000000" />
-    </LinearLayout>
-
-
-</com.android.launcher3.PagedViewWidget>
diff --git a/res/layout/appwidget_error.xml b/res/layout/appwidget_error.xml
index 03d4ae4..708ece4 100644
--- a/res/layout/appwidget_error.xml
+++ b/res/layout/appwidget_error.xml
@@ -15,15 +15,12 @@
 -->
 
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:paddingTop="10dip"
-    android:paddingBottom="10dip"
-    android:paddingLeft="20dip"
-    android:paddingRight="20dip"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:gravity="center"
-    android:background="@drawable/bg_appwidget_error"
+    android:elevation="2dp"
+    android:background="@drawable/quantum_panel_dark"
     android:textAppearance="?android:attr/textAppearanceMediumInverse"
-    android:textColor="@color/appwidget_error_color"
+    android:textColor="@color/widgets_view_item_text_color"
     android:text="@string/gadget_error_text"
     />
diff --git a/res/layout/dummy_widget.xml b/res/layout/dummy_widget.xml
new file mode 100644
index 0000000..a0fa8fc
--- /dev/null
+++ b/res/layout/dummy_widget.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="horizontal">
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="#ffff0000" />
+
+    <FrameLayout
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="#ff00ff00" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/folder_application.xml b/res/layout/folder_application.xml
index b48b613..4d00331 100644
--- a/res/layout/folder_application.xml
+++ b/res/layout/folder_application.xml
@@ -15,5 +15,5 @@
 -->
 
 <com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon.Folder"
+   style="@style/Icon.Folder"
    android:focusable="true" />
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index fd45d76..237af68 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -26,9 +26,9 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:antialias="true"
-        android:src="@drawable/portal_ring_inner_holo"/>
+        android:src="@drawable/portal_ring_inner"/>
     <com.android.launcher3.BubbleTextView
-        style="@style/WorkspaceIcon"
+        style="@style/Icon"
         android:id="@+id/folder_icon_name"
         android:layout_gravity="top"
         android:layout_width="match_parent"
diff --git a/res/layout/page_indicator_marker.xml b/res/layout/page_indicator_marker.xml
index 686d275..564a958 100644
--- a/res/layout/page_indicator_marker.xml
+++ b/res/layout/page_indicator_marker.xml
@@ -16,8 +16,8 @@
 <com.android.launcher3.PageIndicatorMarker
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="16dp"
-    android:layout_height="16dp"
+    android:layout_width="12dp"
+    android:layout_height="12dp"
     android:layout_gravity="center_vertical">
     <ImageView
         android:id="@+id/inactive"
diff --git a/res/layout/rename_folder.xml b/res/layout/rename_folder.xml
deleted file mode 100644
index 21a335c..0000000
--- a/res/layout/rename_folder.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:padding="20dip"
-    android:orientation="vertical">
-
-    <TextView 
-        android:id="@+id/label"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:text="@string/rename_folder_label"
-        android:gravity="start"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-            
-    <EditText
-        android:id="@+id/folder_name"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:scrollHorizontally="true"
-        android:autoText="false"
-        android:capitalize="none"
-        android:gravity="fill_horizontal"
-        android:maxLength="30"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-</LinearLayout>
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index af2d0163..4737ee1 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -17,8 +17,7 @@
 <com.android.launcher3.SearchDropTargetBar xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:focusable="false"
-    android:orientation="horizontal" >
+    android:focusable="false" >
 
     <!-- Drag specific targets container -->
 
@@ -37,8 +36,7 @@
             <com.android.launcher3.DeleteDropTarget
                 android:id="@+id/delete_target_text"
                 style="@style/DropTargetButton"
-                android:drawableStart="@drawable/remove_target_selector"
-                android:text="@string/delete_zone_label_workspace" />
+                android:text="@string/delete_target_label" />
         </FrameLayout>
 
         <FrameLayout
@@ -50,9 +48,20 @@
             <com.android.launcher3.InfoDropTarget
                 android:id="@+id/info_target_text"
                 style="@style/DropTargetButton"
-                android:drawableStart="@drawable/info_target_selector"
                 android:text="@string/info_target_label" />
         </FrameLayout>
+
+        <FrameLayout
+            style="@style/DropTargetButtonContainer"
+            android:layout_weight="1" >
+
+            <!-- Uninstall target -->
+
+            <com.android.launcher3.UninstallDropTarget
+                android:id="@+id/uninstall_target_text"
+                style="@style/DropTargetButton"
+                android:text="@string/delete_target_uninstall_label" />
+        </FrameLayout>
     </LinearLayout>
 
 </com.android.launcher3.SearchDropTargetBar>
\ No newline at end of file
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index ed8d43e..ecf7def 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,43 +14,72 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<com.android.launcher3.Folder
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.Folder xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:background="@drawable/quantum_panel">
+    android:background="@drawable/quantum_panel"
+    android:elevation="5dp"
+    android:orientation="vertical" >
 
-    <ScrollView
-        android:id="@+id/scroll_view"
+    <FrameLayout
+        android:id="@+id/folder_content_wrapper"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-      <com.android.launcher3.CellLayout
-          android:id="@+id/folder_content"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:cacheColorHint="#ff333333"
-          android:hapticFeedbackEnabled="false" />
-    </ScrollView>
+        android:layout_height="match_parent" >
 
-    <com.android.launcher3.FolderEditText
-        android:id="@+id/folder_name"
+        <!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
+
+        <com.android.launcher3.FocusIndicatorView
+            android:id="@+id/focus_indicator"
+            android:layout_width="20dp"
+            android:layout_height="20dp" />
+
+        <com.android.launcher3.FolderPagedView
+            android:id="@+id/folder_content"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingLeft="4dp"
+            android:paddingRight="4dp"
+            android:paddingTop="8dp"
+            launcher:pageIndicator="@+id/folder_page_indicator" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:id="@+id/folder_footer"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_centerHorizontal="true"
-        android:paddingTop="@dimen/folder_name_padding"
-        android:paddingBottom="@dimen/folder_name_padding"
-        android:background="#00000000"
-        android:hint="@string/folder_hint_text"
-        android:textSize="14sp"
-        android:textColor="#ff777777"
-        android:textColorHint="#ff808080"
-        android:textColorHighlight="#ffCCCCCC"
-        android:textCursorDrawable="@null"
-        android:gravity="center_horizontal"
-        android:singleLine="true"
-        android:imeOptions="flagNoExtractUi"
-        android:fontFamily="sans-serif-condensed"/>
-</com.android.launcher3.Folder>
+        android:clipChildren="false"
+        android:orientation="horizontal"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp" >
+
+        <com.android.launcher3.FolderEditText
+            android:id="@+id/folder_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_weight="1"
+            android:background="#00000000"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="center_horizontal"
+            android:hint="@string/folder_hint_text"
+            android:imeOptions="flagNoExtractUi"
+            android:paddingBottom="8dp"
+            android:paddingTop="4dp"
+            android:singleLine="true"
+            android:textColor="#ff777777"
+            android:textColorHighlight="#ffCCCCCC"
+            android:textColorHint="#ff808080"
+            android:textCursorDrawable="@null"
+            android:textSize="14sp" />
+
+        <include
+            android:id="@+id/folder_page_indicator"
+            android:layout_width="wrap_content"
+            android:layout_height="12dp"
+            android:layout_gravity="center_vertical"
+            layout="@layout/page_indicator" />
+
+    </LinearLayout>
+
+</com.android.launcher3.Folder>
\ No newline at end of file
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
new file mode 100644
index 0000000..7fefeba
--- /dev/null
+++ b/res/layout/widget_cell.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.widget.WidgetCell
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:focusable="true"
+    android:background="@color/widgets_cell_color"
+    android:gravity="center_horizontal">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/widget_preview_label_vertical_padding"
+        android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
+        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+        android:orientation="horizontal">
+
+        <!-- The name of the widget. -->
+        <TextView
+            android:id="@+id/widget_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="start"
+            android:shadowColor="#B0000000"
+            android:shadowRadius="2.0"
+            android:singleLine="true"
+            android:textColor="@color/widgets_view_item_text_color"
+            android:textSize="14sp" />
+
+        <!-- The original dimensions of the widget (can't be the same text as above due to different
+             style. -->
+        <TextView
+            android:id="@+id/widget_dims"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="5dp"
+            android:layout_marginLeft="5dp"
+            android:textColor="@color/widgets_view_item_text_color"
+            android:textSize="14sp"
+            android:fontFamily="sans-serif-condensed"
+            android:shadowRadius="2.0"
+            android:shadowColor="#B0000000" />
+    </LinearLayout>
+
+    <!-- The image of the widget. This view does not support padding. Any placement adjustment
+         should be done using margins. -->
+    <com.android.launcher3.widget.WidgetImageView
+        android:id="@+id/widget_preview"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</com.android.launcher3.widget.WidgetCell>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
new file mode 100644
index 0000000..ced5648
--- /dev/null
+++ b/res/layout/widgets_list_row_view.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/widgets_cell_list_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/widgets_cell_color"
+    android:orientation="vertical"
+    android:focusable="true"
+    android:descendantFocusability="afterDescendants">
+
+    <!-- Section info -->
+
+    <com.android.launcher3.BubbleTextView
+        android:id="@+id/section"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/widget_section_height"
+        android:background="@color/quantum_panel_bg_color_dark"
+        android:drawablePadding="@dimen/widget_section_horizontal_padding"
+        android:ellipsize="end"
+        android:focusable="true"
+        android:gravity="start|center_vertical"
+        android:importantForAccessibility="no"
+        android:paddingBottom="@dimen/widget_section_vertical_padding"
+        android:paddingLeft="@dimen/widget_section_horizontal_padding"
+        android:paddingRight="@dimen/widget_section_horizontal_padding"
+        android:paddingTop="@dimen/widget_section_vertical_padding"
+        android:singleLine="true"
+        android:textColor="@color/widgets_view_section_text_color"
+        android:textSize="16sp"
+        launcher:customShadows="false"
+        launcher:deferShadowGeneration="true"
+        launcher:iconDisplay="widget_section"
+        launcher:iconSizeOverride="@dimen/widget_section_icon_size"
+        launcher:layoutHorizontal="true" />
+
+    <HorizontalScrollView
+        android:id="@+id/widgets_scroll_container"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:scrollbars="none">
+        <LinearLayout
+            android:id="@+id/widgets_cell_list"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/widget_row_padding"
+            android:layout_marginLeft="@dimen/widget_row_padding"
+            android:orientation="horizontal"
+            android:divider="@drawable/widgets_row_divider"
+            android:showDividers="middle"/>
+    </HorizontalScrollView>
+</LinearLayout>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
new file mode 100644
index 0000000..755634f
--- /dev/null
+++ b/res/layout/widgets_view.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- The top and bottom paddings are defined in this container, but since we want
+     the list view to span the full width (for touch interception purposes), we
+     will bake the left/right padding into that view's background itself. -->
+<com.android.launcher3.widget.WidgetsContainerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/widgets_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:descendantFocusability="afterDescendants">
+
+    <FrameLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <FrameLayout
+            android:id="@+id/widgets_reveal_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:focusable="false"
+            android:elevation="2dp"
+            android:visibility="invisible" />
+
+        <!-- DO NOT CHANGE THE ID -->
+        <com.android.launcher3.widget.WidgetsRecyclerView
+            android:id="@+id/widgets_list_view"
+            android:theme="@style/Theme.Dark.CustomOverscroll"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="center"
+            android:elevation="15dp"
+            android:visibility="gone" />
+    </FrameLayout>
+
+</com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
diff --git a/res/mipmap-xxhdpi/on_boarding_welcome.png b/res/mipmap-xxhdpi/on_boarding_welcome.png
deleted file mode 100644
index 7b11dea..0000000
--- a/res/mipmap-xxhdpi/on_boarding_welcome.png
+++ /dev/null
Binary files differ
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index f37f08f..7004524 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Tuis"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android-kernprogramme"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Werk"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Program is nie geïnstalleer nie."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Program is nie beskikbaar nie"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Afgelaaide program in veiligmodus gedeaktiveer"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Legstukke gedeaktiveer in Veiligmodus"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Legstukke"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Legstukke"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Wys Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Raak en hou om \'n legstuk op te tel."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Kan nie item op hierdie Tuisskerm laat los nie."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Kies legstuk om te skep"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Vouernaam"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Hernoem vouer"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Kanselleer"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Voeg by Tuisskerm"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Programme"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Kortpaaie"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Legstukke"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Niks meer spasie op jou Tuisskerms nie."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Deursoek programme"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Laai tans programme …"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Geen programme gevind wat met \"<xliff:g id="QUERY">%1$s</xliff:g>\" ooreenstem nie"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Niks meer spasie op die tuisskerm nie."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen plek meer in die Gunstelinge-laai nie"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Hierdie legstuk is te groot vir die Gunstelinge-laai"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Kortpad \"<xliff:g id="NAME">%s</xliff:g>\" is geskep."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Kortpad \"<xliff:g id="NAME">%s</xliff:g>\" is verwyder."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Kortpad \"<xliff:g id="NAME">%s</xliff:g>\" bestaan reeds."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Kies kortpad"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Kies program"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programme"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Tuis"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Verwyder"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Deïnstalleer"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Verwyder"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Deïnstalleer"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Programinligting"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Programme"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Verwyder"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Deïnstalleer opdatering"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Deïnstalleer program"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Programbesonderhede"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 program gekies"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 legstuk gekies"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 vouer gekies"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 kortpad gekies"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installeer kortpaaie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Laat \'n program toe om kortpaaie by te voeg sonder gebruikerinmenging."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"deïnstalleer kortpaaie"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Laat die program toe om kortpaaie te verwyder sonder gebruikerinmenging."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lees Tuis-instellings en -kortpaaie"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Laat die program toe om die instellings en kortpaaie in Tuis te lees."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"skryf Tuis-instellings en -kortpaaie"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Kon nie legstuk laai nie"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Stel op"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is \'n stelselprogram en kan nie gedeïnstalleer word nie."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Vuurpyllanseerder"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamlose vouer"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Tuisskerm %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Programme-bladsy %1$d van %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Legstukke-bladsy %1$d van %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Welkom"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Maak jouself tuis."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Skep meer skerms vir programme en vouers"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopieer jou program-ikone"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Voer ikone en vouers vanaf jou ou tuisskerms in?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIEER IKONE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"BEGIN VAN NUUTS AF"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiseer jou spasie"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Raak en hou agtergrond om muurpapier, legstukke en instellings te bestuur."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Muurpapiere, legstukke en instellings"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Raak en hou agtergrond om te pasmaak"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"HET DIT"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Hier\'s \'n vouer"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Om een soos dié te skep, raak en hou \'n program en skuif dit dan oor \'n ander een."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Vouer oopgemaak, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Raak om vouer toe te maak"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Raak om hernoem te stoor"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Legstukke"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Muurpapiere"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Instellings"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Wag tans…"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Laai tans af…"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installeer tans…"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Laat draai toe"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nie teruggestel nie"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Verwyder almal"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwyder"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Soek"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Hierdie program is nie geïnstalleer nie"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Die program vir hierdie ikoon is nie geïnstalleer nie. Jy kan dit verwyder of die program soek en dit self installeer."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Voeg by tuisskerm"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Skuif item hierheen"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item is by tuisskerm gevoeg"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item is verwyder"</string>
+    <string name="action_move" msgid="4339390619886385032">"Skuif item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Skuif na ry <xliff:g id="NUMBER_0">%1$s</xliff:g> kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Skuif na posisie <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Skuif na gunstelingposisie <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item geskuif"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Voeg by vouer: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Voeg by vouer met <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item by vouer gevoeg"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Skep vouer met: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Vouer geskep"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Skuif na tuisskerm"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Skuif skerm na links"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Skuif skerm na regs"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skerm is geskuif"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Verander grootte"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Vermeerder breedte"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Vermeerder hoogte"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Verminder breedte"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Verminder hoogte"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Legstukgrootte is verander na breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 1a25f66..d7fed9d 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"ማስጀመሪያ3"</string>
-    <string name="home" msgid="7658288663002113681">"መነሻ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android ዋና መተግበሪያዎች"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ስራ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"መተግበሪያ አልተጫነም።"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"መተግበሪያ አይገኝም"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"የወረደው መተግበሪያ ደህንነቱ በተጠበቀ ሁኔታ ውስጥ ተሰናክሏል"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ምግብሮች በደህንነቱ የተጠበቀ ሁኔታ ተሰናክለዋል"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ፍርግሞች"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ፍርግሞች"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"ማህደረ ማስታወሻ አሳይ"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ፍርግም ለማንሳት ይንኩ እና ይያዙት"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ንጥሉን እዚህ የመነሻ ማያ ገጽ ላይ ማኖር አልተቻለም።"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ለመፍጠር መግብር ይምረጡ"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"አቃፊ ስም"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"አቃፊ ዳግም ሰይም"</string>
-    <string name="rename_action" msgid="5559600076028658757">"እሺ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ይቅር"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ወደ መነሻ ማያ ገጽ ያክሉ"</string>
-    <string name="group_applications" msgid="3797214114206693605">"መተግበሪያዎች"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"አቋራጮች"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ፍርግሞች"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"የመነሻ ማያ ገጾችዎ ላይ ተጨማሪ ቦታ የለም።"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"መተግበሪያዎችን ይፈልጉ"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"መተግበሪያዎችን በመጫን ላይ..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"ከ«<xliff:g id="QUERY">%1$s</xliff:g>» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"</string>
     <string name="out_of_space" msgid="4691004494942118364">"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ይህ መግብር ወደ የተወዳጆች መሣቢያ ላይ እንዳይገባ በጣም ትልቅ ነው"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"አቋራጭ «<xliff:g id="NAME">%s</xliff:g>» ተፈጥሯል።"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"አቋራጭ «<xliff:g id="NAME">%s</xliff:g>» ተወግዶ ነበር።"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"አቋራጭ «<xliff:g id="NAME">%s</xliff:g>» አስቀድሞ አለ።"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"አቋራጭ ይምረጡ"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"መተግበሪያ ይምረጡ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"መተግበሪያዎች"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"መነሻ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"አስወግድ"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"አራግፍ"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"አስወግድ"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"አራግፍ"</string>
     <string name="info_target_label" msgid="8053346143994679532">"የመተግበሪያ መረጃ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"መተግበሪያዎች"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"አስወግድ"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ዝማኔ አራግፍ"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"መተግበሪያ አራግፍ"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"የመተግበሪያ ዝርዝሮች"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 መተግበሪያ ተመርጧል"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ፍርግም ተመርጧል"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 አቃፊ ተመርጧል"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 አቋራጭ ተመርጧል"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"አቋራጮችን ይጭናል"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"መተግበሪያው ያለተጠቃሚ ጣልቃ ገብነት አቋራጭ እንዲያክል ያስችለዋል።"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"አቋራጮችን ያራግፋል"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"መተግበሪያው አቋራጮችን ያለተጠቃሚ ጣልቃ ገብነት እንዲያስወግድ ያስችለዋል።"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"የመነሻ ቅንብሮች እና አቋራጮችን ያነባል"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"መተግበሪያው በመነሻ ውስጥ ያሉ ቅንብሮችን እና አቋራጮችን እንዲያነብ ያስችለዋል።"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"የመነሻ ቅንብሮችን እና አቋራጮችን ይጽፋል"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ፍርግም የመጫን ችግር"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ማዋቀሪያ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ይህ የስርዓት መተግበሪያ ነው እና ማራገፍ አይቻልም።"</string>
-    <string name="dream_name" msgid="1530253749244328964">"የሮኬት ማስጀመሪያ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ስም-አልባ አቃፊ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"መነሻ ማያ ገጽ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"የመተግበሪያዎች ገጽ %1$d ከ%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"የመግብሮች ገጽ %1$d ከ%2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"እንኳን በደህና መጡ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ልክ እቤትዎ እንዳሉ ሆነው ዘና ይበሉ።"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ለመተግበሪያዎች እና አቃፊዎች ተጨማሪ ማያ ገጾችን ይፍጠሩ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"የመተግበሪያ አዶዎችዎን ይቅዱ"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"አዶዎች እና አቃፊዎች ከድሮው የመነሻ ማያ ገጾችዎ ይምጡ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"አዶዎችን ይቅዱ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"እንደ አዲስ ይጀምሩ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ቦታዎን ያደራጁ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ልጣፍ ፣ ምግብሮችን እና ቅንብሮችን ለማቀናበር ጀርባውን ይንኩ እና ይያዙት።"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"የግድግዳ ወረቀቶች፣ ንዑስ ፕሮግራሞች እና ቅንብሮች"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ለማበጀት ጀርባውን ነክተው ይያዙት"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ገባኝ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"አንድ አቃፊ እነሆ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"አንድ እንደዚህ አይነት ለመፍጠር መተግበሪያውን ነክተው ይያዙት እና ወደ ሌላ ያንቀሳቅሱት።"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"እሺ"</string>
     <string name="folder_opened" msgid="94695026776264709">"አቃፊ ተከፍቷል፣ <xliff:g id="WIDTH">%1$d</xliff:g> በ<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"አቃፊን ለመዝጋት ይንኩ"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"ዳግም የተሰየመውን ለማስቀመጥ ይንኩ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ፍርግሞች"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"የግድግዳ ወረቀቶች"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ቅንብሮች"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"በመጠበቅ ላይ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"በማውረድ ላይ"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"በመጫን ላይ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"ማሽከርከርን ይፍቀዱ"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"የማይታወቅ"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ወደነበረበት አልተመለሰም"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ሁሉንም አስወግድ"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"አስወግድ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ፈልግ"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ይህ መተግበሪያ አልተጫነም"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"የዚህ አዶ መተግበሪያ አልተጫነም። ማስወገድ ወይም መተግበሪያውን መፈለግና ራስዎ መጫን ይችላሉ።"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ወደ መነሻ ማያ ገጽ ያክሉ"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ንጥልን ወደዚህ ውሰድ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ወደ መነሻ ማያ ገጽ ንጥል ታክሏል"</string>
+    <string name="item_removed" msgid="851119963877842327">"ንጥል ነገር ተንቀሳቅሷል"</string>
+    <string name="action_move" msgid="4339390619886385032">"ንጥልን አንቀሳቅስ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ወደ ረድፍ <xliff:g id="NUMBER_0">%1$s</xliff:g> ዓምድ <xliff:g id="NUMBER_1">%2$s</xliff:g> አንቀሳቅስ"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"ወደ አቀማመጥ <xliff:g id="NUMBER">%1$s</xliff:g> አንቀሳቅስ"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ወደ ተወዳጆች አቀማመጥ <xliff:g id="NUMBER">%1$s</xliff:g> አንቀሳቅስ"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ንጥል ተንቀሳቅሷል"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ወደ አቃፊ አክል፦ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"ወደ አቃፊ አክል ከ<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ንጥል ወደ አቃፊ ታክሏል"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"አቃፊ ፍጠር ከዚህ ጋር፦ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"አቃፊ ተፈጥሮዋል"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ወደ መነሻ ማያ ገጽ አንቀሳቅስ"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"ማያ ገጽን ወደ ግራ አንቀሳቅስ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"ማያ ገጽን ወደ ቀኝ አንቀሳቅስ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ማያ ገጽ ተንቀሳቅሷል"</string>
+    <string name="action_resize" msgid="1802976324781771067">"መጠን ቀይር"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"ስፋት ጨምር"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ቁመት ጨምር"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ስፋት ይቀንሱ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ቁመት ይቀንሱ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"የመግብር መጠን ወደ ስፋት <xliff:g id="NUMBER_0">%1$s</xliff:g> ቁመት <xliff:g id="NUMBER_1">%2$s</xliff:g> ተለውጧል"</string>
 </resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 592be58..b7cd901 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"الرئيسية"</string>
-    <string name="uid_name" msgid="7820867637514617527">"‏تطبيقات Android الأساسية"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"العمل"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"لم يتم تثبيت التطبيق."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"التطبيق ليس متاحًا"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"تم تعطيل التطبيق الذي تم تنزيله في الوضع الآمن"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"الأدوات معطلة في الوضع الآمن"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"الأدوات"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"الأدوات"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"عرض الذاكرة"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"المس مع الاستمرار لاختيار إحدى الأدوات."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"تعذر إسقاط العنصر على هذه الشاشة الرئيسية."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"اختيار أداة لإنشائها"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"اسم المجلد"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"إعادة تسمية المجلد"</string>
-    <string name="rename_action" msgid="5559600076028658757">"موافق"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"إلغاء"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"إضافة إلى الشاشة الرئيسية"</string>
-    <string name="group_applications" msgid="3797214114206693605">"التطبيقات"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"الاختصارات"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"الأدوات"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ليس هناك مساحة أخرى في الشاشات الرئيسية."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"البحث في التطبيقات"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"جارٍ تحميل التطبيقات…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"لم يتم العثور على أية تطبيقات تتطابق مع \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"لا يوجد المزيد من الحقول في علبة المفضلة"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"هذه الأداة كبيرة جدًا مما يحول دون قبولها في علبة المفضّلة"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"تم إنشاء الاختصار \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"تمت إزالة الاختصار \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"الاختصار \"<xliff:g id="NAME">%s</xliff:g>\" موجود من قبل."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"اختيار اختصار"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"اختيار تطبيق"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"التطبيقات"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"الرئيسية"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"إزالة"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"إزالة"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"إزالة"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"إزالة"</string>
     <string name="info_target_label" msgid="8053346143994679532">"معلومات عن التطبيق"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"التطبيقات"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"إزالة"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"إزالة التحديث"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"إزالة التطبيق"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"تفاصيل التطبيق"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"تم تحديد تطبيق واحد"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"تم تحديد أداة واحدة"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"تم تحديد مجلد واحد"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"تم تحديد اختصار واحد"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"تثبيت اختصارات"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"للسماح لتطبيق ما بإضافة اختصارات بدون تدخل المستخدم."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"إزالة الاختصارات"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"للسماح للتطبيق بإزالة الاختصارات بدون تدخل المستخدم."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"قراءة إعدادات واختصارات الشاشة الرئيسية"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"للسماح للتطبيق بقراءة الإعدادات والاختصارات في الشاشة الرئيسية."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"كتابة إعدادات واختصارات الشاشة الرئيسية"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"حدثت مشكلة أثناء تحميل الأداة"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"الإعداد"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"هذا تطبيق نظام وتتعذر إزالته."</string>
-    <string name="dream_name" msgid="1530253749244328964">"قاذفة صواريخ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"مجلد بدون اسم"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"‏الشاشة الرئيسية %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"‏صفحة التطبيقات %1$d من %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"‏صفحة الأدوات %1$d من %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"مرحبًا"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"تصرف على راحتك."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"إنشاء المزيد من الشاشات للتطبيقات والمجلدات"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"نسخ رموز التطبيقات"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"هل تريد استيراد رموز ومجلدات من الشاشات الرئيسية القديمة؟"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"نسخ الرموز"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"بداية جديدة"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"تنظيم مساحتك"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"المس مع الاستمرار الجزء الخلفي من صورة الشاشة لإدارة الخلفية والأدوات والإعدادات."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"الخلفيات والأدوات والإعدادات"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"المس مع الاستمرار الخلفية لتخصيصها"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"حسنًا"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"إليك المجلد"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"لإنشاء مجلد مثل هذا، المس أحد التطبيقات مع استمرار اللمس، ثم حركه فوق آخر."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"موافق"</string>
     <string name="folder_opened" msgid="94695026776264709">"تم فتح المجلد، بمقاس <xliff:g id="WIDTH">%1$d</xliff:g> في <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"المس لإغلاق المجلد"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"المس لحفظ إعادة التسمية"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"الأدوات"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"الخلفيات"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"الإعدادات"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"انتظار"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"جارٍ التنزيل"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"جارٍ التثبيت"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"السماح بالتدوير"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"غير معروفة"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"استعادة مخفقة"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"إزالة الكل"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"إزالة"</string>
     <string name="abandoned_search" msgid="891119232568284442">"بحث"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"لم يتم تثبيت هذا التطبيق"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"لم يتم تثبيت تطبيق لهذا الرمز. يمكنك إزالته أو البحث عن التطبيق وتثبيته يدويًا."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"إضافة إلى الشاشة الرئيسية"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"نقل العنصر إلى هنا"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"تمت إضافة العنصر إلى الشاشة الرئيسية"</string>
+    <string name="item_removed" msgid="851119963877842327">"تم حذف العنصر"</string>
+    <string name="action_move" msgid="4339390619886385032">"نقل العنصر"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"نقل إلى الصف <xliff:g id="NUMBER_0">%1$s</xliff:g> العمود <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"نقل إلى الموضع <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"نقل إلى الموضع المفضل <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"تم نقل العنصر"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"إضافة إلى المجلد: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"إضافة إلى المجلد الذي به <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"تمت إضافة العنصر إلى المجلد"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"إنشاء مجلد يتضمن: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"تم إنشاء المجلد"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"نقل إلى الشاشة الرئيسية"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"نقل الشاشة إلى اليسار"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"نقل الشاشة إلى اليمين"</string>
+    <string name="screen_moved" msgid="266230079505650577">"تم نقل الشاشة"</string>
+    <string name="action_resize" msgid="1802976324781771067">"تغيير حجم"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"زيادة العرض"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"زيادة الارتفاع"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"تقليل العرض"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"تقليل الارتفاع"</string>
+    <string name="widget_resized" msgid="9130327887929620">"تم تغيير حجم الأداة إلى العرض <xliff:g id="NUMBER_0">%1$s</xliff:g> والارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 0da8364..099a220 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Əsas səhifə"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Əsas Android Tətbiqləri"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"İş"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Tətbiq quraşdırılmayıb."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Tətbiq əlçatmazdır"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Güvənli rejimdə icazə verilməyən tətbiq endirildi"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Vidcetlər Güvənli rejimdə deaktiv edilib"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Vidcetlər"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Vidcetlər"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Suvenirləri göstər"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidceti götürmək üçün toxunub saxlayın."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Bu Əsas ekrana element atmaq mümkün olmadı."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Yaratmaq üçün vidcet seçin"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Qovluq adı"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Qovluq adını dəyiş"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Ləğv et"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Əsas ekrana əlavə et"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Tətbiqlər"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Qısa yollar"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Vidcet"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Əsas ekranlarınızda boş yer yoxdur."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tətbiq Axtarın"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Tətbiqlər endirilir..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" sorğusuna uyğun Tətbiqlər tapılmadı"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Bu Əsas ekranda boş yer yoxdur."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritlər-də yer yoxdur"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Bu vidcet Favorit-ə yerləşdirmək üçün çox böyükdür"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" qısayolu yaradılıb."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" qısayolu kənarlaşdırıldı."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" qısayolu artıq mövcuddur."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Qısayol seçin"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Tətbiq seçin"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Tətbiqlər"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Əsas səhifə"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Yığışdır"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Sistemdən sil"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Kənarlaşdır"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Sistemdən sil"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Tətbiq məlumatı"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Tətbiqlər"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Kənarlaşdır"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Güncəlləməni sistemdən sil"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Tətbiqi sistemdən sil"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Tətbiq məlumatları"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 tətbiq seçildi"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 vidcet seçilib"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 qovluq seçildi"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 qısayol seçilib"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"qısayolları quraşdır"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tətbiqə istifadəçi müdaxiləsi olmadan qısayolları əlavə etməyə icazə verir."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"qısayolları sistemdən sil"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"İstifadəçi müdaxiləsi olmadan tətbiqə qısayolları silməyə icazə verir."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Əsas Səhifə ayarlarını və qısayolları oxuyun"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Tətbiqə Əsas Səhifədə parametrləri və qısayolları oxumağa icazə verir."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Əsas Səhifə ayarlarını və qısayolları yazın"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Vidcet yükləmə problemi"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Quraşdırma"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu sistem tətbiqi olduğu üçün sistemdən silinə bilməz."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Raket Başladıcı"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Qovluq"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Əsas Səhifə ekranı %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d tətbiq səhifəsi %1$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d vidcet səhifəsi %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Xoş gəlmisiniz"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Özünüzü evinizdəki kimi hiss edin."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Tətbiqlər və qovluqlar üçün daha çox ekran yaradın"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Tətbiq ikonalarınızı kopyalayın"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Köhnə Əsas ekranınızda olan ikonalar və qovluqlar import edilsin?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"İKONALARI KOPYALA"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"YENİDƏN BAŞLA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Sahənizi təşkil edin"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Divar kağızını idarə etmək üçün arxa fona toxunun və saxlayın, vidcetlər və ayarlar."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Divar kağızları, vidcetlər və ayarlar"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Fərdiləşdirmək üçün arxa fona toxunaraq saxlayın"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ANLADIM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Burada qovluq var"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Bunun kimi birini yaradın, tətbiqə toxunun və saxlayın, sonra da bunu digərinin üstünə daşıyın."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Qovluq açıldı, <xliff:g id="HEIGHT">%2$d</xliff:g> hündürlük ilə <xliff:g id="WIDTH">%1$d</xliff:g> enində"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Qovluğu bağlamaq üçün toxunun"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Ad dəyişikliyini yadda saxlamaq üçün toxunun"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Vidcet"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Divar kağızları"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ayarlar"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Gözlənilir"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Endirilir"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Quraşdırılır"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Fırlatmağa icazə verin"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Naməlum"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Bərpa edilməyib"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Hamısını Silin"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Yığışdır"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Axtarış"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Bu tətbiq quraşdırılmayıb"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Bu ikona üçün tətbiq quraşdırılmayıb. Onu silə bilərsiniz, və ya tətbiqi taparaq manual yol ilə quraşdıra bilərsiniz."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Əsas ekrana əlavə edin"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Elementi bura köçürün"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Element əsas ekrana əlavə edildi"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element silindi"</string>
+    <string name="action_move" msgid="4339390619886385032">"Elementi köçürün"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Sıra <xliff:g id="NUMBER_0">%1$s</xliff:g> sütun <xliff:g id="NUMBER_1">%2$s</xliff:g> köçürün"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> mövqeyinə köçürün"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"<xliff:g id="NUMBER">%1$s</xliff:g> sevimlilər mövqeyinə köçürün"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elementin yeri dəyişildi"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Qovluğa əlavə edin: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> adlı qovluğa əlavə edin"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element qovluğa əlavə edildi"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Qovluq yaradın: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Qovluq yaradıldı"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Əsas ekrana köçürün"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranı sola köçürün"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranı sağa köçürün"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekran köçürülüb"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ölçüsünü dəyişin"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Eni artırın"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Hündürlüyü artırın"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Eni azaldın"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Hündürlüyü azaldın"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Vidcetin eni <xliff:g id="NUMBER_0">%1$s</xliff:g> hündürlüyü <xliff:g id="NUMBER_1">%2$s</xliff:g> kimi ölçüləndirildi"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 2015158..fc5390b 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -173,8 +173,6 @@
     <skip />
     <!-- no translation found for first_run_cling_description (6447072552696253358) -->
     <skip />
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
     <!-- no translation found for first_run_cling_create_screens_hint (6950729526680114157) -->
     <skip />
     <!-- no translation found for workspace_cling_title (5626202359865825661) -->
@@ -199,10 +197,6 @@
     <skip />
     <!-- no translation found for folder_name_format (6629239338071103179) -->
     <skip />
-    <string name="custom_workspace_cling_title_1" msgid="3750880082935033085"></string>
-    <string name="custom_workspace_cling_description_1" msgid="939966842147696724"></string>
-    <string name="custom_workspace_cling_title_2" msgid="662588444436552198"></string>
-    <string name="custom_workspace_cling_description_2" msgid="8097921091798539310"></string>
     <!-- no translation found for widget_button_text (2880537293434387943) -->
     <skip />
     <!-- no translation found for wallpaper_button_text (8404103075899945851) -->
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 3f710db..eeaa1ed 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Начало"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Основни приложения на Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Приложението не е инсталирано."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Приложението не е налично"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Изтегленото приложение е деактивирано в безопасния режим"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Приспособленията са деактивирани в безопасния режим"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Приспособления"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Приспособления"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Показване на паметта"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Докоснете и задръжте за избор на приспособление."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Не можа да се премести на този начален екран."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Избор на приспособл. за създаване"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Име на папката"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Преименуване на папка"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ОK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Отказ"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Добавяне към началния екран"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Приложения"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Преки пътища"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Приспособления"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"На началните ви екрани няма повече място."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Търсене в приложенията"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Приложенията се зареждат…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Няма намерени приложения, съответстващи на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="out_of_space" msgid="4691004494942118364">"На този начален екран няма повече място."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Няма повече място в областта с любимите"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Това приспособление е твърде голямо за областта с любимите"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Прекият път към <xliff:g id="NAME">%s</xliff:g> е създаден."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Прекият път към <xliff:g id="NAME">%s</xliff:g> бе премахнат."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Прекият път към <xliff:g id="NAME">%s</xliff:g> вече съществува."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Избор на пряк път"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Избор на приложение"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Приложения"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Начало"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Премахване"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Деинсталиране"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Премахване"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Деинсталиране"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Информация за приложението"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Приложения"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Премахване"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Деинст. на актуализацията"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Деинсталиране на приложението"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Подробности за приложението"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Избрано е 1 приложение"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Избрано е 1 приспособление"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Избрана е 1 папка"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Избран е 1 пряк път"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталиране на преки пътища"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Разрешава на приложението да добавя преки пътища без намеса на потребителя."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"деинсталиране на преки пътища"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Разрешава на приложението да премахва преки пътища без намеса на потребителя."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"четене на настройките и преките пътища в Начало"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Разрешава на приложението да чете настройките и преките пътища в Начало."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"запис на настройките и преките пътища в Начало"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при зареждане на приспособлението"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Настройване"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Това е системно приложение и не може да се деинсталира."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Ракетна площадка"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без име"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Начален екран %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Страница с приложения %1$d от %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Страница с приспособления %1$d от %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Добре дошли"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Персонализиране и приспособяване."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Създаване на още екрани за приложения и папки"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Икони на прилож. ви: Копиране"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Да се импортират ли иконите и папките от старите ви начални екрани?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПИРАНЕ НА ИКОНИТЕ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"СТАРТИРАНЕ ОТНАЧАЛО"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Организиране на мястото ви"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Докоснете и задръжте фона, за да управлявате тапета, приспособленията и настройките."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Тапети, приспособления и настройки"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Докоснете и задръжте фона за персонализиране"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"РАЗБРАХ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ето една папка"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"За да създадете подобна, докоснете и задръжте приложение, след което го преместете върху друго."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ОK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папката е отворена – <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Докоснете, за да затворите папката"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Докоснете, за да запазите новото име"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Приспособления"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Настройки"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Изчаква"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Изтегля се"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Инсталира се"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Разрешаване на завъртането"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Няма информация"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Не е възстановено"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Премахване на всички"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Премахване"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Търсене"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Това приложение не е инсталирано"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Приложението за тази икона не е инсталирано. Можете да я премахнете или да потърсите приложението и да го инсталирате ръчно."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Добавяне към началния екран"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Преместване на елемента тук"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Елементът е добавен към началния екран"</string>
+    <string name="item_removed" msgid="851119963877842327">"Елементът е премахнат"</string>
+    <string name="action_move" msgid="4339390619886385032">"Преместване на елемента"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Преместване към ред <xliff:g id="NUMBER_0">%1$s</xliff:g>, колона <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Преместване към позиция <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Преместване към позиция <xliff:g id="NUMBER">%1$s</xliff:g> в любимите"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Елементът е преместен"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Добавяне към папката „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Добавяне към папката, съдържаща <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Елементът е добавен към папката"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Създаване на папка с елемента „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Папката е създадена"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Преместване към началния екран"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Преместване на екрана наляво"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Преместване на екрана надясно"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Екранът е преместен"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Преоразмеряване"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Увеличаване на ширината"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Увеличаване на височината"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Намаляване на ширината"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Намаляване на височината"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Приспособлението е преоразмерено към ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> и височина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 1434201..57f7b51 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"লঞ্চার৩"</string>
-    <string name="home" msgid="7658288663002113681">"হোম"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android প্রাথমিক অ্যাপ্লিকেশানগুলি"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"কাজ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"অ্যাপ্লিকেশান ইনস্টল করা নেই৷"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"অ্যাপ্লিকেশান অনুপলব্ধ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ডাউনলোড করা অ্যাপ্লিকেশান নিরাপদ মোডে অক্ষম রয়েছে"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"সুরক্ষিত মোডে উইজেট নিষ্ক্রিয় থাকে"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"উইজেটগুলি"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"উইজেটগুলি"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"মেম দেখান"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"একটি উইজেট তুলতে তা স্পর্শ করে ধরে রাখুন৷"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"এই হোম স্ক্রীনে আইটেম রাখা যায়নি৷"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"তৈরি করেতে উইজেট চয়ন করুন"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ফোল্ডারের নাম"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ফোল্ডার পুনঃনামকরণ করুন"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ঠিক আছে"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"বাতিল করুন"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"হোম স্ক্রীনে যোগ করুন"</string>
-    <string name="group_applications" msgid="3797214114206693605">"অ্যাপ্লিকেশানগুলি"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"শর্টকাটগুলি"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"উইজেটগুলি"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"আপনার হোম স্ক্রীনগুলিতে আর কোনো জায়গা নেই৷"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"অ্যাপ্লিকেশানগুলি অনুসন্ধান করুন"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"অ্যাপ্লিকেশানগুলি লোড হচ্ছে..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ্লিকেশান পাওয়া যায়নি"</string>
     <string name="out_of_space" msgid="4691004494942118364">"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"পছন্দসই ট্রে\'র জন্য এই উইজেটটি খুবই বড়"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"শর্টকাট \"<xliff:g id="NAME">%s</xliff:g>\" তৈরি করা হয়েছে৷"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"শর্টকাট \"<xliff:g id="NAME">%s</xliff:g>\" সরানো হয়েছে৷"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"শর্টকাট <xliff:g id="NAME">%s</xliff:g> আগে থেকেই আছে৷"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"শর্টকাট চয়ন করুন"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"অ্যাপ্লিকেশান চয়ন করুন"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"অ্যাপ্লিকেশানগুলি"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"হোম"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"সরান"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"আনইনস্টল করুন"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"সরান"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"আনইনস্টল করুন"</string>
     <string name="info_target_label" msgid="8053346143994679532">"অ্যাপ্লিকেশানের তথ্য"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"অ্যাপ্লিকেশানগুলি"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"সরান"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"আপডেট আনইনস্টল করুন"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"অ্যাপ্লিকেশান আনইনস্টল করুন"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"অ্যাপ্লিকেশানের বিশদ বিবরণ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"১টি অ্যাপ্লিকেশান নির্বাচন করা হয়েছে"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"১টি উইজেট নির্বাচন করা হয়েছে"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"১টি ফোল্ডার নির্বাচন করা হয়েছে"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"১টি শর্টকাট নির্বাচন করা হয়েছে"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"শর্টকাটগুলি ইনস্টল করে"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"একটি অ্যাপ্লিকেশানকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি যোগ করার অনুমতি দেয়৷"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"শর্টকাটগুলি আনইনস্টল করে"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"অ্যাপ্লিকেশানটিকে ব্যবহারকারীর হস্তক্ষেপ ছাড়াই শর্টকাটগুলি সরানোর অনুমতি দেয়৷"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"হোম সেটিংস এবং শর্টকাটগুলি পড়ে"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"হোমে অ্যাপ্লিকেশানটিকে সেটিংস এবং শর্টকাটগুলি পড়তে দেয়৷"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"হোম সেটিংস এবং শর্টকাটগুলি লেখে"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"উইজেট লোড হতে সমস্যা হয়েছে"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"সেটআপ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"এটি একটি সিস্টেম অ্যাপ্লিকেশান এবং আনইনস্টল করা যাবে না৷"</string>
-    <string name="dream_name" msgid="1530253749244328964">"রকেট লঞ্চার"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"নামবিহীন ফোল্ডার"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d নম্বর হোম স্ক্রীন"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$dটির মধ্যে %1$dটি অ্যাপ্লিকেশান পৃষ্ঠা"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$dটির মধ্যে %1$dটি উইজেট পৃষ্ঠা"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"স্বাগতম"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"নিজের বাড়ির মতো স্বাচ্ছন্দ্য বোধ করুন৷"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"অ্যাপ্লিকেশান এবং ফোল্ডারগুলির জন্য আরো স্ক্রীn তৈরি করুন"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"আপনার অ্যাপ্লিকেশান আইকনগুলি অনুলিপি করুন"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"আপনার পুরানো হোম স্ক্রীন থেকে আইকন এবং ফোল্ডারগুলি আমদানি করবেন?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"আইকনগুলি অনুলিপি করুন"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"নতুন করে শুরু করুন"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"আপনার স্থান সংগঠিত করুন"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ওয়ালপেপার, উইজেট এবং সেটিংস পরিচালনা করতে পটভূমি স্পর্শ করে ধরে রাখুন৷"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ওয়ালপেপার, উইজেট এবং সেটিংস"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"কাস্টমাইজ করার জন্য পটভূমি স্পর্শ করে ধরে থাকুন"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"বুঝেছি"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"এখানে একটি ফোল্ডার আছে"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"এটির মতো একটি তৈরি করতে, একটি অ্যাপ্লিকেশান স্পর্শ করে ধরে রাখুন, এবং তারপরে এটিকে অন্য একটির উপরে সরিয়ে নিয়ে যান৷"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ঠিক আছে"</string>
     <string name="folder_opened" msgid="94695026776264709">"ফোল্ডার খোলা হয়েছে, <xliff:g id="WIDTH">%1$d</xliff:g> বাই <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ফোল্ডার বন্ধ করতে স্পর্শ করুন"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"পুনঃনামকরণ সংরক্ষণ করতে স্পর্শ করুন"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"উইজেটগুলি"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ওয়ালপেপারগুলি"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"সেটিংস"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"প্রতীক্ষা"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ডাউনলোড হচ্ছে"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ইনস্টল করা হচ্ছে"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"ঘূর্ণনের অনুমতি দিন"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"অজানা"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"পুনঃস্থাপন করা যায়নি"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"সবগুলি সরান"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"সরান"</string>
     <string name="abandoned_search" msgid="891119232568284442">"অনুসন্ধান"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"এই অ্যাপ্লিকেশানটি ইন্সটল করা নাই"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"এই আইকনের অ্যাপ্লিকেশানটি ইন্সটল করা নাই। আপনি এটি সরাতে পারেন বা অ্যাপ্লিকেশানটি অনুসন্ধান করে এটি নিজে ইন্সটল করতে পারেন।"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"হোম স্ক্রীনে যোগ করুন"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"এখানে আইটেম সরান"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"হোম স্ক্রীনে আইটেম যোগ করা হয়েছে"</string>
+    <string name="item_removed" msgid="851119963877842327">"আইটেম সরানো হয়েছে"</string>
+    <string name="action_move" msgid="4339390619886385032">"আইটেম সরান"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"সারি <xliff:g id="NUMBER_0">%1$s</xliff:g> কলাম <xliff:g id="NUMBER_1">%2$s</xliff:g> এ সরান"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"অবস্থানে সরান <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"পছন্দসই অবস্থানে সরান <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"আইটেম সরানো হয়েছে"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ফোল্ডারে যোগ করুন: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> সহ ফোল্ডারে যোগ করা হয়েছে"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"আইটেম ফোল্ডারে যোগ করা হয়েছে"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"এর সাথে ফোল্ডার তৈরি করুন: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ফোল্ডার তৈরি করা হয়েছে"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"হোম স্ক্রীনে সরান"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"স্ক্রীন বাম দিকে সরান"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"স্ক্রীন ডান দিকে সরান"</string>
+    <string name="screen_moved" msgid="266230079505650577">"স্ক্রীন সরানো হয়েছে"</string>
+    <string name="action_resize" msgid="1802976324781771067">"পুনরায় আকার দিন"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"প্রস্থ বাড়ান"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"উচ্চতা বাড়ান"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"প্রস্থ কমান"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা কমান"</string>
+    <string name="widget_resized" msgid="9130327887929620">"উইজেটের আকার প্রস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> তে পরিবর্তন করা হয়েছে"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 89e582a..83f284a 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Inici"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplicacions principals d\'Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Feina"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'aplicació no s\'ha instal·lat."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"L\'aplicació no està disponible."</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'aplicació que has baixat està desactivada al mode segur."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"En Mode segur, els widgets estan desactivats."</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostra la memòria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premut un widget per triar-lo."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"No s\'ha pogut deixar anar l\'element a Inici."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Tria el widget que vulguis crear"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nom de la carpeta"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Canvi de nom de la carpeta"</string>
-    <string name="rename_action" msgid="5559600076028658757">"D\'acord"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancel·la"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Afegir a la pantalla d\'inici"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicacions"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Dreceres"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No queda espai a les pantalles d\'inici."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca a les aplicacions"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"S\'estan carregant les aplicacions..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No s\'ha trobat cap aplicació que coincideixi amb <xliff:g id="QUERY">%1$s</xliff:g>"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Ja no queda espai en aquesta pantalla d\'inici."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No hi ha més espai a la safata Preferits."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Aquest widget és massa gran per a la safata Preferits."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"S\'ha creat la drecera \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"S\'ha suprimit la drecera \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"La drecera \"<xliff:g id="NAME">%s</xliff:g>\" ja existeix."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Tria d\'una drecera"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Tria d\'una aplicació"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicacions"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inici"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Suprimeix"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstal·la"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Suprimeix"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstal·la"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informació de l\'aplicació"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicacions"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Suprimeix"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstal·la l\'actualització"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstal·la l\'aplicació"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalls de l\'aplicació"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicació seleccionada"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget seleccionat"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 carpeta seleccionada"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 drecera seleccionada"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instal·la dreceres"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet que una aplicació afegeixi dreceres sense la intervenció de l\'usuari."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstal·la dreceres"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permet que l\'aplicació suprimeixi dreceres sense la intervenció de l\'usuari."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"llegeix la configuració i les dreceres de la pantalla d\'inici"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permet que l\'aplicació llegeixi la configuració i les dreceres de la pantalla d\'inici."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"escriu la configuració i les dreceres de la pantalla d\'inici"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"S\'ha produït un problema en carregar el widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuració"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aquesta aplicació és una aplicació del sistema i no es pot desinstal·lar."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sense nom"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Pantalla d\'inici %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Pàgina d\'aplicacions %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Pàgina de widgets %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Us donem la benvinguda"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Personalitza la pantalla d\'inici"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crea més pantalles per a aplicacions i carpetes"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar les icones d\'aplicació"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importar icones i carpetes de pantalles d\'inici anteriors?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIA LES ICONES."</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"NOU COMENÇAMENT"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organitza el teu espai"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Toca i mantén premut el fons per gestionar el fons de pantalla, els widgets i la configuració."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fons de pantalla, widgets i configuració"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén premut el fons per fer personalitzacions."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"D\'ACORD"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Aquí hi ha una carpeta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Per crear-ne una com aquesta, mantén premuda una aplicació i, a continuació, mou-la sobre una altra."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"D\'acord"</string>
     <string name="folder_opened" msgid="94695026776264709">"S\'ha obert la carpeta, <xliff:g id="WIDTH">%1$d</xliff:g> per <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toca per tancar la carpeta"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toca per desar el canvi de nom"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fons de pantalla"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Configuració"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"En espera"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"S\'està baixant"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instal·lant"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permet la rotació"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconegut"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"No restaurat"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Suprimeix-ho tot"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Suprimeix"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Aquesta aplicació no està instal·lada"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'aplicació d\'aquesta icona no està instal·lada. Pots suprimir-la o cercar l\'aplicació i instal·lar-la manualment."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Afegeix a la pantalla d\'inici"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mou l\'element aquí"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"S\'ha afegit l\'element a la pantalla d\'inici"</string>
+    <string name="item_removed" msgid="851119963877842327">"S\'ha suprimit l\'element"</string>
+    <string name="action_move" msgid="4339390619886385032">"Desplaça l\'element"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Desplaça l\'element a la fila <xliff:g id="NUMBER_0">%1$s</xliff:g> i la columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Desplaça l\'element a la posició <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Desplaça l\'element a la posició de preferits <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element desplaçat"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Afegeix l\'element a la carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Afegeix l\'element a la carpeta amb <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element afegit a la carpeta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Crea una carpeta amb: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Desplaça a la pantalla d\'inici"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Desplaça pantalla a l\'esquerra"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Desplaça pantalla a la dreta"</string>
+    <string name="screen_moved" msgid="266230079505650577">"S\'ha desplaçat la pantalla"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Canvia la mida"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Augmenta l\'amplada"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Augmenta l\'alçada"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Redueix l\'amplada"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Redueix l\'alçada"</string>
+    <string name="widget_resized" msgid="9130327887929620">"S\'ha canviat la mida del widget a l\'amplada <xliff:g id="NUMBER_0">%1$s</xliff:g> i l\'alçada <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 0288806..c99a7ed 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Plocha"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Práce"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikace není nainstalována."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikace není k dispozici."</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Stažená aplikace je v nouzovém režimu zakázána"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"V nouzovém režimu jsou widgety zakázány."</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgety"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgety"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Zobrazit Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Widget vyberete dotykem a podržením."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Na tuto plochu položku nelze přesunout."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Vyberte widget k vytvoření"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Název složky"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Přejmenovat složku"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Zrušit"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Přidat na plochu"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikace"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Klávesové zkratky"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgety"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Na plochách již není místo."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Hledat aplikace"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítání aplikací…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Dotazu „<xliff:g id="QUERY">%1$s</xliff:g>“ neodpovídají žádné aplikace"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na této ploše již není místo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na panelu Oblíbené položky již není místo."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Tento widget je pro panel Oblíbené položky příliš velký."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Zástupce aplikace <xliff:g id="NAME">%s</xliff:g> byl vytvořen."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Zástupce aplikace <xliff:g id="NAME">%s</xliff:g> byl odebrán."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Zástupce aplikace <xliff:g id="NAME">%s</xliff:g> již existuje."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Výběr zástupce"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Výběr aplikace"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikace"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Plocha"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Odstranit"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Odinstalovat"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Odstranit"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Odinstalovat"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informace o aplikaci"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikace"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Odstranit"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Odinstalovat aktualizaci"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Odinstalovat aplikaci"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Podrobnosti o aplikaci"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Vybrána 1 aplikace"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Vybrán 1 widget"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Vybrána 1 složka"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Vybrán 1 zástupce"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalace zástupce"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Umožňuje aplikaci přidat zástupce bez zásahu uživatele."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"odinstalovat zástupce"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Umožňuje aplikaci odstranit zástupce bez zásahu uživatele."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čtení nastavení a odkazů plochy"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Umožňuje aplikaci číst nastavení a odkazy na ploše."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"zápis nastavení a odkazů plochy"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problém s načtením widgetu"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavení"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikace a nelze ji odinstalovat."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Složka bez názvu"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Plocha %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Stránka aplikací %1$d z %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Stránka widgetů %1$d z %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Vítejte"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Udělejte si pohodlí."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Vytvořte několik obrazovek pro aplikace a složky"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Zkopírování ikon aplikací"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Chcete importovat ikony a složky ze svých starých ploch?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ZKOPÍROVAT IKONY"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ZAČÍT S VÝCHOZÍM ROZVRŽENÍM"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizace prostoru"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Chcete-li spravovat tapetu, widgety a nastavení, dotkněte se pozadí a přidržte je."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Tapety, widgety a nastavení"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Pozadí můžete přizpůsobit klepnutím a podržením"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ROZUMÍM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Toto je složka"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Chcete-li vytvořit složku, přetáhněte aplikaci na jinou aplikaci."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Složka otevřena, rozměry <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Dotykem složku zavřete"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Dotykem uložíte změnu názvu"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgety"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Nastavení"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Čekání"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Stahování"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalace"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Povolit otáčení"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznámé"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nebylo obnoveno"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstranit vše"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstranit"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Hledat"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Tato aplikace není nainstalována"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikace pro tuto ikonu není nainstalována. Můžete ikonu odstranit nebo zkusit aplikaci vyhledat a nainstalovat ručně."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Přidat na plochu"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Přesunout položku sem"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Položka byla přidána na plochu"</string>
+    <string name="item_removed" msgid="851119963877842327">"Položka byla odstraněna"</string>
+    <string name="action_move" msgid="4339390619886385032">"Přesunout položku"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Přesunout na řádek <xliff:g id="NUMBER_0">%1$s</xliff:g> do sloupce <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Přesunout na pozici <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Přesunout do oblíbených položek na pozici <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Položka byla přesunuta"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Přidat do složky: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Přidat do složky s aplikací <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Položka byla přidána do složky"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Vytvořit složku s položkou <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Složka byla vytvořena"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Přesunout na plochu"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Přesunout obrazovku doleva"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Přesunout obrazovku doprava"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Obrazovka byla přesunuta"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Změnit velikost"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Zvýšit šířku"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Zvýšit výšku"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Snížit šířku"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Snížit výšku"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Velikost widgetu upravena: šířka <xliff:g id="NUMBER_0">%1$s</xliff:g>, výška <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 5fa6aa6..eeab92e 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Startskærm"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Kerneapps i Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Arbejde"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Appen er ikke installeret."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Appen er ikke tilgængelig"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloadet app er deaktiveret i sikker tilstand"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets er deaktiveret i Beskyttet tilstand"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Vis Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tryk på en widget, og hold den nede for at vælge."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Elementet kunne ikke trækkes til startskærmen."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Vælg den widget, du vil oprette"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mappenavn"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Omdøb mappe"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Annuller"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Føj til startskærm"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Genveje"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Der er ikke mere plads på dine startskærme."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søg i Apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Indlæser apps…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Der blev ikke fundet nogen apps, som matcher \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Der er ikke mere plads på denne startskærm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Der er ikke mere plads i bakken Foretrukne"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Denne widget er for stor til bakken Foretrukne"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Genvejen \"<xliff:g id="NAME">%s</xliff:g>\" blev oprettet."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Genvejen \"<xliff:g id="NAME">%s</xliff:g>\" blev fjernet."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Genvejen \"<xliff:g id="NAME">%s</xliff:g>\" findes allerede."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Vælg genvej"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Vælg app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startskærm"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Fjern"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Afinstaller"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Fjern"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Afinstaller"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Oplysninger om appen"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Fjern"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Afinstaller opdatering"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Afinstaller appen"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Oplysninger om appen"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app er valgt"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget er valgt"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 mappe er valgt"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 genvej er valgt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere genveje"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillader, at en app tilføjer genveje uden brugerens indgriben."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"afinstaller genveje"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Tillader, at appen fjerner genveje uden brugerens indgriben."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"læs indstillinger og genveje for startskærmen"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Tillader, at appen læser indstillingerne og genvejene på startskærmen."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"skrive indstillinger og genveje for startskærmen"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Der er problemer med indlæsning af widgetten"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurer"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp, som ikke kan afinstalleres."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unavngiven mappe"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Startskærm %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps-side %1$d ud af %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgets-side %1$d ud af %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Velkommen"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Føl dig hjemme."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Opret flere skærme til apps og mapper"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiér dine appikoner"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Vil du importere ikoner og mapper fra gamle startskærme?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIÉR IKONER"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START PÅ EN FRISK"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser din arbejdsplads"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Tryk på en baggrund, og hold fingeren nede for at administrere baggrunde, widgets og indstillinger."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Baggrunde, widgets og indstillinger"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tryk på baggrunden, og hold fingeren nede for at tilpasse den"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK, FORSTÅET"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Her kan du se en mappe"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Du kan oprette en mappe magen til denne ved at trykke på en app og holde fingeren nede, mens du flytter appen til en anden mappe."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen er åben, <xliff:g id="WIDTH">%1$d</xliff:g> gange <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Tryk for at lukke mappen"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Tryk for at gemme det nye navn"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Baggrunde"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Indstillinger"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Afventer"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Downloader"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installerer"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Tillad rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ukendt"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ikke gendannet"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Slet alle"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Søg"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Denne app er ikke installeret"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen, der hører til dette ikon, er ikke installeret. Du kan fjerne den eller prøve at søge efter appen og installere den manuelt."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Føj til startskærm"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Flyt elementet hertil"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er føjet til startskærmen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elementet er fjernet"</string>
+    <string name="action_move" msgid="4339390619886385032">"Flyt element"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Flyt til række <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Flyt til position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Flyt til foretrukne position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elementet blev flyttet"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Føj til mappen: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Føj til mappen, der indeholder <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elementet blev føjet til mappen"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Opret mappe med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mappen blev oprettet"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Flyt til startskærmen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Flyt skærmen til venstre"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Flyt skærmen til højre"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skærmen er flyttet"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Tilpas størrelse"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Øg bredden"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Øg højden"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reducer bredden"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reducer højden"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Størrelsen for widgetten er ændret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og højde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 059983e..ac6f76b 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Startseite"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Arbeit"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App ist nicht installiert."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App nicht verfügbar"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Heruntergeladene App im abgesicherten Modus deaktiviert"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets im abgesicherten Modus deaktiviert"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Speicher anzeigen"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Zum Hinzufügen Widget berühren und halten"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Element wurde nicht auf diesem Startbildschirm abgelegt."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Widget zum Erstellen auswählen"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Ordnername"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Ordner umbenennen"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Abbrechen"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Zum Startbildschirm hinzufügen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Verknüpfungen"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Auf Ihren Startbildschirmen ist kein Platz mehr vorhanden."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"In Apps suchen"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps werden geladen..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ablage \"Favoriten\" ist voll."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Dieses Widget ist zu groß für die Ablage \"Favoriten\"."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Verknüpfung \"<xliff:g id="NAME">%s</xliff:g>\" wurde erstellt."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Verknüpfung \"<xliff:g id="NAME">%s</xliff:g>\" wurde entfernt."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Verknüpfung \"<xliff:g id="NAME">%s</xliff:g>\" ist bereits vorhanden."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Verknüpfung auswählen"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"App auswählen"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startseite"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Entfernen"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Deinstallieren"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Entfernen"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Deinstallieren"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App-Info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Entfernen"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Update deinstallieren"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"App deinstallieren"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"App-Details"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 App ausgewählt"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 Widget ausgewählt"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 Ordner ausgewählt"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 Verknüpfung ausgewählt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Verknüpfungen installieren"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ermöglicht einer App das Hinzufügen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"Verknüpfungen deinstallieren"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ermöglicht einer App das Entfernen von Verknüpfungen ohne Eingreifen des Nutzers"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Einstellungen und Verknüpfungen auf dem Startbildschirm lesen"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Ermöglicht der App, die Einstellungen und Verknüpfungen auf dem Startbildschirm zu lesen"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Einstellungen und Verknüpfungen für den Startbildschirm schreiben"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem beim Laden des Widgets"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Einrichten"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dies ist eine Systemanwendung, die nicht deinstalliert werden kann."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unbenannter Ordner"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Startbildschirm %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps-Seite %1$d von %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgets-Seite %1$d von %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Hallo!"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Gerät personalisieren"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Mehr Bildschirme für Apps und Ordner erstellen"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"App-Symbole kopieren"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Symbole und Ordner alter Startbildschirme importieren?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"Symbole kopieren"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"Standardübersicht verwenden"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Arbeitsbereich organisieren"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Hintergrund berühren und halten, um Hintergrund, Widgets und Einstellungen zu verwalten"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Hintergründe, Widgets &amp; Einstellungen"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Berühren und halten Sie den Hintergrund, um ihn anzupassen."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Hier ist ein Ordner"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Um einen Ordner zu erstellen, berühren und halten Sie eine App und verschieben Sie sie auf eine andere."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Ordner geöffnet, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Ordner durch Berühren schließen"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Umbenennung durch Berühren speichern"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Hintergründe"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Einstellungen"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Warten"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Download läuft"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installation"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Drehung zulassen"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unbekannt"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nicht wiederhergestellt"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Alle entfernen"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Entfernen"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Suchen"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Diese App ist nicht installiert"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Die App für dieses Symbol ist nicht installiert. Sie können das Symbol entfernen oder nach der App suchen und sie manuell installieren."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Zum Startbildschirm hinzufügen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Element hierhin verschieben"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Element zum Startbildschirm hinzugefügt"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element entfernt"</string>
+    <string name="action_move" msgid="4339390619886385032">"Element verschieben"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"In Zeile <xliff:g id="NUMBER_0">%1$s</xliff:g>, Spalte <xliff:g id="NUMBER_1">%2$s</xliff:g> verschoben"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Auf Position <xliff:g id="NUMBER">%1$s</xliff:g> verschoben"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Auf Favoritenposition <xliff:g id="NUMBER">%1$s</xliff:g> verschoben"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element verschoben"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Zum Ordner \"<xliff:g id="NAME">%1$s</xliff:g>\" hinzufügen"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Zum Ordner hinzufügen, in dem sich <xliff:g id="NAME">%1$s</xliff:g> befindet"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element zum Ordner hinzugefügt"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Anhand von <xliff:g id="NAME">%1$s</xliff:g> Ordner erstellen"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Ordner erstellt"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Auf Startbildschirm verschieben"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Bildschirm nach links"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Bildschirm nach rechts"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Bildschirm verschoben"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Größe anpassen"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Breite vergrößern"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Höhe vergrößern"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Breite verringern"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Höhe verringern"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Größe des Widgets zu Breite <xliff:g id="NUMBER_0">%1$s</xliff:g> und Höhe <xliff:g id="NUMBER_1">%2$s</xliff:g> geändert"</string>
 </resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 7e5989d..a60458a 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Αρχική οθόνη"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Βασικές εφαρμογές Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Εργασία"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Η εφαρμογή δεν έχει εγκατασταθεί."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Η λήψη εφαρμογών απενεργοποήθηκε στην Ασφαλή λειτουργία"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Τα γραφικά στοιχεία απενεργοποιήθηκαν στην ασφαλή λειτουργία"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Γραφικά στοιχεία"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Γραφικά στοιχεία"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Εμφάνιση Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Αγγίξτε παρατεταμένα για να πάρετε ένα γραφ.στοιχ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Αδυναμία τοποθέτησης στοιχείου στην Αρχική οθόνη."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Επιλ. γραφ. στοιχείο για δημιουργία"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Όνομα φακέλου"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Μετονομασία φακέλου"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Ακύρωση"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Προσθήκη στην αρχική οθόνη"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Εφαρμογές"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Συντομεύσεις"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Γραφικά στοιχεία"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Δεν υπάρχει άλλος χώρος στις Αρχικές οθόνες σας."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Αναζήτηση εφαρμογών"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Φόρτωση εφαρμογών…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Δεν βρέθηκαν εφαρμογές για το ερώτημα \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Αυτό το γραφικό στοιχείο είναι πολύ μεγάλο για την περιοχή Αγαπημένα."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Δημιουργήθηκε η συντόμευση \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Η συντόμευση \"<xliff:g id="NAME">%s</xliff:g>\" καταργήθηκε."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Η συντόμευση \"<xliff:g id="NAME">%s</xliff:g>\" υπάρχει ήδη."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Επιλογή συντόμευσης"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Επιλογή εφαρμογής"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Εφαρμογές"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Αρχική οθόνη"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Κατάργηση"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Κατάργηση εγκατάστασης"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Κατάργηση"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Κατάργηση εγκατάστασης"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Πληροφορίες εφαρμογής"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Εφαρμογές"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Κατάργηση"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Κατάργηση εγκατάστασης ενημέρωσης"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Κατάργηση εγκατάστασης εφαρμογής"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Λεπτομέρειες εφαρμογής"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Επιλέχτηκε 1 εφαρμογή"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Επιλέχτηκε 1 γραφικό στοιχείο"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Επιλέχτηκε 1 φάκελος"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Επιλέχτηκε 1 συντόμευση"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"εγκατάσταση συντομεύσεων"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Επιτρέπει σε μια εφαρμογή την προσθήκη συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"κατάργηση εγκατάστασης συντομεύσεων"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Επιτρέπει στην εφαρμογή την κατάργηση συντομεύσεων χωρίς την παρέμβαση του χρήστη."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ανάγνωση ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων και των συντομεύσεων στην Αρχική οθόνη."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"εγγραφή ρυθμίσεων και συντομεύσεων αρχικής οθόνης"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Παρουσιάστηκε πρόβλημα στη φόρτωση του γραφικού στοιχείου"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Ρύθμιση"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Αυτή είναι μια εφαρμογή συστήματος και δεν είναι δυνατή η κατάργηση της εγκατάστασής της."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Φάκελος χωρίς όνομα"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Αρχική οθόνη %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Σελίδα εφαρμογών %1$d από %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Σελίδα γραφικών στοιχείων %1$d από %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Καλώς ορίσατε"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Νιώστε σαν στο σπίτι σας."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Δημιουργία περισσότερων οθονών για εφαρμογές και φακέλους"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Αντιγραφή εικονιδίων εφαρμογών"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Εισαγωγή εικονιδίων και φακέλων από παλιές αρχικές οθόνες;"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ΑΝΤΙΓΡΑΦΗ ΕΙΚΟΝΙΔΙΩΝ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ΝΕΑ ΕΝΑΡΞΗ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Οργανώστε το χώρο σας"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Αγγίξτε παρατεταμένα το φόντο για να διαχειριστείτε την ταπετσαρία, τα γραφικά στοιχεία και τις ρυθμίσεις."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ταπετσαρίες, γραφικά στοιχεία και ρυθμίσεις"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Αγγίξτε παρατεταμένα το παρασκήνιο για προσαρμογή"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ΕΓΙΝΕ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ορίστε ένας φάκελος"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Για να δημιουργήσετε έναν φάκελο σαν κι αυτόν, πατήστε παρατεταμένα μια εφαρμογή και στη συνέχεια, μετακινήστε τη πάνω σε μια άλλη."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Άνοιγμα φακέλου, <xliff:g id="WIDTH">%1$d</xliff:g> επί <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Αγγίξτε για να κλείσετε τον φάκελο"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Αγγίξτε για να αποθηκεύσετε το νέο όνομα"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Γραφικά στοιχεία"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ταπετσαρίες"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ρυθμίσεις"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Αναμονή"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Λήψη "</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Εγκατάσταση"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Να επιτρέπεται η περιστροφή"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Άγνωστο"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Δεν ανακτήθηκε"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Κατάργηση όλων"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Κατάργηση"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Αναζήτηση"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Αυτή η εφαρμογή δεν είναι εγκατεστημένη"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Η εφαρμογή γι\' αυτό το εικονίδιο δεν είναι εγκατεστημένη. Μπορείτε να το καταργήσετε ή να αναζητήσετε την εφαρμογή και να την εγκαταστήσετε με μη αυτόματο τρόπο."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Προσθήκη στην αρχική οθόνη"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Μετακίνηση στοιχείου εδώ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Το στοιχείο προστέθηκε στην αρχική οθόνη"</string>
+    <string name="item_removed" msgid="851119963877842327">"Το στοιχείο καταργήθηκε"</string>
+    <string name="action_move" msgid="4339390619886385032">"Μετακίνηση στοιχείου"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Μετακίνηση στη σειρά <xliff:g id="NUMBER_0">%1$s</xliff:g>, στήλη <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Μετακίνηση στη θέση <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Μετακίνηση στη θέση <xliff:g id="NUMBER">%1$s</xliff:g> στα αγαπημένα"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Το στοιχείο καταργήθηκε"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Προσθήκη στο φάκελο: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Προσθήκη στο φάκελο με την εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Το στοιχείο προστέθηκε στο φάκελο"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Δημιουργία φακέλου με: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Δημιουργήθηκε φάκελος"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Μετακίνηση Αρχικής οθόνης"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Μετακίνηση οθόνης αριστερά"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Μετακίνηση οθόνης δεξιά"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Η οθόνη μετακινήθηκε"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Προσαρμογή μεγέθους"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Αύξηση του πλάτους"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Αύξηση του ύψους"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"μείωση του πλάτους"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Μείωση του ύψους"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Έγινε προσαρμογή του μεγέθους του γραφικού στοιχείου σε <xliff:g id="NUMBER_0">%1$s</xliff:g> πλάτος και <xliff:g id="NUMBER_1">%2$s</xliff:g> ύψος"</string>
 </resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 0d004fe..09963e4 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloaded app disabled in Safe mode"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Show Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Couldn\'t drop item on this Home screen."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Choose widget to create"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Folder name"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Rename folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancel"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Add to Home screen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Shortcuts"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No more room on your Home screens."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"This widget is too large for the Favourites tray"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" created."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" was removed."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" already exists."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Choose shortcut"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Choose app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remove"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Uninstall"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Remove"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Uninstall"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Remove"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Uninstall update"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Uninstall app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"App details"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app selected"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selected"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder selected"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 shortcut selected"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"uninstall shortcuts"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Allows the app to remove shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Allows the app to read the settings and shortcuts in Home."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"write Home settings and shortcuts"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem loading widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Home screen %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps page %1$d of %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgets page %1$d of %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Welcome"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Make yourself at home."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Create more screens for apps and folders"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copy your app icons"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organise your space"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Touch &amp; hold background to manage wallpaper, widgets and settings."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Touch &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Here\'s a folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"To create one like this, touch &amp; hold an app, then move it over another."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Touch to close folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Touch to save rename"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Settings"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Waiting"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Downloading"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installing"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Allow rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Not restored"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Remove All"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"This app is not installed"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+    <string name="action_move" msgid="4339390619886385032">"Move item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Move to favourites position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item moved"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Add to folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Add to folder with <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item added to folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Decrease width"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 0d004fe..09963e4 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloaded app disabled in Safe mode"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Show Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Couldn\'t drop item on this Home screen."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Choose widget to create"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Folder name"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Rename folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancel"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Add to Home screen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Shortcuts"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No more room on your Home screens."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"This widget is too large for the Favourites tray"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" created."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" was removed."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" already exists."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Choose shortcut"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Choose app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remove"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Uninstall"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Remove"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Uninstall"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Remove"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Uninstall update"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Uninstall app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"App details"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app selected"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selected"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder selected"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 shortcut selected"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"uninstall shortcuts"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Allows the app to remove shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Allows the app to read the settings and shortcuts in Home."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"write Home settings and shortcuts"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem loading widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Home screen %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps page %1$d of %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgets page %1$d of %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Welcome"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Make yourself at home."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Create more screens for apps and folders"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copy your app icons"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organise your space"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Touch &amp; hold background to manage wallpaper, widgets and settings."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Touch &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Here\'s a folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"To create one like this, touch &amp; hold an app, then move it over another."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Touch to close folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Touch to save rename"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Settings"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Waiting"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Downloading"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installing"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Allow rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Not restored"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Remove All"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"This app is not installed"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+    <string name="action_move" msgid="4339390619886385032">"Move item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Move to favourites position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item moved"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Add to folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Add to folder with <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item added to folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Decrease width"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 0d004fe..09963e4 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App isn\'t installed."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App isn\'t available"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Downloaded app disabled in Safe mode"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Show Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Touch &amp; hold to pick up a widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Couldn\'t drop item on this Home screen."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Choose widget to create"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Folder name"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Rename folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancel"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Add to Home screen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Shortcuts"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No more room on your Home screens."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Search Apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Loading Apps…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No Apps found matching \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"No more room on this Home screen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"No more room in the Favourites tray"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"This widget is too large for the Favourites tray"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" created."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" was removed."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Shortcut \"<xliff:g id="NAME">%s</xliff:g>\" already exists."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Choose shortcut"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Choose app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remove"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Uninstall"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Remove"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Uninstall"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Remove"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Uninstall update"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Uninstall app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"App details"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app selected"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selected"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder selected"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 shortcut selected"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"install shortcuts"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Allows an app to add shortcuts without user intervention."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"uninstall shortcuts"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Allows the app to remove shortcuts without user intervention."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"read Home settings and shortcuts"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Allows the app to read the settings and shortcuts in Home."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"write Home settings and shortcuts"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem loading widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"This is a system app and can\'t be uninstalled."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Unnamed Folder"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Home screen %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps page %1$d of %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgets page %1$d of %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Welcome"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Make yourself at home."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Create more screens for apps and folders"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copy your app icons"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Import icons and folders from your old Home screens?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START AFRESH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organise your space"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Touch &amp; hold background to manage wallpaper, widgets and settings."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpapers, widgets, &amp; settings"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Touch &amp; hold background to customise"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"GOT IT"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Here\'s a folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"To create one like this, touch &amp; hold an app, then move it over another."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder opened, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Touch to close folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Touch to save rename"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpapers"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Settings"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Waiting"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Downloading"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installing"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Allow rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Unknown"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Not restored"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Remove All"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remove"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Search"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"This app is not installed"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"The app for this icon isn\'t installed. You can remove it, or search for the app and install it manually."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Add to Home screen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item added to home screen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item removed"</string>
+    <string name="action_move" msgid="4339390619886385032">"Move item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Move to row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Move to position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Move to favourites position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item moved"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Add to folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Add to folder with <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item added to folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Create folder with: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder created"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Move to Home screen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Move screen to left"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Move screen to right"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Screen moved"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Re-size"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Increase width"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Increase height"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Decrease width"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 4408080..6366742 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Pantalla principal"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplicaciones básicas de Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Trabajo"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"No se instaló la aplicación."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"La aplicación no está disponible."</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo seguro"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo seguro"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén presionado el widget que desees elegir."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Error al soltar elemento en la pantalla principal"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Elegir los widgets para crear"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nombre de carpeta"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Cambiar nombre de carpeta"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Aceptar"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Agregar a la pantalla principal"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicaciones"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Accesos directos"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No hay más espacio en tus pantallas principales."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Buscar aplicaciones"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No hay aplicaciones que coincidan con <xliff:g id="QUERY">%1$s</xliff:g>."</string>
     <string name="out_of_space" msgid="4691004494942118364">"No hay más espacio en esta pantalla principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está llena."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Este widget es demasiado grande para la bandeja de favoritos."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Se creó el acceso directo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Se eliminó el acceso directo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"El acceso directo \"<xliff:g id="NAME">%s</xliff:g>\" ya existe."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Elegir acceso directo"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Elegir aplicación"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicaciones"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Pantalla principal"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eliminar"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Información de la aplicación"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicaciones"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar actualización"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar aplicación"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalles de la aplicación"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Se seleccionó 1 aplicación."</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Se seleccionó 1 widget."</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Se seleccionó 1 carpeta."</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Se seleccionó 1 acceso directo."</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación agregue accesos directos sin que el usuario intervenga."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar accesos directos"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite que la aplicación elimine accesos directos sin que el usuario intervenga."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"leer configuración y accesos directos de la pantalla principal"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite que la aplicación lea la configuración y los accesos directos de la pantalla principal."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"escribir configuración y accesos directos de la pantalla principal"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema al cargar el widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta es una aplicación del sistema y no se puede desinstalar."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Lanzacohetes"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Pantalla principal %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de aplicaciones %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Página de widgets %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bienvenido"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Siéntete como en casa."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crea más pantallas para aplicaciones y carpetas."</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar íconos de aplicaciones"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"¿Importar íconos y carpetas de pant. principales antiguas?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ÍCONOS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"EMPEZAR DE CERO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza tu espacio"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén presionado el fondo para administrar el fondo de pantalla, los widgets y la configuración."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fondos, widgets y configuración"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén presionado el fondo para personalizarlo"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDIDO"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Aquí tienes una carpeta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear una carpeta como esta, mantén presionada una aplicación y luego muévela sobre otra."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string>
     <string name="folder_opened" msgid="94695026776264709">"Carpeta abierta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toca para cerrar la carpeta."</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toca para guardar el nuevo nombre."</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Configuración"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Pendiente"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permitir la rotación"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"No restaurado"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todo"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación no está instalada"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación para este ícono no está instalada. Puedes eliminar el ícono o buscar la aplicación e instarla manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Agregar a la pantalla principal"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Se agregó el elemento a la pantalla principal."</string>
+    <string name="item_removed" msgid="851119963877842327">"Se eliminó el elemento."</string>
+    <string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover a fila <xliff:g id="NUMBER_0">%1$s</xliff:g>, columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mover a la posición número <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover a la posición de favoritos número <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elemento movido"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Agregar a carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Agregar a la carpeta que contiene <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elemento agregado a la carpeta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Crear carpeta con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover a la pantalla principal"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla a la izquierda"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla a la derecha"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Se movió la pantalla."</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ajustar tamaño"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumentar el ancho"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumentar la altura"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reducir el ancho"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reducir la altura"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Se cambió la dimensión del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto."</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 898d0ea..34331fc 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplicaciones básicas de Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Trabajo"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"La aplicación no está instalada."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"La aplicación no está disponible"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicación descargada inhabilitada en modo seguro"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo seguro"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén pulsado el widget que quieras seleccionar."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Error al arrastrar elemento a pantalla de inicio."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Selecciona widget a añadir"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nombre de carpeta"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Cambiar nombre de carpeta"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Aceptar"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Añadir a la pantalla de inicio"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicaciones"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Accesos directos"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"No queda espacio en las pantallas de inicio."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Busca aplicaciones"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicaciones…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"No se han encontrado aplicaciones que contengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"No queda espacio en la pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"La bandeja de favoritos está completa"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Este widget es demasiado grande para la bandeja de favoritos"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Se ha creado el acceso directo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Se ha eliminado el acceso directo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"El acceso directo \"<xliff:g id="NAME">%s</xliff:g>\" ya existe."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Selecciona un acceso directo"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Selecciona una aplicación"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicaciones"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eliminar"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Información de la aplicación"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicaciones"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar actualización"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar aplicación"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Información de la aplicación"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicación seleccionada"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget seleccionado"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 carpeta seleccionada"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 acceso directo seleccionado"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar accesos directos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar accesos directos"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite que la aplicación elimine accesos directos sin intervención del usuario."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"leer información de accesos directos y de ajustes de la pantalla de inicio"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite que la aplicación consulte los ajustes y los accesos directos de la pantalla de inicio."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"escribir información de accesos directos y de ajustes de la pantalla de inicio"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema al cargar el widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación es del sistema y no se puede desinstalar."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Carpeta sin nombre"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Pantalla de inicio %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de aplicaciones %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Página de widgets %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Te damos la bienvenida"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Personaliza tu pantalla de inicio."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crea más pantallas para aplicaciones y carpetas"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar iconos de aplicaciones"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"¿Importar iconos y carpetas de pantallas de inicio antiguas?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ICONOS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"AJUSTES PREDETERMINADOS"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza tu espacio"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén pulsado el fondo para gestionar el fondo de pantalla, los widgets y los ajustes."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fondos de pantalla, widgets y ajustes"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén pulsado el fondo para personalizarlo"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDIDO"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Esto es una carpeta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear una carpeta como esta, mantén pulsada una aplicación y muévela sobre otra."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string>
     <string name="folder_opened" msgid="94695026776264709">"Carpeta abierta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toca para cerrar la carpeta"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toca para cambiar el nuevo nombre"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ajustes"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Esperando"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permitir rotación"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"No restaurado"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todo"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación no está instalada"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"La aplicación de este icono no está instalada. Puedes eliminar el icono o buscar la aplicación e instalarla manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Añadir a la pantalla de inicio"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento añadido a la pantalla de inicio"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elemento eliminado"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover a la fila <xliff:g id="NUMBER_0">%1$s</xliff:g>, columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mover a la posición número <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover a la posición número <xliff:g id="NUMBER">%1$s</xliff:g> de favoritos"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elemento movido"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Añadir a carpeta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Añadir a la carpeta con <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elemento añadido a carpeta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Crear carpeta con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Carpeta creada"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover a la pantalla de inicio"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla a la izquierda"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla a la derecha"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Pantalla movida"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Modificar tamaño"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reducir ancho"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Se ha modificado el tamaño del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto"</string>
 </resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index 76b20ab..c4ba823 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Avaekraan"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Androidi tuumrakendused"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Töö"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Rakendus pole installitud."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Rakendus ei ole saadaval"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Allalaetud rakendus on turvarežiimis keelatud"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Turvarežiimis on vidinad keelatud"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Vidinad"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Vidinad"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mälu kuvamine"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidina valimiseks vajutage ja hoidke seda all."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Üksust ei saanud sellele avaekraanile tuua."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Valige loomiseks vidin"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Kausta nimi"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Kausta ümbernimetamine"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Tühista"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Avaekraanile lisamine"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Rakendused"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Otseteed"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Vidinad"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Teie avaekraanidel ei ole enam ruumi."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Otsige rakendustest"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Rakenduste laadimine ..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Päringule „<xliff:g id="QUERY">%1$s</xliff:g>” ei vastanud ükski rakendus"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Sellel avaekraanil pole enam ruumi."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Salves Lemmikud pole rohkem ruumi"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"See vidin on salve Lemmikud jaoks liiga suur"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” on loodud."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” on eemaldatud."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” on juba olemas."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Otsetee valimine"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Rakenduse valimine"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Rakendused"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Avaekraan"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eemalda"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalli"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eemalda"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalli"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Rakenduse teave"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Rakendused"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eemalda"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalli värskendus"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Rakenduse desinstallimine"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Rakenduse üksikasjad"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Valitud on 1 rakendus"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Valitud on 1 vidin"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Valitud on 1 kaust"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Valitud on 1 otsetee"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installi otseteed"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalli otseteed"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Võimaldab rakendusel eemaldada otseteid kasutaja sekkumiseta."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"loe avaekraani seadeid ja otseteid"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Võimaldab rakendusel lugeda avaekraanil seadeid ja otseteid."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"kirjuta avaekraani seaded ja otseteed"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Probleem vidina laadimisel"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Seadistamine"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"See on süsteemirakendus ja seda ei saa desinstallida."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetu kaust"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Avaekraan %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Rakenduste leht %1$d/%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Vidinate leht %1$d/%2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Tere tulemast"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Tundke end nagu kodus."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Looge rakenduste ja kaustade jaoks rohkem ekraanikuvasid"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopeerige rakenduste ikoonid"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Kas importida vanade avaekraanide ikoonid ja kaustad?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPEERI IKOONID"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ALUSTA ALGUSEST"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Korraldage oma ruumi"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Taustapildi, vidinate ja seadete haldamiseks puudutage tausta ning hoidke seda all."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Taustapildid, vidinad ja seaded"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Kohandamiseks puudutage ja hoidke tausta all"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SELGE"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Siin on kaust"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Sarnase loomiseks vajutage ja hoidke rakendust all, seejärel viige see teise peale."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Kaust on avatud, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Puudutage kausta sulgemiseks"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Puudutage uue nime salvestamiseks"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Vidinad"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustapildid"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Seaded"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Ootamine"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Allalaadimine"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installimine"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Luba pööramine"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Teadmata"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ei taastatud"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Eemalda kõik"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eemalda"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Otsing"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"See rakendus ei ole installitud"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Selle ikooni rakendust pole installitud. Saate selle eemaldada või rakendust otsida ja käsitsi installida."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Lisa avaekraanile"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Teisalda üksus siia"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Üksus lisati avaekraanile"</string>
+    <string name="item_removed" msgid="851119963877842327">"Üksus eemaldati"</string>
+    <string name="action_move" msgid="4339390619886385032">"Teisalda üksus"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Teisaldamine <xliff:g id="NUMBER_0">%1$s</xliff:g>. rea <xliff:g id="NUMBER_1">%2$s</xliff:g>. veergu"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Teisaldamine <xliff:g id="NUMBER">%1$s</xliff:g>. positsioonile"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Teisaldamine lemmikute <xliff:g id="NUMBER">%1$s</xliff:g>. positsioonile"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Üksus teisaldati"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Lisamine kausta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Lisamine kausta nimega <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Üksus lisati kausta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Kausta loomine nimega <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Kaust on loodud"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Teisalda avaekraanile"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Teisalda ekraan vasakule"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Teisalda ekraan paremale"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekraan teisaldati"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Muuda suurust"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Suurenda laiust"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Suurenda kõrgust"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Vähenda laiust"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Vähenda kõrgust"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Vidina suurust muudeti. Laius: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Kõrgus: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 3b0deb8..afed3b5 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -20,95 +20,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="8424725141379931883">"Käivitaja"</string>
-    <string name="home" msgid="5921706419368316758">"Kodu"</string>
-    <string name="uid_name" msgid="3371120195364560632">"Androidi tuumrakendused"</string>
     <string name="folder_name" msgid="8551881338202938211"></string>
-    <string name="chooser_wallpaper" msgid="6063168087625352235">"Taustapildi valimiskoht:"</string>
     <string name="wallpaper_instructions" msgid="4215640646180727542">"Määra taustapilt"</string>
     <string name="pick_wallpaper" msgid="5630222540525626723">"Taustapildid"</string>
     <string name="activity_not_found" msgid="217823393239365967">"Rakendus pole installitud."</string>
-    <string name="widgets_tab_label" msgid="9145860100000983599">"Vidinad"</string>
     <string name="long_press_widget_to_add" msgid="7395697462851217506">"Vidina valimiseks puudutage seda pikalt."</string>
-    <string name="market" msgid="2652226429823445833">"Pood"</string>
     <string name="widget_dims_format" msgid="1386418557719032947">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="2285187188524172774">"Üksust ei saa sellele avaekraanile tuua."</string>
-    <string name="external_drop_widget_pick_title" msgid="7040647073452295370">"Valige loomiseks vidin"</string>
-    <string name="rename_folder_label" msgid="5646236631298452787">"Kausta nimi"</string>
-    <string name="rename_folder_title" msgid="4544573104191526550">"Nimeta kaust ümber"</string>
-    <string name="rename_action" msgid="6016003384693240896">"OK"</string>
-    <string name="cancel_action" msgid="3811860427489435048">"Tühista"</string>
-    <string name="menu_item_add_item" msgid="6233177331075781114">"Lisa avamenüüsse"</string>
-    <string name="group_applications" msgid="2103752818818161976">"Rakendused"</string>
-    <string name="group_shortcuts" msgid="9133529424900391877">"Otseteed"</string>
-    <string name="group_widgets" msgid="6704978494073105844">"Vidinad"</string>
-    <string name="completely_out_of_space" msgid="1759078539443491182">"Teie avakuvadel ei ole enam ruumi."</string>
     <string name="out_of_space" msgid="8365249326091984698">"Sellel avalehel pole enam ruumi."</string>
     <string name="hotseat_out_of_space" msgid="6304886797358479361">"Kohandataval dokialal pole rohkem ruumi."</string>
-    <string name="invalid_hotseat_item" msgid="6545340627805449250">"See vidin on tööpunkti jaoks liiga suur."</string>
-    <string name="shortcut_installed" msgid="7071557296331322355">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” loodud."</string>
-    <string name="shortcut_uninstalled" msgid="2129499669449749995">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” eemaldatud."</string>
-    <string name="shortcut_duplicate" msgid="4757756326465060694">"Otsetee „<xliff:g id="NAME">%s</xliff:g>” on juba olemas."</string>
-    <string name="title_select_shortcut" msgid="1873670208166882222">"Otsetee valimine"</string>
-    <string name="title_select_application" msgid="1793455815754848652">"Rakenduse valimine"</string>
     <string name="all_apps_button_label" msgid="2578400570124163469">"Rakendused"</string>
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Kodu"</string>
-    <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eemalda"</string>
-    <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalli"</string>
     <string name="delete_target_label" msgid="665300185123139530">"Eemalda"</string>
     <string name="delete_target_uninstall_label" msgid="748894921183769150">"Desinstalli"</string>
     <string name="info_target_label" msgid="4019495079517426980">"Rakenduse teave"</string>
-    <string name="accessibility_search_button" msgid="816822994629942611">"Otsing"</string>
-    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Häälotsing"</string>
-    <string name="accessibility_all_apps_button" msgid="8803738611398979849">"Rakendused"</string>
-    <string name="accessibility_delete_button" msgid="3628162007991023603">"Eemalda"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalli värskendus"</string>
-    <string name="menu_add" msgid="3065046628354640854">"Lisa"</string>
-    <string name="menu_manage_apps" msgid="2308685199463588895">"Rakenduste haldamine"</string>
-    <string name="menu_wallpaper" msgid="5837429080911269832">"Taustapilt"</string>
-    <string name="menu_search" msgid="4826514464423239041">"Otsing"</string>
-    <string name="menu_notifications" msgid="6424587053194766192">"Teadistused"</string>
-    <string name="menu_settings" msgid="3946232973327980394">"Süsteemiseaded"</string>
-    <string name="menu_help" msgid="4901160661634590633">"Abi"</string>
-    <string name="cab_menu_delete_app" msgid="4089398025537640349">"Rakenduse desinstallimine"</string>
-    <string name="cab_menu_app_info" msgid="914548323652698884">"Rakenduse üksikasjad"</string>
-    <string name="cab_app_selection_text" msgid="6378522164293415735">"Valitud on 1 rakendus"</string>
-    <string name="cab_widget_selection_text" msgid="962527270506951955">"1 vidin on valitud"</string>
-    <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 kaust on valitud"</string>
-    <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 otsetee on valitud"</string>
     <string name="permlab_install_shortcut" msgid="1201690825493376489">"otseteede installimine"</string>
     <string name="permdesc_install_shortcut" msgid="8634424803272077038">"Võimaldab rakendusel lisada otseteid kasutaja sekkumiseta."</string>
-    <string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"otseteede desinstallimine"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="274355570620220977">"Võimaldab rakendusel eemaldada otseteid kasutaja sekkumiseta."</string>
     <string name="permlab_read_settings" msgid="3452408290738106747">"avalehe seadete ja otseteede lugemine"</string>
     <string name="permdesc_read_settings" msgid="5788109303585403679">"Võimaldab rakendusel lugeda avalehe seadeid ja otseteid."</string>
     <string name="permlab_write_settings" msgid="1360567537236705628">"avalehe seadete ja otseteede kirjutamine"</string>
     <string name="permdesc_write_settings" msgid="8530105489115785531">"Võimaldab rakendusel muuta avalehel seadeid ja otseteid."</string>
     <string name="gadget_error_text" msgid="8359351016167075858">"Probleem vidina laadimisel"</string>
     <string name="uninstall_system_app_text" msgid="6429814133777046491">"See on süsteemirakendus ja seda ei saa desinstallida."</string>
-    <string name="dream_name" msgid="2847171357608437154">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="8633351560105748141">"Nimeta kaust"</string>
-    <string name="workspace_description_format" msgid="2968608205939373034">"Avakuva %1$d"</string>
     <string name="default_scroll_format" msgid="4057140866420001240">"Leht %1$d/%2$d"</string>
     <string name="workspace_scroll_format" msgid="1704767047951143301">"Avakuva %1$d/%2$d"</string>
-    <string name="apps_customize_apps_scroll_format" msgid="5494241912377704885">"Rakenduste leht %1$d/%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="5383009742241717437">"Vidinate leht %1$d/%2$d"</string>
-    <string name="workspace_cling_title" msgid="738396473989890567">"Tunne end nagu kodus"</string>
-    <string name="workspace_cling_move_item" msgid="791013895761065070">"Võite panna oma lemmikrakendused siia."</string>
-    <string name="workspace_cling_open_all_apps" msgid="2459977609848572588">"Kõikide oma rakenduste nägemiseks puudutage ringi."</string>
-    <string name="all_apps_cling_title" msgid="2559734712581447107">"Valige mõned rakendused"</string>
-    <string name="all_apps_cling_add_item" msgid="5665035103260318891">"Rakenduse lisamiseks avakuvale puudutage seda pikalt."</string>
-    <string name="folder_cling_title" msgid="4308949882377840953">"Korraldage oma rakendused kaustadesse"</string>
-    <string name="folder_cling_move_item" msgid="270598675060435169">"Rakenduse liigutamiseks pange sõrm rakendusele ja hoidke seda."</string>
-    <string name="folder_cling_create_folder" msgid="8352867485656129478">"Avakuval uue kausta tegemiseks virnastage üks rakendus teisele."</string>
-    <string name="cling_dismiss" msgid="2780907108735868381">"OK"</string>
     <string name="folder_opened" msgid="1262064100943801533">"Kaust on avatud, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1335478160661137579">"Puudutage kausta sulgemiseks"</string>
     <string name="folder_tap_to_rename" msgid="5201612989905472442">"Puudutage uue nime salvestamiseks"</string>
     <string name="folder_closed" msgid="3130534551370511932">"Kaust suletud"</string>
     <string name="folder_renamed" msgid="7951233572858053642">"Kausta uus nimi: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_name_format" msgid="3051680259794759037">"<xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="custom_workspace_cling_title_1" msgid="1433009175359948587"></string>
-    <string name="custom_workspace_cling_description_1" msgid="6875529190849858047"></string>
-    <string name="custom_workspace_cling_title_2" msgid="5516006164661020362"></string>
-    <string name="custom_workspace_cling_description_2" msgid="2758258454975288377"></string>
 </resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index e02479c..8bfca6c 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Abiarazlea3"</string>
-    <string name="home" msgid="7658288663002113681">"Hasiera"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android-en nukleoko aplikazioak"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Lana"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikazioa instalatu gabe dago."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Ez dago erabilgarri aplikazioa"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Deskargatutako aplikazioa modu seguruan desgaitu da"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgetak desgaitu egin dira modu seguruan"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetak"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgetak"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Erakutsi memoria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Eduki ukituta widgeta aukeratzeko."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Ezin izan da elementua hasierako pantailan jaregin."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Aukeratu sortu beharreko widgeta"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Karpetaren izena"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Aldatu karpetaren izena"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Ados"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Utzi"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Gehitu hasierako pantailan"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikazioak"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Lasterbideak"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgetak"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Hasierako pantailetan ez dago toki gehiago."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Bilatu aplikazioetan"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Aplikazioak kargatzen…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ez da aurkitu \"<xliff:g id="QUERY">%1$s</xliff:g>\" bilaketarekin bat datorren aplikaziorik"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Hasierako pantaila honetan ez dago toki gehiago."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Widgeta handiegia da Gogokoak erretiluan ezartzeko"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea sortu da."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea kendu da."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" lasterbidea lehendik dago."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Aukeratu lasterbidea"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Aukeratu aplikazioa"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikazioak"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Hasiera"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Kendu"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalatu"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Kendu"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalatu"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Aplikazioaren informazioa"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikazioak"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Kendu"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalatu eguneratzea"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalatu aplikazioa"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Aplikazioaren xehetasunak"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Aplikazio bat hautatu da"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Widget bat hautatu da"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Karpeta bat hautatu da"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Lasterbide bat hautatu da"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzea baimentzen die aplikazioei."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"Desinstalatu lasterbideak"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Erabiltzaileak ezer egin gabe lasterbideak kentzea baimentzen die aplikazioei."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Irakurri hasierako ezarpenak eta lasterbideak"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Hasierako pantailako ezarpenak eta lasterbideak irakurtzea baimentzen die aplikazioei."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Idatzi hasierako ezarpenak eta lasterbideak"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Arazo bat izan da widgeta kargatzean"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurazioa"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Sistema-aplikazioa da hau eta ezin da desinstalatu."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Izenik gabeko karpeta"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d hasierako pantaila"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d/%2$d aplikazio-orria"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d/%2$d widget-orria"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Ongi etorri"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Pertsonalizatu hasierako pantaila nahieran."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Sortu pantaila gehiago aplikazioak eta karpetak ezartzeko"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiatu aplikazioen ikonoak"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Ikonoak eta karpetak aurreko hasierako pantailatik inportatu?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIATU IKONOAK"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"HASI HUTSETIK"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Antolatu zure txokoa"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Eduki ukituta atzeko planoa horma-paperak, widgetak eta ezarpenak kudeatzeko."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Horma-paperak, widgetak eta ezarpenak"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Pertsonalizatzeko, eduki ukituta atzeko planoa"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ADOS"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Hortxe duzu karpeta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Horrelako bat sortzeko, eduki ukituta aplikazio bat eta eraman beste baten gainera."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Ados"</string>
     <string name="folder_opened" msgid="94695026776264709">"Karpeta ireki da: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Karpeta ixteko, uki ezazu"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Karpetaren izen berria gordetzeko, uki ezazu"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgetak"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Horma-paperak"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ezarpenak"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Zain"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Deskargatzen"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalatzen"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Baimendu biratzeko aukera"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ezezaguna"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ez da leheneratu"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Kendu guztiak"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Kendu"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Bilatu"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikazio hau ez dago instalatuta"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ikono honen aplikazioa ez dago instalatuta. Ikonoa ken dezakezu, edo aplikazioa bilatu eta eskuz instalatu."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Gehitu hasierako pantailan"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Ekarri elementua hona"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua hasierako pantailan"</string>
+    <string name="item_removed" msgid="851119963877842327">"Kendu da elementua"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mugitu elementua"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Eraman <xliff:g id="NUMBER_0">%1$s</xliff:g>. errenkadara, <xliff:g id="NUMBER_1">%2$s</xliff:g>. zutabera"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Eraman <xliff:g id="NUMBER">%1$s</xliff:g>. postura"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Eraman gogokoen <xliff:g id="NUMBER">%1$s</xliff:g>. postura"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elementua mugitu da"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Gehitu <xliff:g id="NAME">%1$s</xliff:g> karpetan"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Gehitu <xliff:g id="NAME">%1$s</xliff:g> duen karpetan"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elementua karpetan gehitu da"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Sortu karpeta <xliff:g id="NAME">%1$s</xliff:g> elementuarekin"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Karpeta sortu da"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Eraman hasierako pantailara"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Eraman pantaila ezkerrera"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Eraman pantaila eskuinera"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Mugitu da pantaila"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Aldatu tamaina"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Handitu zabalera"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Handitu altuera"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Txikitu zabalera"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Txikitu altuera"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Aldatu da widgetaren tamaina. Zabalera: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Altuera: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 924cccf..701d59d 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"صفحه اصلی"</string>
-    <string name="uid_name" msgid="7820867637514617527">"‏برنامه‌های Android Core"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"کاری"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"برنامه نصب نشده است."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"برنامه در دسترس نیست"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"برنامه دانلود شده در حالت ایمن غیرفعال شد"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ابزارک‌ها در حالت ایمن غیرفعال هستند"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ابزارک‌ها"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ابزارک‌ها"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"‏نمایش Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"برای انتخاب ابزارک لمس کنید و نگه دارید."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"این مورد را نمی‌توان در این صفحه اصلی رها کرد."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"انتخاب ابزارکی که باید ایجاد شود"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"نام پوشه"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"تغییر نام پوشه"</string>
-    <string name="rename_action" msgid="5559600076028658757">"تأیید"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"لغو"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"افزودن به صفحه اصلی"</string>
-    <string name="group_applications" msgid="3797214114206693605">"برنامه‌ها"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"میان‌برها"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ابزارک‌ها"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"فضای بیشتری در صفحات نمایش اصلی شما موجود نیست."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"جستجوی برنامه‌ها"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"در حال بارگیری برنامه‌ها..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"هیچ برنامه‌ای مطابق با «<xliff:g id="QUERY">%1$s</xliff:g>» پیدا نشد"</string>
     <string name="out_of_space" msgid="4691004494942118364">"فضای بیشتری در این صفحه اصلی موجود نیست."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"فضای بیشتری در سینی موارد دلخواه وجود ندارد"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"این ابزارک برای سینی موارد دلخواه بسیار بزرگ است"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"میان‌بر «<xliff:g id="NAME">%s</xliff:g>» ایجاد شد."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"میان‌بر «<xliff:g id="NAME">%s</xliff:g>» حذف شد."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"میان‌بر «<xliff:g id="NAME">%s</xliff:g>» در حال حاضر وجود دارد."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"انتخاب میان‌بر"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"انتخاب برنامه"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"برنامه‌ها"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"صفحه اصلی"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"حذف"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"حذف نصب"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"حذف"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"حذف نصب"</string>
     <string name="info_target_label" msgid="8053346143994679532">"اطلاعات برنامه"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"برنامه‌ها"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"حذف"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"حذف نصب به‌روزرسانی"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"حذف نصب برنامه"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"جزئیات برنامه"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"۱ برنامه انتخاب شد"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"۱ ابزارک انتخاب شد"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"۱ پوشه انتخاب شد"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"۱ میان‌بر انتخاب شد"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"نصب میان‌برها"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"به برنامه اجازه می‌دهد میان‌برها را بدون دخالت کاربر اضافه کند."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"حذف نصب میان‌برها"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"به برنامه اجازه می‌دهد میان‌برها را بدون دخالت کاربر حذف کند."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"خواندن تنظیمات و میان‌برهای صفحه اصلی"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"به برنامه اجازه می‌دهد تنظیمات و میان‌برها را در صفحه اصلی بخواند."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"نوشتن تنظیمات و میان‌برهای صفحه اصلی"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"مشکل در بارگیری ابزارک"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"تنظیم"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمی‌شود."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"پوشه بی‌نام"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"‏صفحه اصلی %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"‏صفحه برنامه‌ها %1$d از %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"‏صفحه ابزارک‌ها %1$d از %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"خوش آمدید"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"راحت باشید."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"صفحات بیشتری را برای برنامه‌ها و پوشه‌ها ایجاد کنید"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"کپی کردن نمادهای برنامه شما"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"نمادها و پوشه‌ها از صفحه‌های اصلی قدیمی شما وارد شوند؟"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"کپی نمادها"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"شروع تازه"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"فضای خود را سازماندهی کنید"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"برای مدیریت کاغذدیواری، ابزارک‌ها و تنظیمات، پس‌زمینه را لمس کرده و نگه‌دارید."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"کاغذدیواری‌ها، ابزارک‌ها و تنظیمات"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"برای سفارشی کردن، پس‌زمینه را لمس کنید و نگه‌دارید"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"متوجه شدم"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"اینجا یک پوشه است"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"برای ایجاد پوشه‌ای مثل این، یک برنامه را لمس کرده و نگه‌دارید، سپس آن را روی برنامه دیگر بیاندازید."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"تأیید"</string>
     <string name="folder_opened" msgid="94695026776264709">"پوشه باز شده، <xliff:g id="WIDTH">%1$d</xliff:g> در <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"برای بستن پوشه لمس کنید"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"برای ذخیره تغییر نام لمس کنید"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ابزارک‌ها"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"کاغذدیواری‌ها"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"تنظیمات"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"در حال انتظار"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"در حال دانلود"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"در حال نصب"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"چرخش مجاز است"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"نامشخص"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"بازیابی نشد"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"حذف همه"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"حذف"</string>
     <string name="abandoned_search" msgid="891119232568284442">"جستجو"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"این برنامه نصب نشده است."</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"برنامه برای این نماد نصب نشده است. می‌توانید آن را حذف کنید یا سعی کنید برنامه را جستجو کنید و آن را به صورت دستی نصب کنید."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"افزودن به صفحه اصلی"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"انتقال مورد به اینجا"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"مورد به صفحه اصلی اضافه شد"</string>
+    <string name="item_removed" msgid="851119963877842327">"مورد حذف شد"</string>
+    <string name="action_move" msgid="4339390619886385032">"انتقال مورد"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"انتقال به سطر <xliff:g id="NUMBER_0">%1$s</xliff:g> ستون <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"انتقال به موقعیت <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"انتقال به موقعیت دلخواه <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"مورد منتقل شد"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"افزودن به پوشه: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"افزودن به پوشه حاوی <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"مورد به پوشه اضافه شد"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ایجاد پوشه با: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"پوشه ایجاد شد"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"انتقال به صفحه اصلی"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"انتقال صفحه به چپ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"انتقال صفحه به راست"</string>
+    <string name="screen_moved" msgid="266230079505650577">"صفحه منتقل شد"</string>
+    <string name="action_resize" msgid="1802976324781771067">"تغییر اندازه"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"افزایش عرض"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"افزایش ارتفاع"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"کاهش عرض"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"کاهش ارتفاع"</string>
+    <string name="widget_resized" msgid="9130327887929620">"اندازه ابزارک به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index a5da03f..f0766d6 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Aloitusruutu"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Androidin ydinsovellukset"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Työ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Sovellusta ei ole asennettu."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Sovellus ei ole käytettävissä"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ladattu sovellus poistettiin käytöstä suojatussa tilassa"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgetit poistettu käytöstä vikasietotilassa"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetit"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgetit"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Näytä muisti"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Valitse widget painamalla sitä pitkään."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Kohteen lisääminen tähän aloitusruutuun epäonnistui."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Valitse luotava widget"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Kansion nimi"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Nimeä kansio uudelleen"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Peruuta"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Lisää aloitusruutuun"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Sovellukset"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Pikakuvakkeet"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgetit"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Aloitusruuduilla ei ole enää tilaa."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sovellushaku"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Ladataan sovelluksia…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"”<xliff:g id="QUERY">%1$s</xliff:g>” ei palauttanut sovelluksia."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tässä aloitusruudussa ei ole enää tilaa."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Suosikit-valikossa ei ole enää tilaa"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Tämä widget on liian suuri Suosikit-valikkoon lisättäväksi"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Pikakuvake <xliff:g id="NAME">%s</xliff:g> luotiin."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Pikakuvake <xliff:g id="NAME">%s</xliff:g> poistettiin."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Pikakuvake <xliff:g id="NAME">%s</xliff:g> on jo olemassa."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Valitse pikakuvake"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Valitse sovellus"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Sovellukset"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Aloitusruutu"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Poista"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Poista"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Poista"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Poista"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Sovelluksen tiedot"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Sovellukset"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Poista"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Poista päivitys"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Poista sovellus"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Sovelluksen tiedot"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 sovellus valittu"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget valittu"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 kansio valittu"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 pikakuvake valittu"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"asenna pikakuvakkeita"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Antaa sovelluksen lisätä pikakuvakkeita itsenäisesti ilman käyttäjän valintaa."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"poista pikakuvakkeita"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Antaa sovelluksen poistaa pikakuvakkeita ilman käyttäjän valintaa."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lue aloitusruudun asetuksia ja pikakuvakkeita"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Antaa sovelluksen lukea aloitusruudun asetukset ja pikakuvakkeet."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"kirjoita aloitusruudun asetuksia ja pikakuvakkeita"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Ongelma ladattaessa widgetiä"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Asetus"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tämä on järjestelmäsovellus, eikä sitä voi poistaa."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Sinko"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nimetön kansio"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Aloitusruutu %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Apps-sivu %1$d / %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgetit-sivu %1$d / %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Tervetuloa"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Ole kuin kotonasi."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Luo lisää ruutuja sovelluksille ja kansioille"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopioi sovelluskuvakkeet"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Tuodaanko kuvakkeet ja kansiot vanhoista aloitusruuduista?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIOI KUVAKKEET"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ALOITA ALUSTA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Järjestä tilasi"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Hallitse taustakuvaa, widgetejä ja asetuksia koskettamalla taustaa pitkään."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Taustakuvat, widgetit ja asetukset"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Muokkaa taustaa koskettamalla ja painamalla pitkään"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SELVÄ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Tässä on kansio"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Luo se seuraavasti: kosketa sovellusta pitkään ja siirrä se sitten toisen päälle."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Kansio avattu, koko <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Sulje kansio koskettamalla"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Tallenna uudella nimellä koskettamalla"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgetit"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Taustakuvat"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Asetukset"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Odottaa"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Ladataan"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Asennetaan"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Salli kierto"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Tuntematon"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ei palautettu"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Poista kaikki"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Poista"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Haku"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Sovellusta ei ole asennettu"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Kuvakkeen sovellusta ei ole asennettu. Voit poistaa kuvakkeen tai etsiä sovelluksen ja asentaa sen manuaalisesti."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Lisää aloitusnäytölle"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Siirrä kohde tänne"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Kohde lisättiin aloitusnäytölle."</string>
+    <string name="item_removed" msgid="851119963877842327">"Kohde poistettiin."</string>
+    <string name="action_move" msgid="4339390619886385032">"Siirrä kohde"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Siirrä rivin <xliff:g id="NUMBER_0">%1$s</xliff:g> sarakkeeseen <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Siirrä kohtaan <xliff:g id="NUMBER">%1$s</xliff:g>."</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Siirrä suosikkien kohtaan <xliff:g id="NUMBER">%1$s</xliff:g>."</string>
+    <string name="item_moved" msgid="4606538322571412879">"Kohde on siirretty."</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Lisää kansioon <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Lisää samaan kansioon sovelluksen <xliff:g id="NAME">%1$s</xliff:g> kanssa."</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Kohde on lisätty kansioon."</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Luo kansio, jossa on <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="folder_created" msgid="6409794597405184510">"Kansio on luotu."</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Siirrä aloitusnäytölle"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Siirrä näyttöä vasemmalle"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Siirrä näyttöä oikealle"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Näyttö siirrettiin."</string>
+    <string name="action_resize" msgid="1802976324781771067">"Muuta kokoa"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Lisää leveyttä"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Lisää korkeutta"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Vähennä leveyttä"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Vähennä korkeutta"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widgetin kokoa muutettiin. Sen leveys on nyt <xliff:g id="NUMBER_0">%1$s</xliff:g> ja korkeus <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 62a2b89..0c19ef2 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Lanceur3"</string>
-    <string name="home" msgid="7658288663002113681">"Accueil"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Applications de base Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Travail"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Application indisponible"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sécurisé."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets désactivés en mode sans échec"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afficher la mémoire"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Maintenez un doigt sur le widget pour l\'ajouter."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Imposs. de déposer l\'élément sur l\'écran d\'accueil"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Sélectionnez le widget à créer"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nom du dossier"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Renommer le dossier"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Annuler"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Ajouter à l\'écran d\'accueil"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Applications"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Raccourcis"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Vous n\'avez plus d\'espace libre sur vos écrans d\'accueil."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher des applications"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur l\'écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Il n\'y a plus d\'espace dans la zone des favoris"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ce widget est trop volumineux pour la zone des favoris"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Le raccourci « <xliff:g id="NAME">%s</xliff:g> » a été créé."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Le raccourci « <xliff:g id="NAME">%s</xliff:g> » a été supprimé."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Le raccourci « <xliff:g id="NAME">%s</xliff:g> » existe déjà."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Sélectionner un raccourci"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Sélectionner une application"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Applications"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Accueil"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Supprimer"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Désinstaller"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Supprimer"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Désinstaller"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Détails de l\'application"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Applications"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Supprimer"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Désinstaller la mise à jour"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Désinstaller l\'application"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Détails de l\'application"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 application sélectionnée"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget sélectionné"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 dossier sélectionné"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 raccourci sélectionné"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"désinstaller des raccourcis"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permet à l\'application de supprimer des raccourcis sans l\'intervention de l\'utilisateur."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permet à l\'application de lire les paramètres et les raccourcis de l\'écran d\'accueil."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"enregistrer les paramètres de la page d\'accueil et des raccourcis"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problème lors du chargement du widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string>
     <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="dream_name" msgid="1530253749244328964">"Lance-missile"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Écran d\'accueil %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Page des applications : %1$d sur %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Page des widgets : %1$d sur %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bienvenue"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Faites comme chez vous."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Créer plus d\'écrans pour les applications et les dossiers"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copier les icônes de vos applis"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importer les icônes et dossiers des anciens écrans d\'accueil?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIER LES ICÔNES"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"DISPOSITION PAR DÉFAUT"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser son espace personnel"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Maintenez votre doigt sur l\'arrière-plan pour gérer les fonds d\'écran, les widgets et les paramètres."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fonds d\'écran, widgets et paramètres"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Maintenez le doigt sur le fond d\'écran pour personnaliser"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"J\'ai compris"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Voici un dossier"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pour créer un dossier comme ça, maintenez votre doigt sur une application, puis déplacez-la sur une autre."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toucher pour fermer le dossier"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toucher pour enregistrer le nouveau nom"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Paramètres"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"En attente"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Téléchargement..."</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installation…"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permettre la rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Non restauré"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Tout supprimer"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette application n\'est pas installée"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'application liée à cette icône n\'est pas installée. Vous pouvez la supprimer ou rechercher l\'application et l\'installer manuellement."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Ajouter à l\'écran d\'accueil"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Élément ajouté à l\'écran d\'accueil"</string>
+    <string name="item_removed" msgid="851119963877842327">"Élément supprimé"</string>
+    <string name="action_move" msgid="4339390619886385032">"Déplacer l\'élément"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Déplacer vers rangée <xliff:g id="NUMBER_0">%1$s</xliff:g> colonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g> dans les favoris"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Élément déplacé"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Ajouter au dossier : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Ajouter au dossier contenant <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Élément ajouté au dossier"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Créer un dossier avec : <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Dossier créé"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Déplacer sur l\'écran d\'accueil"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Déplacer l\'écran à gauche"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Déplacer l\'écran à droite"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Écran déplacé"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Redimensionner"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Augmenter la largeur"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Augmenter la hauteur"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Diminuer la largeur"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Le widget a été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index d23b6a4..662bcf1 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Accueil"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Applications de base Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Android Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Application indisponible"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sécurisé."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Les widgets sont désactivés en mode sécurisé."</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afficher la mémoire"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"App. de manière prolongée pour sélectionner widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Impossible de déposer élément sur écran d\'accueil."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Sélectionner le widget à créer"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nom du dossier"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Renommer le dossier"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Annuler"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Ajouter à l\'écran d\'accueil"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Applications"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Raccourcis"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Vous n\'avez plus d\'espace libre sur vos écrans d\'accueil."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Rechercher dans les applications"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Chargement des applications en cours…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Aucune application ne correspond à la requête \"<xliff:g id="QUERY">%1$s</xliff:g>\"."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Pas d\'espace libre sur cet écran d\'accueil."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Plus d\'espace disponible dans la zone de favoris."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ce widget est trop volumineux pour la zone de favoris."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Le raccourci \"<xliff:g id="NAME">%s</xliff:g>\" a été créé."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Le raccourci \"<xliff:g id="NAME">%s</xliff:g>\" a été supprimé."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Le raccourci \"<xliff:g id="NAME">%s</xliff:g>\" existe déjà."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Sélectionner un raccourci"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Sélectionner une application"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Applications"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Accueil"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Supprimer"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Désinstaller"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Supprimer"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Désinstaller"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informations sur l\'application"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Applications"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Supprimer"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Désinstaller la mise à jour"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Désinstaller l\'application"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Informations sur l\'application"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 application sélectionnée"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget sélectionné"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 dossier sélectionné"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 raccourci sélectionné"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permettre à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"désinstaller des raccourcis"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permettre à l\'application de supprimer des raccourcis sans l\'intervention de l\'utilisateur"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lire les paramètres et les raccourcis de l\'écran d\'accueil"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permettre à l\'application de lire les paramètres et les raccourcis de l\'écran d\'accueil"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"modifier les paramètres et les raccourcis de l\'écran d\'accueil"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problème lors du chargement du widget."</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuration"</string>
     <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="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dossier sans nom"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Écran d\'accueil %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Page des applications %1$d sur %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Page des widgets %1$d sur %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bienvenue"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Familiarisez-vous avec l\'écran d\'accueil."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Créez des écrans personnalisés pour vos applis et dossiers"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copier les icônes de vos applis"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importer les icônes et dossiers des anciens écrans d\'accueil ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIER LES ICÔNES"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"DISPOSITION PAR DÉFAUT"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organisez votre espace"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Appuyez de manière prolongée sur l\'arrière-plan pour gérer les fonds d\'écran, les widgets et les paramètres."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fonds d\'écran, widgets et paramètres"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Appuyez de manière prolongée sur l\'arrière-plan pour le personnaliser."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Voici un dossier"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pour en créer un, appuyez de manière prolongée sur une application, puis déplacez-la vers une autre."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dossier ouvert, <xliff:g id="WIDTH">%1$d</xliff:g> par <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Appuyez pour fermer le dossier."</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Appuyez pour enregistrer le nouveau nom."</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fonds d\'écran"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Paramètres"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"En attente"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Téléchargement…"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installation…"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Autoriser la rotation"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Non restauré"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Tout supprimer"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette application n\'est pas installée"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'application correspondant à cette icône n\'est pas installée. Vous pouvez supprimer cette dernière, ou essayer de rechercher l\'application et de l\'installer manuellement."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Ajouter à l\'écran d\'accueil"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Déplacer l\'élément ici"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"L\'élément a bien été ajouté à l\'écran d\'accueil."</string>
+    <string name="item_removed" msgid="851119963877842327">"L\'élément a bien été supprimé."</string>
+    <string name="action_move" msgid="4339390619886385032">"Déplacer l\'élément"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Déplacer vers la ligne <xliff:g id="NUMBER_0">%1$s</xliff:g>, colonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Déplacer vers la position <xliff:g id="NUMBER">%1$s</xliff:g> dans les favoris"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Élément déplacé"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Ajouter au dossier \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Ajouter au dossier contenant \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Élément ajouté au dossier"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Créer un dossier avec \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="folder_created" msgid="6409794597405184510">"Dossier créé"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Déplacer vers l\'écran d\'accueil"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Déplacer l\'écran vers la gauche"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Déplacer l\'écran vers la droite"</string>
+    <string name="screen_moved" msgid="266230079505650577">"L\'écran a bien été déplacé."</string>
+    <string name="action_resize" msgid="1802976324781771067">"Redimensionner"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Augmenter la largeur"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Augmenter la hauteur"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Diminuer la largeur"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Le widget a bien été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)."</string>
 </resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index 96a53dc..6cf76a7 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Inicio"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplicacións básicas de Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Traballo"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"A aplicación non está instalada"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"A aplicación non está dispoñible"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"A aplicación que descargaches está desactivada no modo seguro"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Os widgets están desactivados no modo seguro"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memoria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Mantén premido un widget para seleccionalo."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Non se puido engadir á pantalla de inicio."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Escolle o widget que queiras crear"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nome do cartafol"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Cambiar o nome do cartafol"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Aceptar"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Engadir á pantalla de inicio"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicacións"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Atallos"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Non hai máis espazo nas pantallas de inicio."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Aplicacións de busca"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Cargando aplicacións..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Non hai máis espazo nesta pantalla de inicio."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Non hai máis espazo na bandexa de favoritos"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Este widget é demasiado grande para a bandexa de favoritos"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Creouse o atallo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Eliminouse o atallo \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"O atallo \"<xliff:g id="NAME">%s</xliff:g>\" xa existe."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Escoller un atallo"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Escoller unha aplicación"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicacións"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Inicio"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eliminar"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Información da aplicación"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicacións"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eliminar"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar actualización"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar aplicación"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalles da aplicación"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicación seleccionada"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget seleccionado"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 cartafol seleccionado"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 atallo seleccionado"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atallos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a unha aplicación engadir atallos sen intervención do usuario."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar atallos"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite a unha aplicación eliminar atallos sen intervención do usuario."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler a configuración e os atallos da pantalla de inicio"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite a unha aplicación ler a configuración e os atallos da páxina de inicio."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"modificar a configuración e os atallos da pantalla de inicio"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Produciuse un problema ao cargar o widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuración"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Esta aplicación é do sistema e non se pode desinstalar."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Lanzacohetes"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartafol sen nome"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Pantalla de inicio %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Páxina de aplicacións %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Páxina de widgets %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Dámosche a benvida"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Síntete como na túa casa."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crea máis pantallas para aplicacións e cartafoles"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar iconas das aplicacións"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Queres importar as iconas e os cartafoles doutras pantallas de inicio?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ICONAS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEZAR DE CERO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiza o espazo"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Mantén premido o fondo para xestionar o fondo de pantalla e máis."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fondos pantalla, widgets e configuración"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Mantén tocado o segundo plano para personalizar"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"DE ACORDO"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Isto é un cartafol"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para crear un igual, mantén premida a aplicación e móvea sobre outra."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Aceptar"</string>
     <string name="folder_opened" msgid="94695026776264709">"Abriuse o cartafol, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toca para pechar o cartafol"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toca para gardar o cambio de nome"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Configuración"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"En espera"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Descargando"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permitir xiro"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Descoñecido"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Non restaurado"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminar todas"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicación non está instalada"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicación para esta icona non está instalada. Podes eliminala ou buscar a aplicación e instalala manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Engadir á pantalla de inicio"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mover elemento aquí"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Engadiuse o elemento á pantalla de inicio"</string>
+    <string name="item_removed" msgid="851119963877842327">"Eliminouse o elemento"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mover elemento"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover á fila <xliff:g id="NUMBER_0">%1$s</xliff:g> columna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mover á posición <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover á posición dos favoritos <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Moveuse o elemento"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Engadir ao cartafol: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Engadir ao cartafol con <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Engadiuse o elemento ao cartafol"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Crear cartafol con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Creouse o cartafol"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover á pantalla de inicio"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover pantalla á esquerda"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mover pantalla á dereita"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Moveuse a pantalla"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Cambiar tamaño"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumentar ancho"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reducir ancho"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Cambiouse o tamaño do widget polo ancho <xliff:g id="NUMBER_0">%1$s</xliff:g> e a altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index a2798d6..4a2274f 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"હોમ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core એપ્લિકેશન્સ"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"એપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"એપ્લિકેશન ઉપલબ્ધ નથી"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"સુરક્ષિત મોડમાં ડાઉનલોડ કરેલ એપ્લિકેશન અક્ષમ કરી"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"સુરક્ષિત મોડમાં વિજેટ્સ અક્ષમ કર્યા"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"વિજેટ્સ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"વિજેટ્સ"</string>
-    <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem દર્શાવો"</string>
+    <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem બતાવો"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"વિજેટ ચૂંટવા માટે ટચ કરો અને પકડી રાખો."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"આ હોમ સ્ક્રીન પર આઇટમ છોડી શકાઈ નથી."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"બનાવવા માટે વિજેટ પસંદ કરો"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ફોલ્ડરનું નામ"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ફોલ્ડરનું નામ બદલો"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ઑકે"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"રદ કરો"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"હોમ સ્ક્રીન પર ઉમેરો"</string>
-    <string name="group_applications" msgid="3797214114206693605">"એપ્લિકેશન્સ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"શોર્ટકટ્સ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"વિજેટ્સ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"તમારી હોમ સ્ક્રીન પર વધુ જગ્યા નથી."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"શોધ એપ્લિકેશનો"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"એપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" થી મેળ ખાતી કોઈ એપ્લિકેશનો મળી નથી"</string>
     <string name="out_of_space" msgid="4691004494942118364">"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"મનપસંદ ટ્રે પર વધુ જગ્યા નથી"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"મનપસંદ ટ્રે માટે આ વિજેટ ખૂબ મોટું છે"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" શોર્ટકટ બનાવ્યું."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" શોર્ટકટ દૂર કર્યું હતું."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" શોર્ટકટ પહેલાંથી અસ્તિત્વમાં છે."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"શોર્ટકટ પસંદ કરો"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"એપ્લિકેશન પસંદ કરો"</string>
-    <string name="all_apps_button_label" msgid="9110807029020582876">"એપ્લિકેશન્સ"</string>
+    <string name="all_apps_button_label" msgid="9110807029020582876">"એપ્લિકેશનો"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"હોમ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"દૂર કરો"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"અનઇન્સ્ટોલ કરો"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"દૂર કરો"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"અનઇન્સ્ટોલ કરો"</string>
     <string name="info_target_label" msgid="8053346143994679532">"એપ્લિકેશન માહિતી"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"એપ્લિકેશન્સ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"દૂર કરો"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"અપડેટ અનઇન્સ્ટોલ કરો"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"એપ્લિકેશન અનઇન્સ્ટોલ કરો"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"એપ્લિકેશનની વિગતો"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 એપ્લિકેશન પસંદ કરી"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 વિજેટ પસંદ કર્યું"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ફોલ્ડર પસંદ કર્યું"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 શોર્ટકટ પસંદ કર્યું"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"શોર્ટકટ્સ ઇન્સ્ટોલ કરો"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ ઉમેરવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"શોર્ટકટ્સ અનઇન્સ્ટોલ કરો"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"એપ્લિકેશનને વપરાશકર્તા હસ્તક્ષેપ વગર શોર્ટકટ્સ દૂર કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"હોમ સેટિંગ્સ અને શોર્ટકટ્સ વાંચો"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"એપ્લિકેશનને હોમમાં સેટિંગ્સ અને શોર્ટકટ્સ વાંચવાની મંજૂરી આપે છે."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"હોમ સેટિંગ્સ અને શોર્ટકટ્સ લખો"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"વિજેટ લોડ કરવામાં સમસ્યા"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"સેટઅપ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"આ એક સિસ્ટમ એપ્લિકેશન છે અને અનઇન્સ્ટોલ કરી શકાતી નથી."</string>
-    <string name="dream_name" msgid="1530253749244328964">"રોકેટ લોન્ચર"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"અનામી ફોલ્ડર"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d હોમ સ્ક્રીન"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d માંથી %1$d એપ્લિકેશન્સ પૃષ્ઠ"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d માંથી %1$d વિજેટ્સ પૃષ્ઠ"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"સ્વાગત છે"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ઘરે જાતે બનાવે છે."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"એપ્લિકેશન્સ અને ફોલ્ડર્સ માટે વધુ સ્ક્રીન બનાવો"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"તમારા એપ્લિકેશન આયકન્સને કૉપિ કરો"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"તમારી જૂની હોમ સ્ક્રીન્સથી આયકન્સ અને ફોલ્ડર્સને આયાત કરીએ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"આયકન્સને કૉપિ કરો"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"નવેસરથી પ્રારંભ કરો"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"તમારા સ્થાનને ગોઠવો"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"વૉલપેપર, વિજેટ્સ અને સેટિંગ્સને સંચાલિત કરવા માટે પૃષ્ઠભૂમિને ટચ કરો અને પકડી રાખો."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"વૉલપેપર્સ, વિજેટ્સ અને સેટિંગ્સ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"પૃષ્ઠભૂમિને કસ્ટમાઇઝ કરવા માટે ટચ કરો અને પકડી રાખો"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"સમજાઈ ગયું"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"અહીં ફોલ્ડર છે"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"આના જેવું એક બનાવવા માટે, એપ્લિકેશનને ટચ કરો અને પકડી રાખો, પછી તેને બીજીમાં ખસેડો."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ઑકે"</string>
     <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> બાય <xliff:g id="HEIGHT">%2$d</xliff:g> નું ફોલ્ડર ખોલ્યું"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ફોલ્ડર બંધ કરવા માટે ટચ કરો"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"નામ બદલવાનું સાચવવા માટે ટચ કરો"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"વિજેટ્સ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"વૉલપેપર્સ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"સેટિંગ્સ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"રાહ જુએ છે"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ડાઉનલોડ કરે છે"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ઇન્સ્ટોલ કરી રહ્યું છે"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"પરિભ્રમણને મંજૂરી આપો"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"અજાણ્યો"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"પુનર્સ્થાપિત કર્યું નથી"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"બધું દૂર કરો"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"દૂર કરો"</string>
     <string name="abandoned_search" msgid="891119232568284442">"શોધો"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"આ એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"આ આયકન માટેની એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી. તમે તેને દૂર કરી શકો છો અથવા એપ્લિકેશન માટે શોધ કરી અને તેને મેન્યુઅલી ઇન્સ્ટોલ કરી શકો છો."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"હોમ સ્ક્રીન પર ઉમેરો"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"આઇટમ અહીં ખસેડો"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"હોમ સ્ક્રીનમાં આઇટમ ઉમેરી"</string>
+    <string name="item_removed" msgid="851119963877842327">"આઇટમ દૂર કરી"</string>
+    <string name="action_move" msgid="4339390619886385032">"આઇટમ ખસેડો"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> પંક્તિ <xliff:g id="NUMBER_1">%2$s</xliff:g> કૉલમ પર ખસેડો"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> સ્થિતિ પર ખસેડો"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"મનપસંદ સ્થિતિ <xliff:g id="NUMBER">%1$s</xliff:g> પર ખસેડો"</string>
+    <string name="item_moved" msgid="4606538322571412879">"આઇટમ ખસેડી"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ફોલ્ડરમાં ઉમેરો: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> સાથે ફોલ્ડરમાં ઉમેરો"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ફોલ્ડરમાં આઇટમ ઉમેરી"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"આની સાથે ફોલ્ડર બનાવો: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ફોલ્ડર બનાવ્યું"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"હોમ સ્ક્રીન પર ખસેડો"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"સ્ક્રીનને ડાબી બાજુ ખસેડો"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"સ્ક્રીનને જમણી બાજુ ખસેડો"</string>
+    <string name="screen_moved" msgid="266230079505650577">"સ્ક્રીન ખસેડી"</string>
+    <string name="action_resize" msgid="1802976324781771067">"આકાર બદલો"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"પહોળાઈ વધારો"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ઊંચાઈ વધારો"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"પહોળાઈ ઘટાડો"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ઊંચાઈ ઘટાડો"</string>
+    <string name="widget_resized" msgid="9130327887929620">"વિજેટનો આકાર બદલીને <xliff:g id="NUMBER_0">%1$s</xliff:g> પહોળાઈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ઊંચાઈ કર્યો"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0599da0..6fdbf24 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"होम"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android के मुख्य ऐप्लिकेशन"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"कार्यस्‍थल"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"एप्‍लिकेशन इंस्‍टॉल नहीं है."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ऐप्स उपलब्ध नहीं है"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"डाउनलोड किए गए ऐप्स सुरक्षित मोड में अक्षम है"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोड में अक्षम हैं"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"शॉर्टकट"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"शॉर्टकट"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"मेमोरी दिखाएं"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट को चुनने के लिए स्‍पर्श करके रखें."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"आइटम को इस होम स्‍क्रीन पर नहीं छोड़ा जा सका."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"बनाने के लिए विजेट चुनें"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"फ़ोल्‍डर का नाम"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"फ़ोल्‍डर का नाम बदलें"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ठीक"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"अभी नहीं"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"होम स्‍क्रीन में जोड़ें"</string>
-    <string name="group_applications" msgid="3797214114206693605">"ऐप्लिकेशन"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"शॉर्टकट"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"शॉर्टकट"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"आपकी होम स्‍क्रीन पर स्थान शेष नहीं है."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ऐप्‍स खोजें"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ऐप्स लोड हो रहे हैं..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलान करने वाला कोई ऐप नहीं मिला"</string>
     <string name="out_of_space" msgid="4691004494942118364">"इस होम स्‍क्रीन पर स्थान शेष नहीं है."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"पसंदीदा ट्रे में और स्थान नहीं है"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"पसंदीदा ट्रे के लिए यह विजेट बहुत ही बड़ा है"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"शॉर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" बनाया गया."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"शॉर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" निकाल दिया गया था."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"शॉर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" पहले से मौजूद है."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"शॉर्टकट चुनें"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"एप्‍लिकेशन चुनें"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ऐप्लिकेशन"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"होम"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"निकालें"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"अनइंस्टॉल करें"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"निकालें"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"अनइंस्टॉल करें"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ऐप्लिकेशन की जानकारी"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ऐप्लिकेशन"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"निकालें"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"अपडेट अनइंस्‍टॉल करें"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ऐप्लिकेशन अनइंस्‍टॉल करें"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ऐप्लिकेशन का विवरण"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 एप्‍लिकेशन चयनित"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 विजेट चयनित"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 फ़ोल्‍डर चयनित"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 शॉर्टकट चयनित"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट इंस्‍टॉल करें"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ऐप्लिकेशन को उपयोगकर्ता के हस्‍तक्षेप के बिना शॉर्टकट जोड़ने देती है."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"शॉर्टकट अनइंस्टॉल करें"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ऐप्लिकेशन को उपयोगकर्ता के हस्‍तक्षेप के बिना शॉर्टकट निकालने देती है."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"होम सेटिंग और शॉर्टकट पढ़ें"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ऐप्लिकेशन को होम में सेटिंग और शॉर्टकट पढ़ने देती है."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"होम सेटिंग और शॉर्टकट लिखें"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"विजेट लोड करने में समस्‍या"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"यह एक सिस्टम ऐप्लिकेशन है और इसे अनइंस्टॉल नहीं किया जा सकता."</string>
-    <string name="dream_name" msgid="1530253749244328964">"रॉकेट लॉन्‍चर"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फ़ोल्डर"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"होम स्‍क्रीन %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"ऐप्लिकेशन पृष्ठ %2$d में से %1$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"शॉर्टकट %2$d में से %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"स्वागत है"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"जैसा चाहें वैसा उपयोग करें."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ऐप्लिकेशन और फ़ोल्डर के लिए और अधिक स्क्रीन बनाएं"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ऐप्स आइकन की प्रतिलिपि बनाएं"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"अपनी पुरानी होम स्क्रीन से आइकन और फ़ोल्डर आयात करें?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"आइकन की प्रतिलिपि बनाएं"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"फिर से शुरू करें"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"अपने स्थान को व्यवस्थित करें"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"वॉलपेपर, शॉर्टकट और सेटिंग प्रबंधित करने के लिए पृष्ठभूमि को स्पर्श करके रखें."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वॉलपेपर, शॉर्टकट और सेटिंग"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"पृष्ठभूमि कस्टमाइज़ करने के लिए स्पर्श करके रखें"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"समझ लिया"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"यहां एक फ़ोल्डर है"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"इसके जैसा कोई एक बनाने के लिए, किसी ऐप्लिकेशन को स्पर्श करके रखें, फिर इसे किसी दूसरे पर ले जाएं."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ठीक"</string>
     <string name="folder_opened" msgid="94695026776264709">"फ़ोल्डर खोला गया, <xliff:g id="WIDTH">%1$d</xliff:g> गुणा <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"फ़ोल्‍डर बंद करने के लिए स्‍पर्श करें"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"बदला गया नाम सहेजने के लिए स्पर्श करें"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"शॉर्टकट"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"सेटिंग"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"प्रतीक्षा में"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड हो रहा है"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"इंस्टॉल हो रहा है"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"रोटेशन की अनुमति दें"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"पुन:स्थापित नहीं हुआ"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"सभी निकालें"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"निकालें"</string>
     <string name="abandoned_search" msgid="891119232568284442">"खोजें"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"यह ऐप्स इंस्टॉल नहीं है"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"इस आइकन का ऐप्स इंस्टॉल नहीं है. आप उसे निकाल सकते हैं या ऐप्स की खोज करके उसे मैन्युअल रूप से इंस्टॉल कर सकते हैं."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"होम स्‍क्रीन में जोड़ें"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"आइटम यहां ले जाएं"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"होम स्क्रीन में आइटम जोड़ा गया"</string>
+    <string name="item_removed" msgid="851119963877842327">"आइटम निकाला गया"</string>
+    <string name="action_move" msgid="4339390619886385032">"आइटम ले जाएं"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"पंक्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तंभ <xliff:g id="NUMBER_1">%2$s</xliff:g> पर ले जाएं"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थिति पर ले जाएं"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"<xliff:g id="NUMBER">%1$s</xliff:g> की पसंदीदा स्थिति पर ले जाएं"</string>
+    <string name="item_moved" msgid="4606538322571412879">"आइटम ले जाया गया"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"फ़ोल्डर में जोड़ें: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> के साथ फ़ोल्डर में जोड़ें"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"आइटम फ़ोल्डर में जोड़ा गया"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"इसके साथ फ़ोल्डर बनाएं: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"फ़ोल्डर बनाया गया"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"होम स्क्रीन पर ले जाएं"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रीन को बाएं ले जाएं"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रीन को दाएं ले जाएं"</string>
+    <string name="screen_moved" msgid="266230079505650577">"स्क्रीन ले जाई गई"</string>
+    <string name="action_resize" msgid="1802976324781771067">"आकार बदलें"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"चौड़ाई बढ़ाएं"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ऊंचाई बढ़ाएं"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"चौड़ाई घटाएं"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ऊंचाई घटाएं"</string>
+    <string name="widget_resized" msgid="9130327887929620">"विजेट का आकार बदलकर उसकी चौड़ाई <xliff:g id="NUMBER_0">%1$s</xliff:g> और ऊंचाई <xliff:g id="NUMBER_1">%2$s</xliff:g> कर दी गई"</string>
 </resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 00810a7..a54a7e4 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Pokretač3"</string>
-    <string name="home" msgid="7658288663002113681">"Početna"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Matične aplikacije za Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Posao"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Preuzeta aplikacija onemogućena je u Sigurnom načinu rada"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgeti su onemogućeni u Sigurnom načinu rada"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgeti"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgeti"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Prikaži mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Dodirnite i držite kako biste podigli widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Stavka nije ispuštena na ovaj početni zaslon."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Odabir widgeta za stvaranje"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Naziv mape"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Preimenovanje mape"</string>
-    <string name="rename_action" msgid="5559600076028658757">"U redu"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Odustani"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Dodavanje na početni zaslon"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikacije"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Prečaci"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgeti"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Na vašim početnim zaslonima više nema mjesta."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pretraži aplikacije"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Učitavanje aplikacija…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nema aplikacija podudarnih s upitom \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na ovom početnom zaslonu više nema mjesta."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Favoriti"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Widget je prevelik za traku Favoriti"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Izrađen je prečac za \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Uklonjen je prečac za \"<xliff:g id="NAME">%s</xliff:g>\"."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Prečac za \"<xliff:g id="NAME">%s</xliff:g>\" već postoji."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Odabir prečaca"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Odabir aplikacije"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacije"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Početna"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Ukloni"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Deinstaliraj"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Ukloni"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Deinstaliraj"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informacije o aplikaciji"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikacije"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Ukloni"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Deinstalacija ažuriranja"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Deinstaliranje aplikacije"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Pojedinosti o aplikaciji"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Odabrana je 1 aplikacija"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Odabran je 1 widget"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Odabrana je 1 mapa"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Odabran je 1 prečac"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečaca"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji omogućuje dodavanje prečaca bez intervencije korisnika."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"deinstaliranje prečaca"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Aplikaciji omogućuje uklanjanje prečaca bez intervencije korisnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čitanje postavki početnog zaslona i prečaca"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Aplikaciji omogućuje čitanje postavki i prečaca na početnom zaslonu."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"pisanje postavki početnog zaslona i prečaca"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem pri učitavanju widgeta"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Postavljanje"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je aplikacija sustava i ne može se ukloniti."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Lansirna rampa"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Početni zaslon %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Stranica aplikacija %1$d od %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Stranica widgeta %1$d od %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Dobro došli"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Osjećajte se kao kod kuće."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Izradite više zaslona za aplikacije i mape"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiranje ikona aplikacija"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Želite li uvesti ikone i mape sa starih početnih zaslona?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIRAJ IKONE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"POKRENI NOVO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizirajte svoj prostor"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Dodirnite i držite pozadinu da biste upravljali pozadinskom slikom, widgetima i postavkama."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Pozadine, widgeti i postavke"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Dodirnite i zadržite pozadinu radi prilagodbe"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SHVAĆAM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Evo mape"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Da biste izradili ovakvu mapu, dodirnite i držite aplikaciju pa je pomaknite preko druge aplikacije."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"U redu"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mapa je otvorena, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Dodirnite da biste zatvorili mapu"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Dodirnite da biste spremili preimenovanje"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgeti"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadine"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Postavke"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Čekanje"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Preuzimanje"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instaliranje"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Dopusti rotaciju"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nije vraćeno"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Ukloni sve"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Traži"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacija nije instalirana"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija ove ikone nije instalirana. Možete je ukloniti ili potražiti aplikaciju i instalirati je ručno."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodavanje na početni zaslon"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Premjesti stavku ovdje"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodana na početni zaslon"</string>
+    <string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+    <string name="action_move" msgid="4339390619886385032">"Premještanje stavke"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Premještanje u redak <xliff:g id="NUMBER_0">%1$s</xliff:g>, stupac <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Premještanje na položaj <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Premještanje na položaj favorita <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Stavka premještena"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Dodavanje u mapu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodavanje u mapu s aplikacijom <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Stavka dodana u mapu"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Izrada mape pomoću stavke: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mapa izrađena"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Premještanje na početni zaslon"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Premještanje zaslona ulijevo"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Premještanje zaslona udesno"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Zaslon je premješten"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Promjena veličine"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Povećanje širine"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Povećanje visine"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Smanjenje širine"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Smanjenje visine"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Širina widgeta promijenjena je na <xliff:g id="NUMBER_0">%1$s</xliff:g>, a visina na <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 513548a..e9fc574 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Főoldal"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Alap Android-alkalmazások"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Munka"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Az alkalmazás nincs telepítve."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Az alkalmazás nem érhető el"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"A letöltött alkalmazás Csökkentett módban ki van kapcsolva"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"A modulok ki vannak kapcsolva Csökkentett módban"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Modulok"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Modulok"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem. megjelenítése"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Modul felvételéhez érintse meg, és tartsa lenyomva"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nem lehet elemeket dobni erre a kezdőképernyőre."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"A létrehozáshoz válasszon modult"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mappa neve"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Mappa átnevezése"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Mégse"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Hozzáadás a kezdőképernyőhöz"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Alkalmazások"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Parancsikonok"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Modulok"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Nincs több hely a kezdőképernyőkön."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Alkalmazások keresése"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Alkalmazások betöltése…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Egy alkalmazás sem található a(z) „<xliff:g id="QUERY">%1$s</xliff:g>” lekérdezésre."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nincs több hely ezen a kezdőképernyőn."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nincs több hely a Kedvencek tálcán"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ez a modul túl nagy a Kedvencek tálcán való elhelyezéshez"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"A(z) „<xliff:g id="NAME">%s</xliff:g>” parancsikon létrehozva."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"A(z) „<xliff:g id="NAME">%s</xliff:g>” parancsikon eltávolítva."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"A(z) „<xliff:g id="NAME">%s</xliff:g>” parancsikon már létezik."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Parancsikon választása"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Válasszon alkalmazást"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Alkalmazások"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Főoldal"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eltávolítás"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Eltávolítás"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eltávolítás"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Eltávolítás"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Alkalmazásinformáció"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Alkalmazások"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eltávolítás"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Eltávolítja a frissítést"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Alkalmazás eltávolítása"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Az alkalmazás adatai"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 alkalmazás kiválasztva"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 modul kiválasztva"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 mappa kiválasztva"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 parancsikon kiválasztva"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"parancsikonok telepítése"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül adjon hozzá parancsikonokat."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"parancsikonok eltávolítása"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Lehetővé teszi egy alkalmazás számára, hogy felhasználói beavatkozás nélkül távolítson el parancsikonokat."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Főoldal beállításainak és parancsikonjainak beolvasása"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Lehetővé teszi az alkalmazás számára, hogy beolvassa a kezdőképernyő beállításait és parancsikonjait."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Főoldal beállításainak és parancsikonjainak írása"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Probléma történt a modul betöltésekor"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Beállítás"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ez egy rendszeralkalmazás, és nem lehet eltávolítani."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Aknavető"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Névtelen mappa"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d. kezdőképernyő"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d/%1$d. alkalmazásoldal"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d/%1$d. moduloldal"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Üdvözöljük!"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Varázsolja egyedivé készülékét."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Hozzon létre további képernyőket az alkalmazásoknak és mappáknak"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Alkalmazásikonok másolása"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importálja ikonjait és mappáit régi kezdőképernyőiről?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"IKONOK MÁSOLÁSA"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"TELJESEN ÚJ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Munkaterület rendezése"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Érintse meg és tartsa lenyomva a hátteret a háttérkép, modulok és beállítások kezeléséhez."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Háttérképek, modulok és beállítások"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Érintse meg és tartsa lenyomva a személyre szabáshoz"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"MEGÉRTETTEM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Itt egy mappa"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Mappa létrehozásához érintse meg és tartsa lenyomva az alkalmazást, majd húzza egy másik fölé."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappa megnyitva – szélesség: <xliff:g id="WIDTH">%1$d</xliff:g>; magasság: <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Érintse meg a mappa bezárásához"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Érintse meg az átnevezés mentéséhez"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Modulok"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Háttérképek"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Beállítások"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Várakozik"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Letöltés alatt"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Települ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Elforgatás engedélyezése"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ismeretlen"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nincs visszaállítva"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Az összes eltávolítása"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eltávolítás"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Keresés"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Az alkalmazás nincs telepítve"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Az ikonhoz tartozó alkalmazás nincs telepítve. Törölheti az ikont, vagy az alkalmazás megkeresése után manuálisan telepítheti azt."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Hozzáadás a kezdőképernyőhöz"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Elem áthelyezése ide"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elem hozzáadva a kezdőképernyőhöz"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elem eltávolítva"</string>
+    <string name="action_move" msgid="4339390619886385032">"Elem mozgatása"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Áthelyezés ide: <xliff:g id="NUMBER_0">%1$s</xliff:g>. sor, <xliff:g id="NUMBER_1">%2$s</xliff:g>. oszlop"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Áthelyezés a(z) <xliff:g id="NUMBER">%1$s</xliff:g>. pozícióba"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Áthelyezés a kedvencek <xliff:g id="NUMBER">%1$s</xliff:g>. pozíciójába"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elem áthelyezve"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Hozzáadás a(z) <xliff:g id="NAME">%1$s</xliff:g> mappához"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Hozzáadás a mappához a következővel: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elem hozzáadva a mappához"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Mappa létrehozása a következővel: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mappa létrehozva"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Áthelyezés a kezdőképernyőre"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Képernyő mozgatása balra"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Képernyő mozgatása jobbra"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Képernyő áthelyezve"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Átméretezés"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Szélesség növelése"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Magasság növelése"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Szélesség csökkentése"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Magasság csökkentése"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Modul átméretezve <xliff:g id="NUMBER_0">%1$s</xliff:g> szélességre és <xliff:g id="NUMBER_1">%2$s</xliff:g> magasságra"</string>
 </resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 4af794e..de4aed1 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Հիմնական"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Աշխատանքային"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Ծրագիրը տեղադրված չէ:"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Հավելվածը հասանելի չէ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ներբեռնված ծրագիրն անջատված է Անվտանգ ռեժիմում"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Վիջեթներն անջատված են անվտանգ ռեժիմում"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Վիջեթներ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Վիջեթներ"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Ցուցադրել մեմը"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Հպեք և պահեք՝ վիջեթն ընտրելու համար:"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Հնարավոր չէ տեղադրել տարրն այս հիմնական էկրանին:"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Ստեղծելու համար ընտրեք վիջեթը"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Պանակի անունը"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Վերանվանել պանակը"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Լավ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Չեղարկել"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Ավելացնել հիմնական էկրանին"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Ծրագրեր"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Դյուրանցումներ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Վիջեթներ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Այլևս տեղ չկա ձեր հիմնական էկրաններին:"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Հավելվածների որոնում"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Հավելվածների բեռնում…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Այլևս տեղ չկա այս հիմնական էկրանին:"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ընտրյալների ցուցակում այլևս ազատ տեղ չկա"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Այս վիջեթը շատ մեծ է Ընտրյալների ցուցակի համար"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"«<xliff:g id="NAME">%s</xliff:g>» դյուրանցումը ստեղծված է:"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"«<xliff:g id="NAME">%s</xliff:g>» դյուրանցումը հեռացվեց:"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"«<xliff:g id="NAME">%s</xliff:g>» դյուրանցումն արդեն գոյություն ունի:"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Ընտրել դյուրանցումը"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Ընտրել ծրագիրը"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ծրագրեր"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Հիմնական"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Հեռացնել"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Ապատեղադրել"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Հեռացնել"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Ապատեղադրել"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Ծրագրի տեղեկություններ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Ծրագրեր"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Հեռացնել"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Ապատեղադրել թարմացումը"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Ապատեղադրել ծրագիրը"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Ծրագրի մանրամասներ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ընտրված ծրագիր"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ընտրված վիջեթ"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ընտրված պանակ"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ընտրված դյուրանցում"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"տեղադրել դյուրանցումներ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ծրագրին թույլ է տալիս ավելացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ապատեղադրել դյուրանցումները"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ծրագրին թույլ է տալիս հեռացնել դյուրանցումներ՝ առանց օգտագործողի միջամտության:"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"կարդալ հիմնաէջի կարգավորումներն ու դյուրանցումները"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Ծրագրին թույլ է տալիս կարդալ հիմնաէջի կարգավորումներն ու դյուրանցումները:"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ստեղծել հիմնաէջի կարգավորումներ ու դյուրանցումներ"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Վիջեթի բեռնման խնդիր կա"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Կարգավորում"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Սա համակարգային ծրագիր է և չի կարող ապատեղադրվել:"</string>
-    <string name="dream_name" msgid="1530253749244328964">"Հրթիռային թողարկիչ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Անանուն պանակ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Հիմնական էկրան %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Ծրագրերի էջերը՝ %1$d %2$d-ից"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Վիջեթների էջերը՝ %1$d %2$d-ից"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Բարի գալուստ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Զգացեք ձեզ ինչպես տանը:"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Ստեղծեք նոր էկրաններ ծրագրերի և պանակների համար"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Պատճենել ձեր ծրագրի պատկերակները"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Ներմուծե՞լ պատկերակները և պանակները ձեր նախկին Հիմնական էկրանից"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ՊԱՏՃԵՆԵԼ ՊԱՏԿԵՐԱԿՆԵՐԸ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ՄԵԿՆԱՐԿԵԼ ԸՍՏ ԿԱՆԽԱԴՐՎԱԾԻ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Կառավարեք ձեր տարածությունը"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Հպեք և պահեք հետնաշերտի վրա՝ պաստառները, վիջեթներն ու կարգավորումները կառավարելու համար:"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Պաստառներ, վիջեթներ և կարգավորումներ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Հարմարեցնելու համար հպեք և պահեք հետնաշերտի վրա"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ՀԱՍԿԱՆԱԼԻ Է"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ահա մի պանակ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Նման պանակ ստեղծելու համար հպեք և պահեք որևէ ծրագրի վրա, ապա տեղաշարժեք այն մեկ ուրիշ ծրագրի վրա:"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Լավ"</string>
     <string name="folder_opened" msgid="94695026776264709">"Թղթապանակը բաց է, <xliff:g id="WIDTH">%1$d</xliff:g>-ից <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Հպեք՝ պանակը փակելու համար"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Հպեք՝ վերանվանումը պահելու համար"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Վիջեթներ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Պաստառներ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Կարգավորումներ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Առկախ է"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Ներբեռնվում է"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Տեղադրվում է"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Թույլ տալ պարբերական կրկնությունը"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Անհայտ է"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Չի վերականգնվել"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Հեռացնել բոլորը"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Հեռացնել"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Գտնել"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Այս ծրագիրը տեղադրված չէ:"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Այս պատկերակի ծրագիրը տեղադրված չէ: Դուք կարող եք հեռացնել այն կամ գտնել ծրագիրը և տեղադրել այն ձեռքով:"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Ավելացնել Հիմնական էկրանին"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Տեղափոխել տարրն այստեղ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Տարրն ավելացվեց հիմնական էկրանին"</string>
+    <string name="item_removed" msgid="851119963877842327">"Տարրը հեռացվեց"</string>
+    <string name="action_move" msgid="4339390619886385032">"Տեղափոխել տարրը"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Տեղափոխել տող <xliff:g id="NUMBER_0">%1$s</xliff:g> սյունակ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Տեղափոխել դիրք <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Տեղափոխել նախընտրած դիրք՝ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Տարրը տեղափոխվեց"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Ավելացնել թղթապանակում՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Ավելացնել «<xliff:g id="NAME">%1$s</xliff:g>» պանակին"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Տարրն ավելացվեց թղթապանակում"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Ստեղծել թղթապանակ, օգտագործելով՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Թղթապանակը ստեղծվեց"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Տեղափոխել Հիմնական էկրան"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Տեղափոխել էկրանը ձախ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Տեղափոխել էկրանը աջ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Էկրանը տեղափոխվեց"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Չափափոխել"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Ավելացնել լայնությունը"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Ավելացնել բարձրությունը"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Նվազեցնել լայնությունը"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Նվազեցնել բարձրությունը"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Վիջեթի լայնությունը փոխվել է <xliff:g id="NUMBER_0">%1$s</xliff:g>-ի, իսկ բարձրությունը՝ <xliff:g id="NUMBER_1">%2$s</xliff:g>-ի"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index b0c5d13..c65254a 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Layar Utama"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplikasi Inti Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Kantor"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikasi tidak dipasang."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikasi tidak tersedia"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplikasi yang diunduh dinonaktifkan dalam mode Aman"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widget dinonaktifkan dalam mode Aman"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widget"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Tampilkan Memori"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh lama untuk memilih widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Tidak dapat melepas item ke layar Utama ini."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Pilih widget untuk membuat"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nama folder"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Ganti nama folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Oke"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Batal"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Tambahkan ke layar Utama"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikasi"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Pintasan"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widget"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Tidak ada ruang lagi di layar Utama Anda."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Telusuri Apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuat Aplikasi..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tidak ditemukan Aplikasi yang cocok dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tidak ada ruang tersisa di baki Favorit"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Widget ini terlalu besar untuk baki Favorit"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" sudah dibuat."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" telah dihapus."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" sudah ada."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Pilih pintasan"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Pilih aplikasi"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikasi"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Layar Utama"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Hapus"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Copot pemasangan"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Hapus"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Copot pemasangan"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Info aplikasi"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikasi"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Hapus"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Copot pemasangan pembaruan"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Copot aplikasi"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detail aplikasi"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplikasi dipilih"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget dipilih"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder dipilih"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 pintasan dipilih"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"memasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Mengizinkan aplikasi menambahkan pintasan tanpa campur tangan pengguna."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"mencopot pemasangan pintasan"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Mengizinkan aplikasi menghapus pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"membaca setelan dan pintasan layar Utama"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Mengizinkan aplikasi membaca setelan dan pintasan di layar Utama."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"menulis setelan dan pintasan layar Utama"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Masalah memuat widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Siapkan"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat dicopot pemasangannya."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Layar utama %1$d"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Laman %1$d dari %2$d"</string>
     <string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
-    <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Laman aplikasi %1$d dari %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Laman widget %1$d dari %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Selamat Datang"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Serasa di rumah sendiri."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Buat lebih banyak layar untuk aplikasi dan folder"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Salin ikon aplikasi Anda"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Impor ikon dan folder dari layar Utama lama Anda?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"IKON SALIN"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"MULAI DARI AWAL"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Kelola ruang Anda"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Sentuh lama latar belakang untuk mengelola wallpaper, widget, dan setelan."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Wallpaper, widget, &amp; setelan"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Sentuh &amp; tahan latar belakang untuk menyesuaikan"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"MENGERTI"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ini adalah folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Untuk membuat seperti yang ini, sentuh lama aplikasi, lalu pindahkan ke atas aplikasi lain."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Oke"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Sentuh untuk menutup folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Sentuh untuk menyimpan ganti nama"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Wallpaper"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Setelan"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Menunggu"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Mengunduh"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Memasang"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Izinkan putaran"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Tidak dikenal"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Tak dipulihkan"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Buang Semua"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Buang"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Telusuri"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikasi ini belum terpasang"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikasi untuk ikon ini belum dipasang. Anda dapat membuangnya, atau menelusuri aplikasi dan memasangnya secara manual."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Tambahkan ke layar Utama"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Pindahkan item ke sini"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan ke layar utama"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item dihapus"</string>
+    <string name="action_move" msgid="4339390619886385032">"Pindahkan item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Pindahkan ke baris <xliff:g id="NUMBER_0">%1$s</xliff:g> kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"PIndahkan ke posisi <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pindahkan ke posisi favorit <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item dipindahkan"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Tambahkan ke folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Tambahkan ke folder dengan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item ditambahkan ke folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Pindahkan ke layar Utama"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Pindahkan layar ke kiri"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Pindahkan layar ke kanan"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Layar dipindahkan"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ubah ukuran"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Tambahi lebar"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Tambahi tinggi"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Kurangi lebar"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Kurangi tinggi"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget diubah ukurannya menjadi lebar <xliff:g id="NUMBER_0">%1$s</xliff:g> tinggi <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index a3fa0bc..1d46cdc 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Heim"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Kjarnaforrit Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Vinna"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Forritið er ekki uppsett."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Forritið er ekki í boði"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Sótt forrit er óvirkt í öryggisstillingu"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Græjur eru óvirkar í öruggri stillingu"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Græjur"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Græjur"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Sýna minni"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Haltu fingri á græju til að grípa hana."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Ekki er hægt að sleppa atriði á þennan heimaskjá."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Veldu græju til að búa til"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Möppuheiti"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Endurnefna möppu"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Í lagi"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Hætta við"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Bæta á heimaskjá"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Forrit"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Flýtileiðir"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Græjur"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Heimaskjáirnir þínir eru fullskipaðir."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Leita í forritum"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Hleður forrit…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ekki fundust forrit sem samsvara „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Ekki meira pláss á þessum heimaskjá."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ekki meira pláss í bakka fyrir uppáhald"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Þessi græja er of stór fyrir bakkann fyrir uppáhald"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ var búin til."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ var fjarlægð."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Flýtileiðin „<xliff:g id="NAME">%s</xliff:g>“ er þegar til."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Veldu flýtileið"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Veldu forrit"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Forrit"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Heim"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Fjarlægja"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Eyða"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Fjarlægja"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Eyða"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Upplýsingar um forrit"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Forrit"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Fjarlægja"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Fjarlægja uppfærslu"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Fjarlægja forrit"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Upplýsingar um forrit"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 forrit valið"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 græja valin"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 mappa valin"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 flýtileið valin"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"setja upp flýtileiðir"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Leyfir forriti að bæta við flýtileiðum án íhlutunar notanda."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"fjarlægja flýtileiðir"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Leyfir forriti að fjarlægja flýtileiðir án íhlutunar notanda."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lesa stillingar og flýtileiðir heimaskjás"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Leyfir forriti að lesa stillingar og flýtileiðir heimaskjás."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"skrifa stillingar og flýtileiðir heimaskjás"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Vandamál við að hlaða græju"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Uppsetning"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Þetta er kerfisforrit sem ekki er hægt að fjarlægja."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Eldflaugapallur"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ónefnd mappa"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Heimaskjár %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Forritasíða %1$d af %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Græjusíða %1$d af %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Komdu fagnandi"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Komdu þér vel fyrir."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Búðu til fleiri skjái fyrir forrit og möppur"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Afritaðu forritatáknin þín"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Flytja inn tákn og möppur af eldri heimaskjáum?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"AFRITA TÁKN"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"BYRJA UPP Á NÝTT"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Settu hlutina á sína staði"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Haltu inni á bakgrunni til að stjórna veggfóðri, græjum og stillingum."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Veggfóður, græjur og stillingar"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Haltu fingri á bakgrunninum til að sérsníða hann"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ÉG SKIL"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Hér er mappa"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Til að búa til svona skaltu draga forrit yfir á annað forrit."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Í lagi"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappa opnuð, <xliff:g id="WIDTH">%1$d</xliff:g> sinnum <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Snertu til að loka möppunni"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Snertu til að staðfesta nýtt heiti"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Græjur"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Veggfóður"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Stillingar"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Bíður"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Sækir"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Setur upp"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Leyfa snúning"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Óþekkt"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ekki endurheimt"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Fjarlægja öll"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjarlægja"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Leita"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Þetta forrit er ekki uppsett"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Forritið fyrir þetta tákn er ekki uppsett. Þú getur fjarlægt það eða leitað að forritinu og sett það upp handvirkt."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Bæta á heimaskjá"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Færa atriði hingað"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Atriði bætt á heimaskjáinn"</string>
+    <string name="item_removed" msgid="851119963877842327">"Atriði fjarlægt"</string>
+    <string name="action_move" msgid="4339390619886385032">"Færa atriði"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Færa í línu <xliff:g id="NUMBER_0">%1$s</xliff:g>, dálk <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Færa í stöðu <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Færa í stöðu <xliff:g id="NUMBER">%1$s</xliff:g> á festisvæði"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Atriði fært"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Setja í möppu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Setja í möppu með <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Atriði sett í möppu"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Búa til möppu með: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mappa búin til"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Færa á heimaskjá"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Færa skjá til vinstri"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Færa skjá til hægri"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skjár færður"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Breyta stærð"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Auka breidd"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Auka hæð"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Minnka breidd"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Minnka hæð"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Stærð græju breytt í <xliff:g id="NUMBER_0">%1$s</xliff:g> á breidd og <xliff:g id="NUMBER_1">%2$s</xliff:g> á hæð"</string>
 </resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index d78d032..02057a1 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home page"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Applicazioni di base Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Lavoro"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App non installata."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App non disponibile"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'app scaricata è stata disattivata in modalità provvisoria"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widget disabilitati in modalità provvisoria"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widget"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostra Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tocca e tieni premuto per scegliere un widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Rilascio elemento in schermata Home non riuscito."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Scegli il widget da creare"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nome cartella"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Rinomina cartella"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Annulla"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Aggiungi a schermata Home"</string>
-    <string name="group_applications" msgid="3797214114206693605">"App"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Scorciatoie"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widget"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Spazio nelle schermate Home esaurito."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cerca app"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Caricamento di app…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nessuna app trovata corrispondente a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Spazio nella schermata Home esaurito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spazio esaurito nella barra dei Preferiti"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Questo widget è troppo grande per la barra dei Preferiti"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Scorciatoia \"<xliff:g id="NAME">%s</xliff:g>\" creata."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"La scorciatoia \"<xliff:g id="NAME">%s</xliff:g>\" è stata rimossa."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Scorciatoia \"<xliff:g id="NAME">%s</xliff:g>\" già presente."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Scegli scorciatoia"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Scegli app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"App"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home page"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Rimuovi"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Disinstalla"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Rimuovi"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Disinstalla"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informazioni app"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"App"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Rimuovi"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Disinstalla aggiornamento"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Disinstalla app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Dettagli sull\'app"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app selezionata"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selezionato"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 cartella selezionata"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 scorciatoia selezionata"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"aggiunta di scorciatoie"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Consente a un\'app di aggiungere scorciatoie automaticamente."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"eliminazione di scorciatoie"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Consente all\'app di rimuovere scorciatoie automaticamente."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lettura di impostazioni e scorciatoie in Home"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Consente all\'app di leggere le impostazioni e le scorciatoie in Home."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"creazione di impostazioni e scorciatoie in Home"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Errore durante il caricamento del widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configurazione"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Questa è un\'app di sistema e non può essere disinstallata."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Lanciamissili"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Cartella senza nome"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Schermata Home %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Pagina di applicazioni %1$d di %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Pagina di widget %1$d di %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Benvenuto"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Personalizza la schermata Home."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Creare più schermate per app e cartelle"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copia le icone delle tue app"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importare icone e cartelle dalle schermate Home precedenti?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIA ICONE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"RICOMINCIA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizza il tuo spazio"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Tocca e tieni premuto lo sfondo per gestire sfondi, widget e impostazioni."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Sfondi, widget e impostazioni"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tocca lo sfondo e tieni premuto per personalizzare"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ecco una cartella"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Per crearne una simile, tocca un\'app e tieni premuto, dopodiché spostala sopra un\'altra."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Cartella aperta, <xliff:g id="WIDTH">%1$d</xliff:g> per <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Tocca per chiudere la cartella"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Tocca per salvare nuovo nome"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Sfondi"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Impostazioni"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"In attesa"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Download..."</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installazione..."</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Consenti rotazione"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Sconosciuto"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Non ripristinato"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Rimuovi tutto"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Rimuovi"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Cerca"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"L\'app non è installata"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'app per questa icona non è installata. Puoi rimuoverla o cercare l\'app e installarla manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Aggiungi a schermata Home"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Sposta elemento qui"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elemento aggiunto alla schermata Home"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elemento rimosso"</string>
+    <string name="action_move" msgid="4339390619886385032">"Sposta elemento"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Sposta a riga <xliff:g id="NUMBER_0">%1$s</xliff:g>, colonna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Sposta nella posizione <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Sposta nella posizione <xliff:g id="NUMBER">%1$s</xliff:g> dei preferiti"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elemento spostato"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Aggiungi alla cartella: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Aggiungi a cartella con <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elemento aggiunto alla cartella"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Crea cartella con: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Cartella creata"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Sposta nella schermata Home"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Sposta schermata a sinistra"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Sposta schermata a destra"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Schermata spostata"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ridimensiona"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumenta larghezza"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumenta altezza"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Riduci larghezza"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Riduci altezza"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget ridimensionato a larghezza <xliff:g id="NUMBER_0">%1$s</xliff:g>, altezza <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 61fb53e..a8039f7 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"דף הבית"</string>
-    <string name="uid_name" msgid="7820867637514617527">"‏אפליקציות הליבה של Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"עבודה"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"האפליקציה לא מותקנת."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"האפליקציה אינה זמינה"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"אפליקציה שהורדת הושבתה במצב בטוח"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ווידג\'טים מושבתים במצב בטוח"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"רכיבי ווידג\'ט"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"רכיבי ווידג\'ט"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"הצג זכרון"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"גע נגיעה רציפה בווידג\'ט כדי לבחור בו."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"לא ניתן היה לשחרר את הפריט במסך דף הבית הזה."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"בחר ווידג\'ט ליצירה"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"שם תיקיה"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"שנה את שם התיקיה"</string>
-    <string name="rename_action" msgid="5559600076028658757">"אישור"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"בטל"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"הוסף למסך דף הבית"</string>
-    <string name="group_applications" msgid="3797214114206693605">"אפליקציות"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"קיצורי דרך"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"רכיבי ווידג\'ט"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"אין יותר מקום במסכי דף הבית."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"חפש אפליקציות"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"טוען אפליקציות…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"לא נמצאו אפליקציות התואמות ל-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"אין עוד מקום במסך דף הבית הזה."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"אין עוד מקום במגש המועדפים"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"הווידג\'ט הזה גדול מדי עבור מגש המועדפים."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"קיצור הדרך \'<xliff:g id="NAME">%s</xliff:g>\' נוצר."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"קיצור הדרך \'<xliff:g id="NAME">%s</xliff:g>\' הוסר."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"קיצור הדרך \'<xliff:g id="NAME">%s</xliff:g>\' כבר קיים."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"בחר קיצור דרך"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"בחר אפליקציה"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"אפליקציות"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"דף הבית"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"הסר"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"הסר התקנה"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"הסר"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"הסר התקנה"</string>
     <string name="info_target_label" msgid="8053346143994679532">"פרטי אפליקציה"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"אפליקציות"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"הסר"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"הסר את התקנת העדכון"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"הסר את התקנת האפליקציה"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"פרטי האפליקציה"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"נבחרה אפליקציה אחת"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"נבחר ווידג\'ט אחד"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"נבחרה תיקיה אחת"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"נבחר קיצור דרך אחד"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"התקן קיצורי דרך"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"מאפשר לאפליקציה להוסיף קיצורי דרך ללא התערבות המשתמש."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"הסר התקנה של קיצורי דרך"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"מאפשר לאפליקציה להסיר קיצורי דרך ללא התערבות המשתמש."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"קרא הגדרות וקיצורי דרך של דף הבית"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"מאפשר לאפליקציה לקרוא את ההגדרות וקיצורי הדרך בדף הבית."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"כתוב הגדרות וקיצורי דרך של דף הבית"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"בעיה בטעינת ווידג\'ט"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"הגדר"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"זוהי אפליקציית מערכת ולא ניתן להסיר את התקנתה."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"תיקיה ללא שם"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"‏מסך דף הבית %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"‏דף אפליקציות %1$d מתוך %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"‏דף רכיבי ווידג\'ט ‏%1$d מתוך %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ברוכים הבאים"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"להרגיש בבית."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"צור מסכים נוספים עבור אפליקציות ותיקיות"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"העתקת סמלי האפליקציות שלך"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"האם לייבא סמלים ותיקיות ממסכי דף הבית הישנים שלך?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"העתק סמלים"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"התחל דף חדש"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ארגן את אזור העבודה שלך"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"גע נגיעה רציפה ברקע כדי לנהל את הטפט, רכיבי הווידג\'ט וההגדרות."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"טפטים, ווידג\'טים והגדרות"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"גע והחזק ברקע לביצוע התאמה אישית"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"הבנתי"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"הנה תיקייה"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"כדי ליצור תיקייה כזו, גע נגיעה רציפה באפליקציה, ולאחר מכן גרור ושחרר אותו על-גבי אפליקציה אחרת."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"אישור"</string>
     <string name="folder_opened" msgid="94695026776264709">"תיקיה פתוחה, <xliff:g id="WIDTH">%1$d</xliff:g> על <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"גע כדי לסגור את התיקיה"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"גע כדי לשמור את שינוי השם"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"רכיבי ווידג\'ט"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"טפטים"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"הגדרות"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"ממתין"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"מוריד"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"מתקין"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"אפשרות סיבוב"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"לא ידוע"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"לא שוחזרה"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"הסר את הכל"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"הסר"</string>
     <string name="abandoned_search" msgid="891119232568284442">"חפש"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"אפליקציה זו אינה מותקנת"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"האפליקציה של סמל זה אינה מותקנת. ניתן להסיר אותו, או לחפש את האפליקציה ולהתקין אותה ידנית."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"הוסף למסך דף הבית"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"העבר את הפריט לכאן"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"הפריט הועבר אל מסך דף הבית"</string>
+    <string name="item_removed" msgid="851119963877842327">"הפריט הוסר"</string>
+    <string name="action_move" msgid="4339390619886385032">"העבר את הפריט"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"העבר אל שורה <xliff:g id="NUMBER_0">%1$s</xliff:g> עמודה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"העבר אל מיקום <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"העבר אל מיקום <xliff:g id="NUMBER">%1$s</xliff:g> במועדפים"</string>
+    <string name="item_moved" msgid="4606538322571412879">"הפריט הועבר"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"הוסף לתיקייה: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"העבר אל התיקייה עם <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"הפריט נוסף לתיקייה"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"צור תיקייה עם: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"התיקייה נוצרה"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"העבר אל מסך דף הבית"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"הזז את המסך שמאלה"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"הזז את המסך ימינה"</string>
+    <string name="screen_moved" msgid="266230079505650577">"המסך הועבר"</string>
+    <string name="action_resize" msgid="1802976324781771067">"שנה גודל"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"הגדל רוחב"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"הגדל גובה"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"הקטן רוחב"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"הקטן גובה"</string>
+    <string name="widget_resized" msgid="9130327887929620">"גודל הווידג\'ט שונה - רוחב <xliff:g id="NUMBER_0">%1$s</xliff:g> גובה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ec872b8..ba58d88 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"ホーム"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"仕事用"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"このアプリはインストールされていません。"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"このアプリは使用できません"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ダウンロードしたアプリは、セーフモードでは無効です"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"セーフモードではウィジェットは無効です"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ウィジェット"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ウィジェット"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"メモリーを表示"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ウィジェットを追加するには押し続けます。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"このホーム画面にアイテムをドロップできませんでした"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"作成するウィジェットの選択"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"フォルダ名"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"フォルダ名を変更"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"キャンセル"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ホーム画面に追加"</string>
-    <string name="group_applications" msgid="3797214114206693605">"アプリ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ショートカット"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ウィジェット"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ホーム画面に空きスペースがありません。"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"アプリを検索"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"アプリを読み込んでいます…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"「<xliff:g id="QUERY">%1$s</xliff:g>」に一致するアプリは見つかりませんでした"</string>
     <string name="out_of_space" msgid="4691004494942118364">"このホーム画面に空きスペースがありません。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"お気に入りトレイに空きスペースがありません"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"このウィジェットはお気に入りトレイには大きすぎます"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"ショートカット「<xliff:g id="NAME">%s</xliff:g>」を作成しました。"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"ショートカット「<xliff:g id="NAME">%s</xliff:g>」を削除しました。"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"ショートカット「<xliff:g id="NAME">%s</xliff:g>」は既に存在します。"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"ショートカットを選択"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"アプリを選択"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"アプリ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ホーム"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"削除"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"アンインストール"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"削除"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"アンインストール"</string>
     <string name="info_target_label" msgid="8053346143994679532">"アプリ情報"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"アプリ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"削除"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"更新をアンインストール"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"アプリをアンインストール"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"アプリの詳細"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1つのアプリが選択されています"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1つのウィジェットが選択されています"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1つのフォルダが選択されています"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1つのショートカットが選択されています"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ショートカットのインストール"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ユーザー操作なしでショートカットを追加することをアプリに許可します。"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ショートカットのアンインストール"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ユーザー操作なしでショートカットを削除することをアプリに許可します。"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ホームの設定とショートカットの読み取り"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ホームの設定とショートカットの読み取りをアプリに許可します。"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ホームの設定とショートカットの書き込み"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ウィジェットを表示できません"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"セットアップ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"このシステムアプリはアンインストールできません。"</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"名前のないフォルダ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ホーム画面: %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"アプリの%1$d/%2$dページ"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ウィジェットの%1$d/%2$dページ"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ようこそ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ホームをカスタマイズします。"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"アプリとフォルダの画面をもっと作成します"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"アプリのアイコンをコピー"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"古いホーム画面からアイコンとフォルダをインポートしますか?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"アイコンをコピー"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"初期状態にリセットする"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"スペースを整理"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"壁紙、ウィジェット、設定を管理するには、背景を押し続けます。"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"壁紙、ウィジェット、設定"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"カスタマイズするにはバックグラウンドを押し続けます"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"これがフォルダです"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"これと同じフォルダを作成するには、アプリを押し続けてから別のアプリの上に移動します。"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"フォルダが開いています。<xliff:g id="WIDTH">%1$d</xliff:g>x<xliff:g id="HEIGHT">%2$d</xliff:g>の大きさです"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"タップしてフォルダを閉じます"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"タップして名前の変更を保存します"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ウィジェット"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"壁紙"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"設定"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"待機中"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ダウンロード中"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"インストール中"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"回転を許可"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"復元失敗"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"すべて削除"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"削除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"検索"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"このアプリはインストールされていません"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"このアイコンのアプリはインストールされていません。このアイコンは削除できます。または、手動でアプリを検索してインストールしください。"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ホーム画面に追加"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"アイテムをここに移動"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"アイテムをホーム画面に追加しました"</string>
+    <string name="item_removed" msgid="851119963877842327">"アイテムを削除しました"</string>
+    <string name="action_move" msgid="4339390619886385032">"アイテムを移動"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"行<xliff:g id="NUMBER_0">%1$s</xliff:g>、列<xliff:g id="NUMBER_1">%2$s</xliff:g>に移動"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"位置<xliff:g id="NUMBER">%1$s</xliff:g>に移動"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"お気に入りの位置<xliff:g id="NUMBER">%1$s</xliff:g>に移動"</string>
+    <string name="item_moved" msgid="4606538322571412879">"アイテムを移動しました"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"フォルダ「<xliff:g id="NAME">%1$s</xliff:g>」に追加"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g>のあるフォルダに追加"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"アイテムをフォルダに追加しました"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"「<xliff:g id="NAME">%1$s</xliff:g>」フォルダを作成"</string>
+    <string name="folder_created" msgid="6409794597405184510">"フォルダを作成しました"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ホーム画面に移動"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"画面を左に移動"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"画面を右に移動"</string>
+    <string name="screen_moved" msgid="266230079505650577">"画面を移動しました"</string>
+    <string name="action_resize" msgid="1802976324781771067">"サイズを変更"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"幅を広くする"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"高さを高くする"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"幅を狭くする"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"高さを低くする"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ウィジェットのサイズを幅<xliff:g id="NUMBER_0">%1$s</xliff:g>、高さ<xliff:g id="NUMBER_1">%2$s</xliff:g>に変更しました"</string>
 </resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index b96d3d2..07030d8 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"მთავარი"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android-ის ბირთვის აპები"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"სამუშაო"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"აპი არ არის დაყენებული."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"აპი მიუწვდომელია"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"უსაფრთხო რეჟიმში ჩამოტვირთული აპი გაუქმებულია"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"უსაფრთხო რეჟიმში ვიჯეტი გამორთულია"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ვიჯეტები"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ვიჯეტები"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem-ის ჩვენება"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"შეეხეთ და დააყოვნეთ ვიჯეტის ასარჩევად."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ერთეულის მთავარ ეკრანზე ჩაგდება ვერ მოხერხდა."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"აირჩიეთ ვიჯეტი შესაქმნელად"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"საქაღალდის სახელი"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"საქაღალდის გადარქმევა"</string>
-    <string name="rename_action" msgid="5559600076028658757">"კარგი"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"გაუქმება"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"მთავარ ეკრანზე დამატება"</string>
-    <string name="group_applications" msgid="3797214114206693605">"აპები"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"მალსახმობები"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ვიჯეტები"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"მთავარ ეკრანებზე ადგილი აღარ არის."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"აპების ძიება"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"აპები იტვირთება..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"„<xliff:g id="QUERY">%1$s</xliff:g>“-ის თანხვედრი აპები არ მოიძებნა"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ამ მთავარ ეკრანზე ადგილი აღარ არის."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"რჩეულების თაროზე ადგილი არ არის"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ეს ვიჯეტი ძალიან დიდია რჩეულების თაროსთვის"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"შეიქმნა მალსახმობი „<xliff:g id="NAME">%s</xliff:g>“."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"მასლახმობი „<xliff:g id="NAME">%s</xliff:g>“ წაშლილია."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"მალსახმობი „<xliff:g id="NAME">%s</xliff:g>“ უკვე არსებობს."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"აირჩიეთ მალსახმობი"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"აირჩიეთ აპი"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"აპები"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"მთავარი"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"წაშლა"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"დეინსტალაცია"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"წაშლა"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"დეინსტალაცია"</string>
     <string name="info_target_label" msgid="8053346143994679532">"აპის შესახებ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"აპები"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"წაშლა"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"განახლების დეინსტალაცია"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"აპის დეინსტალაცია"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"აპის შესახებ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"არჩეულია 1 აპი"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"არჩეულია 1 ვიჯეტი"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"არჩეულია 1 საქაღალდე"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"არჩეულია 1 მალსახმობი"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"მალსახმობების დაყენება"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"აპისთვის მალსახმობების დამოუკიდებლად დამატების უფლების მიცემა."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"მალსახმობების წაშლა"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"აპისთვის მალსახმობების დამოუკიდებლად წაშლის უფლების მიცემა."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვა"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"აპისთვის მთავარი ეკრანის პარამეტრებისა და მალსახმობების წაკითხვის უფლების მიცემა."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"მთავარი ეკრანის პარამეტრებისა და მალსახმობების ჩაწერა"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"პრობლემა ვიჯეტის ჩატვირთვისას"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"დაყენება"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ეს სისტემური აპია და მისი წაშლა შეუძლებელია."</string>
-    <string name="dream_name" msgid="1530253749244328964">"ფეიერვერკი"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"უსახელო საქაღალდე"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"მთავარი ეკრანი %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"აპების გვერდი %1$d, %2$d-დან"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ვიჯეტების გვერდი %1$d, %2$d-დან"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"მოგესალმებით"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"იგრძენით თავი საკუთარ სახლში"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"აპებისა და საქაღალდეებისთვის კიდევ ერთი ეკრანის შექმნა"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"თქვენი აპის ხატულების კოპირება"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"გსურთ, ძველი მთავარი ეკრანიდან ხატულების და საქაღ. იმპორტი?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ხატულების კოპირება"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"სტანდარტული განლაგება"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"თქვენი სივრცის ორგანიზება"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"თუ გსურთ ფონების, ვიჯეტების და პარამეტრების მართვა, შეეხეთ და არ აუშვათ ფონს."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ფონები, ვიჯეტები, &amp; პარამეტრები"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"მოსარგებად შეეხეთ &amp; დააყოვნეთ ფონზე"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"გასაგებია"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"აი, საქაღალდე"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ასეთის შესაქმნელად, შეეხეთ და დააყოვნეთ აპზე, ხოლო შემდეგ გადააჩოჩეთ შემდეგზე."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"კარგი"</string>
     <string name="folder_opened" msgid="94695026776264709">"საქაღალდე გახსნილია, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"შეეხეთ საქაღალდის დასახურად"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"შეეხეთ ახალი სახელის შესანახად"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ვიჯეტები"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ფონები"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"პარამეტრები"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"მოცდა..."</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ჩამოტვირთვა..."</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ინსტალაცია..."</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"როტაციის დაშვება"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"უცნობი"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"არ აღდგა"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ყველას ამოშლა"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ამოშლა"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ძიება"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ეს აპი დაყენებული არ არის"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ამ ხატულის აპი დაყენებული არ არის. შეგიძლიათ ამოშალოთ, ან მოიძიოთ აპი და ხელით მოახდინოთ მისი ინსტალაცია."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"მთავარ ეკრანზე დამატება"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ერთეულის გადაადგილება აქ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ერთეული დაემატა მთავარ ეკრანს"</string>
+    <string name="item_removed" msgid="851119963877842327">"ერთეული წაიშალა"</string>
+    <string name="action_move" msgid="4339390619886385032">"ერთეულის გადაადგილება"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"გადატანა რიგში <xliff:g id="NUMBER_0">%1$s</xliff:g> სვეტში <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"გადატანა <xliff:g id="NUMBER">%1$s</xliff:g> პოზიციაზე"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"გადატანა რჩეულთა პოზიციაზე <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ერთეული გადაადგილდა"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"საქაღალდეში დამატება: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"საქაღალდეში დამატება <xliff:g id="NAME">%1$s</xliff:g>-ით"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ერთეული დაემატა საქაღალდეს"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"საქაღალდის შექმნა ერთეულით: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"საქაღალდე შექმნილია"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"მთავარ ეკრანზე გადატანა"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"ეკრანის გადატანა მარცხნივ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"ეკრანის გადატანა მარჯვნით"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ეკრანი გადაადგილდა"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ზომის შეცვლა"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"სიგანის გაზრდა"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"სიმაღლის გაზრდა"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"სიგანის შემცირება"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"სიმაღლის შემცირება"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ვიჯეტის ზომები შეიცვალა: სიგანე <xliff:g id="NUMBER_0">%1$s</xliff:g> სიმაღლე <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index c5b5a62..e79c9ce 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Негізгі"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core қолданбалары"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Жұмыс"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Қолданба орнатылмаған."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Қолданба қол жетімді емес"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Жүктелген қолданба қауіпсіз режимде өшірілген"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Қауіпсіз режимде виджеттер өшіріледі"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеттер"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виджеттер"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Жадты көрсету"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетті таңдау үшін түртіп, мықтап ұстаңыз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Элементті осы Негізгі Экранға тастау орындалмады."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Жасақтау үшін виджет таңдау"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Қалта атауы"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Қалтаның атауын өзгерту"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Жарайды"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Өшіру"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Негізгі экранға қосу"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Қолданбалар"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Төте пернелер"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виджеттер"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Негізгі экранда орын жоқ."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Қолданбаларды іздеу"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Қолданбалар жүктелуде…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"«<xliff:g id="QUERY">%1$s</xliff:g>» сұрауына сәйкес келетін қолданбалар жоқ"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Бұл Негізгі экранда орын қалмады."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Қалаулылар науасында орын қалмады"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Бұл виджет Қалаулылар науасы үшін тым үлкен"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі жасақталды."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі алынды."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" төте пернесі бұрыннан бар."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Төте перне таңдау"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Қолданба таңдау"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Қолданбалар"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Негізгі"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Алып тастау"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Алмау"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Алып тастау"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Алмау"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Қолданба ақпары"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Қолданбалар"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Алып тастау"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Жаңартуды алмау"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Қолданбаны алып тастау"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Қолданба туралы толығырақ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 қолданба таңдалған"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виджет таңдалған"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 қалта таңдалған"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 төте перне таңдалған"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"төте пернелерді орнату"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді қосу мүмкіндігін береді."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"төте пернелерді алып тастау"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Қолданбаға пайдаланушының қатысуынсыз төте пернелерді алу мүмкіндігін береді."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Негізгі экрандағы параметрлер мен төте пернелерді оқу"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Қолданбаға Негізгі экрандағы параметрлер мен төте пернелерді оқу мүмкіндігін береді."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Негізгі экран параметрлері мен төте пернелерін жазу"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Виджетті жүктеу барысында мәселе орын алды"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Орнату"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бұл жүйе қолданбасы, сондықтан оны алу мүмкін емес."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Атауы жоқ қалта"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d негізгі экран"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d қолданба беті, барлығы %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d виджет беті, барлығы %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Қош келдіңіз"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Өзіңізді ыңғайлы сезініңіз."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Қолданбалар мен қалталар үшін көбірек экрандар жасау"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Қолданба таңбаларын көшіру"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Бұрынғы негізгі экрандарыңыздағы таңбалар мен қалталар импортталсын ба?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ТАҢБАЛАРДЫ КӨШІРУ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ЖАҢАДАН БАСТАУ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Кеңістікті реттеу"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Артқы фонды, виджеттерді және параметрлерді басқару үшін артқы шебін түртіп, мықтап ұстаңыз."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Тұсқағаздар, виджеттер және параметрлер"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Теңшеу үшін фонды түртіп, ұстап тұрыңыз"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ТҮСІНДІМ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Міне, қалта."</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Осы сияқты қалта жасау үшін, қолданбаны түртіп, мықтап ұстаңыз, одан кейін екіншісінің үстінен жылжытыңыз."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Жарайды"</string>
     <string name="folder_opened" msgid="94695026776264709">"Қалта ашылды, <xliff:g id="WIDTH">%1$d</xliff:g> және <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Қалтаны жабу үшін түртіңіз"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Өзгертілген атауын сақтау үшін түртіңіз"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Артқы фондар"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Параметрлер"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Күтілуде"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Жүктелуде"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Орнатылуда"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Айналуға рұқсат ету"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Белгісіз"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Қалп. кел-меді"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Барлығын алып тастау"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып тастау"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Іздеу"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Бұл қолданба орнатылмаған"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Осы белгіше үшін қолданба орнатылмаған. Оны жоюға болады немесе қолданбаны іздеп, қолмен орнатуға болады."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Негізгі экранға қосу"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Элементті мұнда жылжыту"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент негізгі экранға қосылды"</string>
+    <string name="item_removed" msgid="851119963877842327">"Элемент жойылды"</string>
+    <string name="action_move" msgid="4339390619886385032">"Элементті жылжыту"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>-жол, <xliff:g id="NUMBER_1">%2$s</xliff:g>-бағанға жылжыту"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-орынға жылжыту"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"<xliff:g id="NUMBER">%1$s</xliff:g> нөмірлі таңдаулы орынға жылжыту"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Элемент жылжытылды"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Қалтаға қосу: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> бар қалтаға қосу"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Элемент қалтаға қосылды"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Мына бар қалтаны жасау: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Қалта жасалды"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Негізгі экранға жылжыту"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Экранды солға жылжыту"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Экранды оңға жылжыту"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Экран жылжытылды"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Өлшемін өзгерту"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Енін арттыру"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Биіктігін арттыру"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Енін азайту"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Биіктігін азайту"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Виджет өлшемінің ені <xliff:g id="NUMBER_0">%1$s</xliff:g>, биіктігі <xliff:g id="NUMBER_1">%2$s</xliff:g> болып өзгертілді"</string>
 </resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 670ac70..9f7f537 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"ដើម"</string>
-    <string name="uid_name" msgid="7820867637514617527">"កម្មវិធី​​សំខាន់​ៗ​របស់ Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ការងារ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"មិន​បាន​ដំឡើង​កម្មវិធី។"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"មិន​មាន​កម្មវិធី"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"បាន​បិទ​កម្មវិធី​ដែល​បាន​ទាញ​យក​ក្នុង​របៀប​សុវត្ថិភាព"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"បាន​បិទ​ធាតុ​ក្រាហ្វិក​ក្នុង​របៀប​សុវត្ថិភាព"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ធាតុ​ក្រាហ្វិក"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ធាតុ​ក្រាហ្វិក"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"បង្ហាញ​ Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ប៉ះ &amp; សង្កត់ ដើម្បី​ជ្រើស​ធាតុ​ក្រាហ្វិក។"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"មិន​អាច​ទម្លាក់​ធាតុ​លើ​អេក្រង់​ដើម​នេះ​ទេ"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ជ្រើស​ធាតុ​ក្រាហ្វិក ដើម្បី​​​បង្កើត"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ឈ្មោះ​ថត"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ប្ដូរ​ឈ្មោះ​ថត"</string>
-    <string name="rename_action" msgid="5559600076028658757">"យល់ព្រម"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"បោះបង់"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"បន្ថែម​ទៅ​អេក្រង់​ដើម"</string>
-    <string name="group_applications" msgid="3797214114206693605">"កម្មវិធី"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ផ្លូវកាត់"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ធាតុ​ក្រាហ្វិក"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​រស់​អ្នក​ទៀត​ទេ។"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ស្វែងរកកម្មវិធី"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"កំពុងដំណើរការកម្មវិធី..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"គ្មានកម្មវិធីដែលត្រូវជាមួយ \"<xliff:g id="QUERY">%1$s</xliff:g>\" ទេ"</string>
     <string name="out_of_space" msgid="4691004494942118364">"គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​នេះ​ទៀត​ទេ។"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"គ្មាន​បន្ទប់​​ក្នុង​ថាស​និយម​ប្រើ"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ធាតុ​ក្រាហ្វិក​នេះ​ធំ​ពេក​សម្រាប់​ថាស​និយម​ប្រើ"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"បាន​បង្កើត​ផ្លូវកាត់ \"<xliff:g id="NAME">%s</xliff:g>\" ។"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"បាន​លុប​ផ្លូវកាត់ \"<xliff:g id="NAME">%s</xliff:g>\" ។"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"មាន​ផ្លូវកាត់ \"<xliff:g id="NAME">%s</xliff:g>\" រួច​ហើយ។"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"ជ្រើស​ផ្លូវកាត់"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"ជ្រើស​កម្មវិធី"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"កម្មវិធី"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ដើម"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"លុប​ចេញ"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"លុប"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"លុប​ចេញ"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"លុប"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ព័ត៌មាន​កម្មវិធី"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"កម្មវិធី"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"លុប​ចេញ"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"លុប​បច្ចុប្បន្នភាព"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"លុប​កម្មវិធី"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ព័ត៌មាន​លម្អិត​កម្មវិធី"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"បាន​ជ្រើស​កម្មវិធី ១"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"បាន​ជ្រើស​ធាតុ ១"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"បាន​ជ្រើស​ថត ១"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"បាន​ជ្រើស​ផ្លូវកាត់ ១"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ដំឡើង​ផ្លូវកាត់"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​បន្ថែម​ផ្លូវកាត់​ ដោយ​មិន​ចាំបាច់​​អំពើ​ពី​អ្នក​ប្រើ។"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"លុប​ផ្លូវកាត់"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​លុប​ផ្លូវកាត់​ដោយ​មិន​ចាំបាច់​អំពើ​ពី​អ្នក​ប្រើ។"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"អាន​ការ​កំណត់​ និង​ផ្លូវកាត់​​អេក្រង់​ដើម"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"អនុញ្ញាត​ឲ្យ​កម្មវិធី​អាន​ការ​កំណត់ និង​ផ្លូវកាត់​ក្នុង​អេក្រង់​ដើម។"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"សរសេរ​ការ​កំណត់ ​និង​ផ្លូវកាត់​​លើ​អេក្រង់​ដើម"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"បញ្ហា​ក្នុង​ការ​ផ្ទុក​ធាតុ​​ក្រាហ្វិក"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"រៀបចំ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"នេះ​​​ជា​កម្មវិធី​ប្រព័ន្ធ មិន​អាច​លុប​បាន​ទេ។"</string>
-    <string name="dream_name" msgid="1530253749244328964">"កម្មវិធី​ចាប់ផ្ដើម​រ៉ូកែត"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ថត​គ្មាន​ឈ្មោះ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"អេក្រង់​ដើម %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"ទំព័រ​កម្មវិធី %1$d នៃ %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ទំព័រ​ធាតុ​ក្រាហ្វិក ​%1$d នៃ %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"សូម​ស្វាគមន៍​"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ធ្វើ​ដោយ​ខ្លួន​ឯង​នៅ​លើ​អេក្រង់​ដើម។"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"បង្កើត​អេក្រង់​ច្រើន​សម្រាប់​កម្មវិធី​ ​និង​ថតឯកសារ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ចម្លង​រូបតំណាង​កម្មវិធី​របស់​អ្នក"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"នាំចូល​រូបតំណាង និង​ថត​ពី​អេក្រង់​ដើម​ចាស់​របស់​អ្នក?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"រូប​តំណាង​ច្បាប់​ចម្លង"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ចាប់ផ្ដើម​ធ្វើ​ឲ្យ​ស្រស់"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"រៀបចំ​ចន្លោះ​របស់​អ្នក"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ប៉ះ &amp; សង្កត់​លើ​ផ្ទៃ​ខាង​ក្រោម ដើម្បី​គ្រប់គ្រង​ផ្ទាំង​រូបភាព, ធាតុ​ក្រាហ្វិក និង​ការ​កំណត់។"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ផ្ទាំងរូបភាព,ធាតុក្រាហ្វិក &amp; ការកំណត់"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ប៉ះ &amp; សង្កត់​ផ្ទៃ​ខាង​ក្រោយ​ដើម្បី​ប្ដូរ​តាម​​តម្រូវ​ការ"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"យល់​ហើយ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"នេះ​ជា​ថត"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ដើម្បី​បង្កើត​មួយ​ដូច​នេះ ប៉ះ &amp; សង្កត់​​លើ​កម្មវិធី បន្ទាប់​មក​ផ្លាស់ទី​វា​ទៅ​លើ​ធាតុ​មួយ​ផ្សេង​ទៀត។"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"យល់ព្រម"</string>
     <string name="folder_opened" msgid="94695026776264709">"បាន​បើក​ថត <xliff:g id="WIDTH">%1$d</xliff:g> ដោយ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ប៉ះ ដើម្បី​បិទ​ថត"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"ប៉ះ ដើម្បី​រក្សាទុក​ការ​ប្ដូរ​ឈ្មោះ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ធាតុ​ក្រាហ្វិក"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ផ្ទាំង​រូបភាព"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ការកំណត់"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"រង់ចាំ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"​ទាញ​យក"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ដំឡើង"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"អនុញ្ញាតឲ្យបង្វិល"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"មិន​ស្គាល់"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"មិនបាន​​ស្តា​រ"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"លុបចេញ​​​ទាំងអស់"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"លុបចេញ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ស្វែងរក"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"មិន​បាន​ដំឡើង​កម្មវិធី​នេះ"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"មិន​បាន​ដំឡើង​កម្មវិធី​សម្រាប់​រូបតំណាង​នេះ។ អ្នក​អាច​លុប​វា ឬ​ស្វែងរក​កម្មវិធី និង​ដំឡើង​វា​ដោយ​ដៃ។"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"បន្ថែមទៅអេក្រង់ដើម"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ផ្លាស់ធាតុមកទីនេះ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ធាតុដែលត្រូវបានបន្ថែមទៅអេក្រង់ដើម"</string>
+    <string name="item_removed" msgid="851119963877842327">"ធាតុដែលបានដកចេញ"</string>
+    <string name="action_move" msgid="4339390619886385032">"ផ្លាស់ទីធាតុ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ផ្លាស់ទីទៅជួរដេកទី <xliff:g id="NUMBER_0">%1$s</xliff:g> ជួរឈរទី <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"ផ្លាស់ទីទៅទីតាំង <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ផ្លាស់ទីទៅការចូលចិត្តទីតាំងទី <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"បានផ្លាស់ទីធាតុ"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"បន្ថែមទៅថតឯកសារ៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"បន្ថែមទៅថតឯកសារដែលមានឈ្មោះ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"បានបន្ថែមធាតុទៅថតឯកសារ"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"បង្កើតថតឯកសារជាមួយ៖ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"បានបង្កើតថតឯកសារ"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ផ្លាស់ទៅអេក្រង់ដើម"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"រំកិលអេក្រង់ទៅខាងឆ្វេង"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"រំកិលអេក្រង់ទៅខាងស្តាំ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"អេក្រង់ដែលបានផ្លាស់ទី"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ប្ដូរទំហំ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"បង្កើនទទឹង"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"បង្កើនកម្ពស់"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"បន្ថយទទឹង"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"បន្ថយកម្ពស់"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ធាតុក្រាហ្វិកដែលបានប្តូរទំហំទៅទទឹងប្រវែង <xliff:g id="NUMBER_0">%1$s</xliff:g> កម្ពស់ប្រវែង <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index 7a07051..5cd8792 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"ಲಾಂಚರ್3"</string>
-    <string name="home" msgid="7658288663002113681">"ಮುಖಪುಟ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ಕೆಲಸ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾದ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್‌ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ಸುರಕ್ಷಿತ ಮೋಡ್‌ನಲ್ಲಿ ವಿಜೆಟ್‌ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ವಿಜೆಟ್‌ಗಳು"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ವಿಜೆಟ್‌ಗಳು"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"ಸ್ಮರಣೆ ತೋರಿಸು"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ವಿಜೆಟ್ ಅನ್ನು ಆರಿಸಿಕೊಳ್ಳಲು ಸ್ಪರ್ಶಿಸಿ &amp; ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಐಟಂ ಅನ್ನು ಬಿಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ರಚಿಸಲು ವಿಜೆಟ್‌ ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ಫೋಲ್ಡರ್ ಹೆಸರು"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ಫೋಲ್ಡರ್ ಅನ್ನು ಮರುಹೆಸರಿಸಿ"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ಸರಿ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ರದ್ದುಮಾಡು"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string>
-    <string name="group_applications" msgid="3797214114206693605">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ವಿಜೆಟ್‌ಗಳು"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ನಿಮ್ಮ ಮುಖಪುಟದ ಪರದೆಗಳಲ್ಲಿ ಯಾವುದೇ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ಅಪ್ಲಿಕೇಷನ್‌ಗಳನ್ನು ಹುಡುಕಿ"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇಗೆ ಈ ವಿಜೆಟ್‌ ತುಂಬಾ ದೊಡ್ಡದಾಗಿದೆ"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"ಶಾರ್ಟ್‌ಕಟ್‌ \"<xliff:g id="NAME">%s</xliff:g>\" ಅನ್ನು ರಚಿಸಲಾಗಿದೆ."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"ಶಾರ್ಟ್‌ಕಟ್‌ \"<xliff:g id="NAME">%s</xliff:g>\" ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"ಶಾರ್ಟ್‌ಕಟ್‌ \"<xliff:g id="NAME">%s</xliff:g>\" ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"ಶಾರ್ಟ್‌ಕಟ್‌ ಆರಿಸಿ"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"ಅಪ್ಲಿಕೇಶನ್ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ಮುಖಪುಟ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ತೆಗೆದುಹಾಕು"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ಅಸ್ಥಾಪಿಸು"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ತೆಗೆದುಹಾಕು"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ಅಸ್ಥಾಪಿಸು"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ತೆಗೆದುಹಾಕು"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ನವೀಕರಣವನ್ನು ಅಸ್ಥಾಪಿಸು"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ಅಪ್ಲಿಕೇಶನ್ ಅಸ್ಥಾಪಿಸು"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ಅಪ್ಲಿಕೇಶನ್ ವಿವರಗಳು"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ವಿಜೆಟ್‌ ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ಫೋಲ್ಡರ್‌ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ಶಾರ್ಟ್‌ಕಟ್‌ ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಅಸ್ಥಾಪಿಸಿ"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ಬಳಕೆದಾರರ ಹಸ್ತಕ್ಷೇಪವಿಲ್ಲದೆ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಓದಿ"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ಮುಖಪುಟದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿ ನೀಡುತ್ತದೆ."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ಮುಖಪುಟದ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಮತ್ತು ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಬರೆಯಿರಿ"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ವಿಜೆಟ್ ಲೋಡ್‌ ಮಾಡುವಲ್ಲಿ ಸಮಸ್ಯೆ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ಸೆಟಪ್"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
-    <string name="dream_name" msgid="1530253749244328964">"ರಾಕೆಟ್ ಲಾಂಚರ್"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ಹೆಸರಿಲ್ಲದ ಫೋಲ್ಡರ್"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ಮುಖಪುಟದ ಪರದೆ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d ರಲ್ಲಿ %1$d ಅಪ್ಲಿಕೇಶನ್ ಪುಟ"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d ರಲ್ಲಿ %1$d ವಿಜೆಟ್‌ಗಳ ಪುಟ"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ಸುಸ್ವಾಗತ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ನಿಮ್ಮ ಮನೆಯಂತೆ ಭಾವಿಸಿ."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಫೋಲ್ಡರ್‌ಗಳಿಗಾಗಿ ಇನ್ನಷ್ಟು ಪರದೆಗಳನ್ನು ರಚಿಸಿ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ಅಪ್ಲಿಕೇಶನ್‌ ಐಕಾನ್‌ ನಕಲಿಸು"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"ನಿಮ್ಮ ಹಳೆಯ ಮುಖಪುಟದ ಪರದೆಗಳಿಂದ ಐಕಾನ್‌ಗಳು ಮತ್ತು ಫೋಲ್ಡರ್‌ಗಳನ್ನು ಆಮದು ಮಾಡಿಕೊಳ್ಳುವುದೇ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ಐಕಾನ್‌ಗಳನ್ನು ನಕಲಿಸು"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ಹೊಸದಾಗಿ ಪ್ರಾರಂಭಿಸು"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ನಿಮ್ಮ ಸ್ಥಳವನ್ನು ವ್ಯವಸ್ಥಿತಗೊಳಿಸಿ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ವಾಲ್‌ಪೇಪರ್‌, ವಿಜೆಟ್‌ಗಳು ಮತ್ತು ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಹಿನ್ನೆಲೆಯನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ವಾಲ್‌ಪೇಪರ್‌ಗಳು, ವಿಜೆಟ್‌ಗಳು, &amp; ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ಹಿನ್ನೆಲೆಯನ್ನು ಸ್ಪರ್ಶಿಸಿ &amp; ಒತ್ತಿ ಹಿಡಿಯಿರಿ"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ಅರ್ಥವಾಯಿತು"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ಇಲ್ಲೊಂದು ಫೋಲ್ಡರ್ ಇದೆ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ಈ ರೀತಿ ರಚಿಸಲು, ಸ್ಪರ್ಶಿಸಿ &amp; ಆಪ್‌ ಹಿಡಿದುಕೊಂಡು ಮತ್ತೊಂದರ ಮೇಲೆ ಸರಿಸಿ."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ಸರಿ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ಫೋಲ್ಡರ್ ತೆರೆಯಲಾಗಿದೆ, <xliff:g id="WIDTH">%1$d</xliff:g> ಬೈ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ಫೋಲ್ಡರ್‌ ಮುಚ್ಚಲು ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"ಮರುಹೆಸರನ್ನು ಉಳಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ವಿಜೆಟ್‌ಗಳು"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ವಾಲ್‌ಪೇಪರ್‌ಗಳು"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ಸ್ಥಾಪಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"ತಿರುಗಿಸುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"ಅಜ್ಞಾತ"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ಇನ್ನೂ ಪುನಃಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ಎಲ್ಲವನ್ನೂ ತೆಗೆದುಹಾಕಿ"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ಹುಡುಕು"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ಈ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ಈ ಐಕಾನ್ ಅಪ್ಲಿಕೇಶನ್ ಸ್ಥಾಪನೆಗೊಂಡಿಲ್ಲ. ನೀವು ಅದನ್ನು ತೆಗೆದುಹಾಕಬಹುದು ಅಥವಾ ಅಪ್ಲಿಕೇಶನ್ ಹುಡುಕಬಹುದು ಮತ್ತು ಹಸ್ತಚಾಲಿತವಾಗಿ ಅದನ್ನು ಸ್ಥಾಪಿಸಬಹುದು."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ಮುಖಪುಟಕ್ಕೆ ಸೇರಿಸು"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ಐಟಂ ಇಲ್ಲಿಗೆ ಸರಿಸಿ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ಮುಖಪುಟ ಪರದೆಗೆ ಐಟಂ ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="item_removed" msgid="851119963877842327">"ಐಟಂ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+    <string name="action_move" msgid="4339390619886385032">"ಐಟಂ ಸರಿಸಿ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> ಸಾಲು <xliff:g id="NUMBER_1">%2$s</xliff:g> ಕಾಲಮ್‌ಗೆ ಸರಿಸಿ"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ಮೆಚ್ಚಿನ <xliff:g id="NUMBER">%1$s</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ಐಟಂ ಸರಿಸಲಾಗಿದೆ"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ಫೋಲ್ಡರ್‌ಗೆ ಸೇರಿಸಿ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ಮೂಲಕ ಫೋಲ್ಡರ್‌ಗೆ ಸೇರಿಸಿ"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ಐಟಂ ಅನ್ನು ಫೋಲ್ಡರ್‌ಗೆ ಸೇರಿಸಲಾಗಿದೆ"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಲ್ಡರ್ ರಚಿಸಿ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ಫೋಲ್ಡರ್ ರಚಿಸಲಾಗಿದೆ"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ಮುಖಪುಟಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"ಪರದೆಯನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"ಪರದೆಯನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ಪರದೆ ಸರಿಸಲಾಗಿದೆ"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ಮರುಗಾತ್ರ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"ಅಗಲವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ಎತ್ತರವನ್ನು ಹೆಚ್ಚು ಮಾಡಿ"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ಅಗಲವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ವಿಜೆಟ್ ಅನ್ನು <xliff:g id="NUMBER_0">%1$s</xliff:g> ಅಗಲ <xliff:g id="NUMBER_1">%2$s</xliff:g> ಎತ್ತರಕ್ಕೆ ಮರುಗಾತ್ರಗೊಳಿಸಲಾಗಿದೆ"</string>
 </resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index c73b431..fa445ac 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"홈"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android 핵심 앱"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"업무"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"앱이 설치되지 않았습니다."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"앱을 사용할 수 없음"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"다운로드한 앱은 안전 모드에서 사용할 수 없습니다."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"안전 모드에서 위젯 사용 중지됨"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"위젯"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"위젯"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"메모리 표시"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"위젯을 선택하려면 길게 터치하세요."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"홈 화면에 항목을 놓을 수 없습니다."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"만들 위젯 선택"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"폴더 이름"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"폴더 이름 바꾸기"</string>
-    <string name="rename_action" msgid="5559600076028658757">"확인"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"취소"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"홈 화면에 추가"</string>
-    <string name="group_applications" msgid="3797214114206693605">"앱"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"바로가기"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"위젯"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"홈 화면에 더 이상 공간이 없습니다."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"앱 검색"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"앱 로드 중..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\'<xliff:g id="QUERY">%1$s</xliff:g>\'와(과) 일치하는 앱이 없습니다."</string>
     <string name="out_of_space" msgid="4691004494942118364">"홈 화면에 더 이상 공간이 없습니다."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"즐겨찾기 트레이에 더 이상 공간이 없습니다."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"위젯이 너무 커서 즐겨찾기 트레이에 들어갈 수 없습니다."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"바로가기(\'<xliff:g id="NAME">%s</xliff:g>\')가 생성되었습니다."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"바로가기(\'<xliff:g id="NAME">%s</xliff:g>\')가 삭제되었습니다."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"바로가기(\'<xliff:g id="NAME">%s</xliff:g>\')가 이미 있습니다."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"바로가기 선택"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"앱 선택"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"앱"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"홈"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"삭제"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"제거"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"삭제"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"제거"</string>
     <string name="info_target_label" msgid="8053346143994679532">"앱 정보"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"앱"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"삭제"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"업데이트 제거"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"앱 제거"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"앱 세부정보"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"앱 1개 선택됨"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"위젯 1개 선택됨"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"폴더 1개 선택됨"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"바로가기 1개 선택됨"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"바로가기 설치"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"앱이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"바로가기 제거"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"앱이 사용자의 작업 없이 바로가기를 삭제할 수 있도록 합니다."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"홈 설정 및 바로가기 읽기"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"앱이 홈에 있는 설정 및 바로가기를 읽을 수 있도록 합니다."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"홈 설정 및 바로가기 쓰기"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"위젯을 로드하는 중 문제가 발생했습니다."</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"설정"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"시스템 앱은 제거할 수 없습니다."</string>
-    <string name="dream_name" msgid="1530253749244328964">"로켓 실행기"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"이름이 없는 폴더"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"홈 화면 %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"앱 페이지 %1$d/%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"위젯 페이지 %1$d/%2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"환영합니다."</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"편리한 사용 환경을 만드세요."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"앱 및 폴더를 표시할 화면 더 만들기"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"앱 아이콘 복사"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"이전 메인 스크린에서 아이콘과 폴더를 가져오시겠습니까?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"아이콘 복사"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"새로 시작"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"공간 관리하기"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"배경화면, 위젯, 설정을 관리하려면 백그라운드를 길게 터치합니다."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"배경화면, 위젯, 설정"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"백그라운드를 길게 터치하여 맞춤설정합니다."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"확인"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"폴더"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"폴더를 만들려면 앱을 길게 터치한 다음 다른 앱 위에 올려 놓으세요."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"확인"</string>
     <string name="folder_opened" msgid="94695026776264709">"폴더 열림(<xliff:g id="WIDTH">%1$d</xliff:g>X<xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"터치하여 폴더를 닫음"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"터치하여 바꾼 이름을 저장"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"위젯"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"배경화면"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"설정"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"대기 중"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"다운로드 중"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"설치 중"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"회전 허용"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"알 수 없음"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"복원되지 않음"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"모두 삭제"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"삭제"</string>
     <string name="abandoned_search" msgid="891119232568284442">"검색"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"이 앱이 설치되어 있지 않음"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"이 아이콘의 앱이 설치되어 있지 않습니다. 아이콘을 삭제하거나 앱을 검색하여 수동으로 설치하세요."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"메인 스크린에 추가"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"여기에 항목을 이동"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"메인 스크린에 항목 추가됨"</string>
+    <string name="item_removed" msgid="851119963877842327">"항목 삭제됨"</string>
+    <string name="action_move" msgid="4339390619886385032">"항목 이동"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>행 <xliff:g id="NUMBER_1">%2$s</xliff:g>열로 이동"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>번 위치로 이동"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"즐겨찾는 <xliff:g id="NUMBER">%1$s</xliff:g>번 위치로 이동"</string>
+    <string name="item_moved" msgid="4606538322571412879">"항목을 이동했습니다."</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"폴더에 추가: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g>이(가) 포함된 폴더에 추가"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"항목이 폴더에 추가되었습니다."</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"다음이 포함된 폴더 만들기: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"폴더를 만들었습니다."</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"메인 스크린으로 이동"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"화면을 왼쪽으로 이동"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"화면을 오른쪽으로 이동"</string>
+    <string name="screen_moved" msgid="266230079505650577">"화면 이동됨"</string>
+    <string name="action_resize" msgid="1802976324781771067">"크기 조정"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"폭 늘리기"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"높이 늘리기"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"폭 줄이기"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"높이 줄이기"</string>
+    <string name="widget_resized" msgid="9130327887929620">"폭 <xliff:g id="NUMBER_0">%1$s</xliff:g>, 높이 <xliff:g id="NUMBER_1">%2$s</xliff:g>로 위젯 크기 조정됨"</string>
 </resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index a8a605b..2078748 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Үйгө"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core колдонмолору"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Жумуш"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Колдонмо орнотулган эмес."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Колдонмо жеткиликтүү эмес"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Жүктөп алынган колдонмо Коопсуз режиминде иштен чыгарылды"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Виджеттер Коопсуз режимде өчүрүлгөн"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеттер"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виджеттер"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Мемди көргөзүү"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетти тандаш үчүн, басып туруңуз"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Муну бул Үй экранына ыргытуу мүмкүн эмес."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Түзүлүүчү виджетти тандаңыз"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Фолдердин аты"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Фолдердин атын өзгөртүү"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Жокко чыгаруу"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Үй экранына кошуу"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Колдонмолор"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Тез чакырмалар"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виджеттер"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Үй экрандарыңызда бош орун калган жок."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Колдонмолорду издөө"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Колдонмолор жүктөлүүдө…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" дал келген колдонмолор табылган жок"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Бул Үй экранында бош орун жок."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Тандамалдар тайпасында орун калган жок"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Бул виджет Тандамалдар үчүн өтө чоң"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы түзүлдү."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы алынып салынды."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" тез чакырмасы бар."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Тез чакырма тандоо"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Колдонмо тандоо"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Колдонмолор"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Үйгө"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Алып салуу"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Чечип салуу"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Алып салуу"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Чечип салуу"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Колдонмо тууралуу"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Колдонмолор"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Алып салуу"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Жаңыртууну чечип салуу"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Колдонмону чечип салуу"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Колдонмонун кеңири маалыматтары"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 колдонмо тандалды"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виджет тандалды"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 фолдер тандалды"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 тез чакырма тандалды"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"тез чакырмаларды орнотуу"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Колдонмого колдонуучуга кайрылбастан тез чакырма кошууга уруксат берет."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"тез чакырмаларды жок кылуу"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Колдонмого колдонуучуга кайрылбастан тез чакырмаларды жок кылууга уруксат берет."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Үйдүн тууралоолорун жана тез чакырмаларын окуу"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Колдонмого Үйдүн тууралоолорун жана тез чакырмаларын окууга уруксат берет."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Үйдүн тууралоолорун жана тез чакырмаларын жазуу"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Виджетти жүктөөдө маселе бар"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Орнотуу"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Бул системдик колдонмо жана аны чечкенге болбойт."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Аты жок фолдер"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Үй экраны %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Колдонмолор барагы %2$d ичинен %1$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Виджеттер барагы %2$d ичинен %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Кош келиңиз"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Өзүңүздү үйүңүздөгүдөй эркин сезиңиз."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Колдонмолор жана фолдерлер үчүн кошумча экрандарды түзүңүз"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Колдонмоңуздун сүрөтчөлөрүн көчүрүү"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Эски үй экрандарыңыздан сүрөтчөлөр жана фолдерлер импорттолсунбу?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"СҮРӨТЧӨЛӨРДҮ КӨЧҮРҮҮ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ТАЗАСЫН БАШТОО"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Өз мейкиндигиңизди уюштуруңуз"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Тушкагаздарды, виджеттерди жана тууралоолорду башкаруу үчүн фонду басып туруңуз."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Тушкагаздар, виджеттер &amp; жөндөөлөр"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Өзгөчөлөштүрүү үчүн фонго тийип &amp; коё бербей туруңуз"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ТҮШҮНДҮМ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Мынакей фолдер"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Башкасын түзүш үчүн колдонмону басып туруп, башканын жанына жылдырыңыз."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Фолдер ачылды, туурасы <xliff:g id="WIDTH">%1$d</xliff:g>, бийиктиги <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Фолдерди жабыш үчүн тийиңиз"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Тийип, аттын өзгөртүлүшүн сактаңыз"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виджеттер"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тушкагаздар"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Тууралоолор"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Күтүүдө"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Жүктөлп алнууда"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Орнотулууда"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Айлантууга уруксат берүү"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Белгисиз"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Калыбн келт. жок"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Баарын алып салуу"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Алып салуу"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Издөө"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Бул колдонмо орнотулган эмес"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Бул сүрөтчөнүн колдонмосу орнотулган эмес. Аны алып салсаңыз же колдонмону издеп, кол менен орнотсоңуз болот."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Башкы экранга кошуу"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Бул нерсени бул жерге жылдыруу"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Башкы экранга кошулду"</string>
+    <string name="item_removed" msgid="851119963877842327">"Жоюлду"</string>
+    <string name="action_move" msgid="4339390619886385032">"Муну жылдыруу"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> катарга <xliff:g id="NUMBER_1">%2$s</xliff:g> тилкеге жылдыруу"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> орунга жылдыруу"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Сүйүктүүлөргө <xliff:g id="NUMBER">%1$s</xliff:g> жылдыруу"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Нерсе жылдырылды"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Куржунга кошуу: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> куржунуна кошуу"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Нерсе куржунга кошулду"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Төмөнкү менен куржун түзүү: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Куржун түзүлдү"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Башкы экранга жылдыруу"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Экранды солго жылдыруу"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Экранды оңго жылдыруу"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Экран жылдырылды"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Өлчөмүн өзгөртүү"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Кеңейтүү"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Бийиктетүү"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Ичкертүү"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Жапыздатуу"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Виджеттин кеңдиги <xliff:g id="NUMBER_0">%1$s</xliff:g> бийиктиги <xliff:g id="NUMBER_1">%2$s</xliff:g> болду"</string>
 </resources>
diff --git a/res/values-land/config.xml b/res/values-land/config.xml
deleted file mode 100644
index 31115c9..0000000
--- a/res/values-land/config.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-<!-- Workspace -->
-    <!-- Whether or not the drop targets drop down as opposed to fade in -->
-    <bool name="config_useDropTargetDownTransition">false</bool>
-</resources>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 1b34181..06a9984 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -18,9 +18,4 @@
 <!-- QSB -->
     <dimen name="toolbar_button_vertical_padding">8dip</dimen>
     <dimen name="toolbar_button_horizontal_padding">0dip</dimen>
-
-<!-- AppsCustomize -->
-    <dimen name="apps_customize_tab_bar_height">42dp</dimen>
-    <integer name="apps_customize_widget_cell_count_x">3</integer>
-    <integer name="apps_customize_widget_cell_count_y">2</integer>
 </resources>
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
index 8a255c9..c5a76d5 100644
--- a/res/values-land/styles.xml
+++ b/res/values-land/styles.xml
@@ -28,7 +28,7 @@
     </style>
 
     <!-- This style applies to the drop target when it is shown in the sidebar -->
-    <style name="DropTargetButton" parent="DropTargetButton.Base">
+    <style name="DropTargetButton" parent="DropTargetButtonBase">
         <item name="android:layout_height">wrap_content</item>
         <item name="android:gravity">center</item>
         <item name="android:drawablePadding">0dp</item>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 1beb049..dff2612 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"ໜ້າຫຼັກ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"ແອັບພລິເຄຊັນຫຼັກຂອງ Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ວຽກ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ແອັບຯບໍ່ໄດ້ຖືກຕິດຕັ້ງ."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ແອັບຯ​ໃຊ້​ບໍ່​ໄດ້"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ແອັບຯ​ທີ່​ດາວ​ໂຫລດ​ແລ້ວ​ຖືກ​ປິດ​ການ​ນຳ​ໃຊ້​ໃນ Safe mode"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"​ວິດ​ເຈັດ​ຖືກ​ປິດ​ໃນ Safe mode"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ວິດເຈັດ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ວິດເຈັດ"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"ສະແດງຄວາມຈຳ"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ສຳພັດຄ້າງໄວ້ ເພື່ອຈັບວິດເຈັດ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ບໍ່ສາມາດວາງລາຍການໃສ່ໜ້າຈໍຫຼັກນີ້ໄດ້"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ເລືອກວິດເຈັດເພື່ອສ້າງມັນ"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ຊື່ໂຟນເດີ"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ປ່ຽນຊື່ໂຟນເດີ"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ຕົກລົງ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ຍົກ​ເລີກ​"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ເພີ່ມໃສ່ໜ້າຈໍຫຼັກ"</string>
-    <string name="group_applications" msgid="3797214114206693605">"ແອັບຯ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ທາງລັດ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ວິດເຈັດ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກຂອງທ່ານ."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ຊອກຫາແອັບ"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"​ກຳ​ລັງ​ໂຫລດ​ແອັບ..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"ບໍ່​ພົບ​ແອັບ​ໃດ​ທີ່​ກົງ​ກັນ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ວິດເຈັດນີ້ໃຫຍ່ເກີນໄປທີ່ຈະເກັບໄວ້ໃນຖາດເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"ທາງລັດ \"<xliff:g id="NAME">%s</xliff:g>\" ຖືກສ້າງແລ້ວ."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"ທາງລັດ \"<xliff:g id="NAME">%s</xliff:g>\" ຖືກລຶບແລ້ວ."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"ທາງລັດ \"<xliff:g id="NAME">%s</xliff:g>\" ມີຢູ່ແລ້ວ."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"ເລືອກທາງລັດ"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"ເລືອກແອັບຯ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ແອັບຯ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ໜ້າຫຼັກ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ລຶບ"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ຖອນ​ການ​ຕິດ​ຕັ້ງ"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ລຶບ"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ຖອນ​ການ​ຕິດ​ຕັ້ງ"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ຂໍ້ມູນແອັບຯ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ແອັບຯ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ລຶບ"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ຖອນອັບເດດ"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ຖອນແອັບຯ"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ລາຍລະອຽດແອັບຯ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ແອັບຯຖືກເລືອກ"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ວິດເຈັດຖືກເລືອກ"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ໂຟນເດີຖືກເລືອກ"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ທາງລັດຖືກເລືອກ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ຕິດຕັ້ງທາງລັດ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ອະນຸຍາດໃຫ້ແອັບຯ ເພີ່ມທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ຖອນທາງລັດ"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວ ລຶບທາງລັດໂດຍບໍ່ຕ້ອງຮັບການຢືນຢັນຈາກຜູ່ໃຊ້."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ອ່ານການຕັ້ງຄ່າໜ້າຫຼັກ ແລະທາງລັດ"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ອະນຸຍາດໃຫ້ແອັບຯດັ່ງກ່າວອ່ານການຕັ້ງຄ່າ ແລະທາງລັດໃນໜ້າຫຼັກ."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ຂຽນການຕັ້ງຄ່າໜ້າຫຼັກ ແລະທາງລັດ"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ມີບັນຫາໃນການໂຫລດວິດເຈັດ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ຕິດຕັ້ງ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ນີ້ແມ່ນແອັບຯຂອງລະບົບ ແລະບໍ່ສາມາດຖອນການຕິດຕັ້ງອອກໄດ້."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ໂຟນເດີຍັງບໍ່ຖືກຕັ້ງຊື່"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ໜ້າຈໍຫຼັກ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"ແອັບຯໜ້າ %1$d ໃນ %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ວິດເຈັດໜ້າ %1$d ໃນ %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ຍິນດີຕ້ອນຮັບ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ເຮັດໂຕໃຫ້ຄືຢູ່ໃນບ້ານ"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ສ້າງຈໍເພີ່ມເຕີມສຳລັບແອັບຯ ແລະໂຟນເດີ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ສຳເນົາໄອຄອນແອັບຯຂອງທ່ານ"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"ນຳເຂົ້າໄອຄອນ ແລະ ໂຟນເດີຈາກໂຮມສະກຣີນອັນເກົ່າຂອງທ່ານບໍ່?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ສຳເນົາໄອຄອນ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ເລີ່ມຕົ້ນໃໝ່"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ຈັດການພື້ນທີ່ຂອງທ່ານ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ແຕະຄ້າງໄວ້ທີ່ພາບພື້ນຫຼັງເພື່ອຈັດການພາບພື້ນຫຼັງ, ວິດເຈັດແລະການຕັ້ງຄ່າ."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"​ຮູບ​ພື້ນຫຼັງ, ວິດເຈັດ, &amp; ​ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ແຕະທີ່​ພາບ​ພື້ນ​ຫລັງ​ຄ້າງ​ໄວ້​ເພື່ອ​ປັບ​ແຕ່ງ"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ເຂົ້າໃຈແລ້ວ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ນີ້ແມ່ນໂຟນເດີ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ເພື່ອ​ສ້າງ​ອັນໃໝ່​ແບບນີ້ ໃຫ້​ແຕະ​ຄ້າງ​ໄວ້​ທີ່​ແອັບຯ​ທີ່​ຕ້ອງການ​ຍ້າຍ​ແລ້ວ​ລາກ​ມັນ​ໄປ​ຫາ​ໂຕ​ອື່ນ."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ຕົກລົງ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ເປີດໂຟນເດີແລ້ວ, <xliff:g id="WIDTH">%1$d</xliff:g> ຄູນ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ສຳພັດເພື່ອປິດໂຟນເດີ"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"ສຳພັດເພື່ອບັນທຶກການປ່ຽນຊື່"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ວິດເຈັດ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ພາບພື້ນຫຼັງ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ການຕັ້ງຄ່າ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"ກຳ​ລັງ​ລໍ​ຖ້າ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ກຳລັງດາວໂຫລດ"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"​ກຳ​ລັງ​ຕິດ​ຕັ້ງ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"ອະ​ນຸ​ຍາດ​ການ​ໝຸນ"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"​ບໍ່​ຮູ້​ຈັກ"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ບໍ່​ໄດ້​ກູ້​ຂໍ້ມູນ​ມາ​ເທື່ອ"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ລຶບ​ທັງ​ໝົດ"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ລຶບ​"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ຊອກຫາ"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ແອັບຯ​ນີ້​ຍັງ​ບໍ່​ໄດ້​ຕິດ​ຕັ້ງ​ເທື່ອ"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"​ແອັບຯ​ສຳ​ລັບ​ໄອ​ຄອນ​ນີ້​ຍັງ​ບໍ່ໄດ້​ຕິດ​ຕັ້ງ​ເທື່ອ. ທ່ານ​ສາ​ມາດ​ລຶບ​ມັນ​ອອກ ຫຼື​ຊອກ​ຫາ​ແອັບຯ ແລ້ວ​ຕິດ​ຕັ້ງ​ມັນ​ໄດ້​ດ້ວຍ​ຕົນ​ເອງ."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ເພີ່ມໃສ່ໜ້າຈໍຫຼັກ"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Move item here"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ເພີ່ມ​ລາຍ​ການ​ໃສ່​ໜ້າ​ຈໍ​ຫຼັກ​ແລ້ວ"</string>
+    <string name="item_removed" msgid="851119963877842327">"ເອົາ​ລາຍ​ການ​ອອກ​ໄປ​ແລ້ວ"</string>
+    <string name="action_move" msgid="4339390619886385032">"ຍ້າຍ​ລາຍ​ການ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ຍ້າຍ​ໄປ​ໃສ່​ແຖວ <xliff:g id="NUMBER_0">%1$s</xliff:g> ຖັນ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"ຍ້າຍ​ໄປ​ໃສ່​ຕຳ​ແໜ່ງ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ຍ້າຍ​ໄປ​ໃສ່​ຕຳ​ແໜ່ງ​ທີ່​ມັກ <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ຍ້າຍ​ລາຍ​ການ​ແລ້ວ"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ເພີ່ມ​ໃສ່​ໂຟ​ລ​ເດີ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"ເພີ່ມ​ໃສ່​ໂຟ​ລ​ເດີ​ດ້ວຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ເພີ່ມ​ລາຍ​ການ​ໃສ່​ໂຟ​ລ​ເດີ​ແລ້ວ"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ສ້າງ​ໂຟ​ລ​ເດີ​ກັບ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ສ້າງ​ໂຟ​ລ​ເດີ​ແລ້ວ"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ຍ້າຍ​ໄປ​ໃສ່​ໜ້າ​ຈໍ​ຫຼັກ"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"ຍ້າຍ​ໜ້າ​ຈໍ​ໄປ​ທາງ​ຊ້າຍ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"ຍ້າຍ​ໜ້າ​ຈໍ​ໄປ​ທາງ​ຂວາ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ຍ້າຍ​ໜ້າ​ຈໍ​ແລ້ວ"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ປັບຂະໜາດ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"ເພີ່ມ​ລວງ​ກ້​ວາງ​ຂຶ້ນ"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ເພີ່ມ​ລວງ​ສູງ​ຂຶ້ນ"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ຫຼຸດ​ລວງ​ກ້​ວາງ​ລົງ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ຫຼຸດ​ລວງ​ສູງ​ລົງ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ປ່ຽນ​ຂະ​ໜາດ​ວິດ​ເຈັດ​ເປັນ​ລວງ​ກ້​ວາງ <xliff:g id="NUMBER_0">%1$s</xliff:g> ລວງ​ສູງ <xliff:g id="NUMBER_1">%2$s</xliff:g> ແລ້ວ"</string>
 </resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 897c2fd..b5c0832 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Pagrindinis"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Pagrindinės „Android“ programos"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Darbas"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Programa neįdiegta."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Programa nepasiekiama"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Atsisiųsta programa išjungta Saugos režimu"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Valdikliai išjungti Saugiame režime"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Valdikliai"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Valdikliai"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Rodyti atmintinę"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Palieskite ir laikykite, kad pasirinkt. valdiklį."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nepavyko nuvilkti elemento į šį pagrindinį ekraną."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Pasirinkite norimą kurti valdiklį"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Aplanko pavadinimas"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Pervardyti aplanką"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Gerai"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Atšaukti"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Pridėti prie pagrindinio ekrano"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Programos"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Spartieji klavišai"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Valdikliai"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Pagrindiniuose ekranuose vietos nebėra."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ieškoti programų"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Įkeliamos programos..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nerasta jokių užklausą „<xliff:g id="QUERY">%1$s</xliff:g>“ atitinkančių programų"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šiame pagrindiniame ekrane vietos nebėra."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Mėgstamiausių dėkle nebėra vietos"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Mėgstamiausių dėklui šis valdiklis per didelis."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Spartusis klavišas „<xliff:g id="NAME">%s</xliff:g>“ sukurtas."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Spartusis klavišas „<xliff:g id="NAME">%s</xliff:g>“ pašalintas."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Spartusis klavišas „<xliff:g id="NAME">%s</xliff:g>“ jau yra."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Pasirinkite spartųjį klavišą"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Pasirinkite programą"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programos"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Pagrindinis"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Pašalinti"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Pašalinti"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Pašalinti"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Pašalinti"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Programos informacija"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Programos"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Pašalinti"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Pašalinti naujinį"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Pašalinti programą"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Išsami programos informacija"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Pasirinkta 1 programa"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Pasirinktas 1 valdiklis"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Pasirinktas 1 aplankas"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Pasirinktas 1 spartusis klavišas"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"įdiegti sparčiuosius klavišus"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Programai leidžiama pridėti sparčiuosius klavišus be naudotojo įsikišimo."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"pašalinti sparčiuosius klavišus"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Programai leidžiama pašalinti sparčiuosius klavišus be naudotojo įsikišimo."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"skaityti pagrindinio puslapio nustatymus ir sparčiuosius klavišus"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Programai leidžiama skaityti pagrindinio puslapio nustatymus ir sparčiuosius klavišus."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"rašyti pagrindinio puslapio nustatymus ir sparčiuosius klavišus"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema įkeliant valdiklį"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sąranka"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Tai sistemos programa ir jos negalima pašalinti."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Aplankas be pavadinimo"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"%1$d pagrindinis ekranas"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d programų psl. iš %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d valdiklių psl. iš %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Sveiki"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Jauskitės kaip namie."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Sukurkite daugiau programų ir aplankų ekrano kopijų"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Programų piktogramų kopij."</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importuoti piktogramas ir aplankus iš senų pagr. ekranų?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIJUOTI PIKTOGRAMAS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"PRADĖTI IŠ NAUJO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Tvarkykite savo vietą"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Palieskite ir laikykite foną, jei norite tvarkyti ekrano foną, valdiklius ir nustatymus."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ekrano fonai, valdikliai ir nustatymai"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Jei norite tinkinti, palieskite ir palaikykite foną"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SUPRATAU"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Štai aplankas"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Kad sukurtumėte tokį patį, palieskite ir laikykite programą, tada perkelkite ją virš kitos programos."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Gerai"</string>
     <string name="folder_opened" msgid="94695026776264709">"Atidarytas aplankas, <xliff:g id="WIDTH">%1$d</xliff:g> ir <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Palieskite, kad uždarytumėte aplanką"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Palieskite, kad išsaugotumėte naują pavadinimą"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Valdikliai"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ekrano fonai"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Nustatymai"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Laukiama"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Atsisiunčiama"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Diegiama"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Leisti kaitaliojimą"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nežinoma"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Neatkurta"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Pašalinti viską"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Pašalinti"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Ieškoti"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ši programa neįdiegta"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Šios piktogramos programa neįdiegta. Galite ją pašalinti arba bandyti ieškoti programos ir ją įdiegti patys."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Pridėti prie pagrind. ekrano"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Perkelti elementą čia"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementas pridėtas prie pagrindinio ekrano"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elementas perkeltas"</string>
+    <string name="action_move" msgid="4339390619886385032">"Perkelti elementą"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Perkelti į <xliff:g id="NUMBER_0">%1$s</xliff:g> eilutę, <xliff:g id="NUMBER_1">%2$s</xliff:g> stulpelį"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Perkelti į <xliff:g id="NUMBER">%1$s</xliff:g> poziciją"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Perkelti į <xliff:g id="NUMBER">%1$s</xliff:g> mėgstamiausių poziciją"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elementas perkeltas"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Pridėti prie aplanko: „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Pridėti prie aplanko su „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elementas pridėtas prie aplanko"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Kurti aplanką naudojant: „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Aplankas sukurtas"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Perkelti į pagrindinį ekraną"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Perkelti ekraną į kairę"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Perkelti ekraną į dešinę"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekranas perkeltas"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Pakeisti dydį"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Padidinti plotį"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Padidinti aukštį"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Sumažinti plotį"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Sumažinti aukštį"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Valdiklio dydis pakeistas: plotis – <xliff:g id="NUMBER_0">%1$s</xliff:g>, aukštis – <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 13a4760..432bda4 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Sākums"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android pamatlietotnes"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Darbs"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Lietotne nav instalēta."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Lietotne nav pieejama."</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Lejupielādētā lietotne ir atspējota drošajā režīmā."</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Logrīki atspējoti drošajā režīmā"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Logrīki"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Logrīki"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Rādīt atmiņu"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Lai izvēlētos logrīku, pieskarieties un turiet to."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nevarēja nomest vienumu šajā sākuma ekrānā."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Izveidojamā logrīka izvēle"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mapes nosaukums"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Mapes pārdēvēšana"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Labi"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Atcelt"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Pievienošana sākuma ekrānam"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Lietotnes"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Saīsnes"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Logrīki"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Sākuma ekrānos vairs nav vietas."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Meklēt lietotnes"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Notiek lietotņu ielāde…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Vaicājumam “<xliff:g id="QUERY">%1$s</xliff:g>” neatbilda neviena lietotne."</string>
     <string name="out_of_space" msgid="4691004494942118364">"Šajā sākuma ekrānā vairs nav vietas."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Izlases joslā vairs nav vietas."</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Šis logrīks ir pārāk liels izlases joslai."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Tika izveidota saīsne “<xliff:g id="NAME">%s</xliff:g>”."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Tika noņemta saīsne “<xliff:g id="NAME">%s</xliff:g>”."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Saīsne “<xliff:g id="NAME">%s</xliff:g>” jau pastāv."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Saīsnes izvēle"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Lietotnes izvēle"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Lietotnes"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Sākums"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Noņemt"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Atinstalēt"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Noņemt"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Atinstalēt"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Lietotnes informācija"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Lietotnes"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Noņemt"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Atinstalēt atjauninājumu"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Atinstalēt lietotni"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Lietotnes informācija"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Atlasīta 1 lietotne"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Atlasīts 1 logrīks"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Atlasīta 1 mape"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Atlasīta 1 saīsne"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalēt saīsnes"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ļauj lietotnei pievienot saīsnes, nejautājot lietotājam."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"atinstalēt saīsnes"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ļauj lietotnei noņemt saīsnes, nejautājot lietotājam."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lasīt sākuma ekrāna iestatījumus un saīsnes"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Ļauj lietotnei lasīt iestatījumus un saīsnes sākuma ekrānā."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"rakstīt sākuma ekrāna iestatījumus un saīsnes"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Ielādējot logrīku, radās problēma."</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Notiek iestatīšana"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Šī ir sistēmas lietotne, un to nevar atinstalēt."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mape bez nosaukuma"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Sākuma ekrāns: %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d. lietotņu lapa no %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d. logrīku lapa no %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Laipni lūdzam!"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Informācija par pamatfunkcijām"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Izveidojiet vairāk ekrānu lietotnēm un mapēm."</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Lietotņu ikonu kopēšana"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Vai importēt ikonas, mapes no iepriekšējiem sākuma ekrāniem?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPĒT IKONAS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"SĀKT NO SĀKUMA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Kārtojiet savu darbvietu"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Pieskarieties fonam un turiet to, lai pārvaldītu fona tapeti, logrīkus un iestatījumus."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Fona tapetes, logrīki un iestatījumi"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Lai pielāgotu, pieskarieties fonam un turiet to nospiestu."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SAPRATU!"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Lūk, mape!"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Lai izveidotu tādu pašu, pieskarieties lietotnei un turiet to, pēc tam pārvietojiet to virs citas lietotnes."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Labi"</string>
     <string name="folder_opened" msgid="94695026776264709">"Atvērta mape: <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Pieskarieties, lai aizvērtu mapi."</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Pieskarieties, lai saglabātu pārdēvēto nosaukumu."</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Logrīki"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fona tapetes"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Iestatījumi"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Gaida"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Lejupielādē"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalē"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Rotācijas atļauja"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Nezināma"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nav atjaunota"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Noņemt visas"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Noņemt"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Meklēt"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Šī lietotne nav instalēta"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Šai ikonai paredzētā lietotne nav instalēta. Varat noņemt ikonu vai meklēt lietotni un instalēt to manuāli."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Pievienot sākuma ekrānam"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Pārvietot vienumu šeit"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Vienums pievienots sākuma ekrānam"</string>
+    <string name="item_removed" msgid="851119963877842327">"Vienums noņemts"</string>
+    <string name="action_move" msgid="4339390619886385032">"Pārvietot vienumu"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Pārvietot uz <xliff:g id="NUMBER_0">%1$s</xliff:g>. rindu, <xliff:g id="NUMBER_1">%2$s</xliff:g>. kolonnu"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Pārvietot uz <xliff:g id="NUMBER">%1$s</xliff:g>. pozīciju"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Pārvietot uz <xliff:g id="NUMBER">%1$s</xliff:g>. izlases pozīciju"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Vienums pārvietots"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Pievienot mapei: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Pievienot mapei, kurā ir <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Vienums pievienots mapei"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Izveidot mapi ar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mape izveidota"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Pārvietot uz sākuma ekrānu"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Pārvietot ekrānu pa kreisi"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Pārvietot ekrānu pa labi"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekrāns pārvietots"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Mainīt lielumu"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Palielināt platumu"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Palielināt augstumu"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Samazināt platumu"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Samazināt augstumu"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Logrīka lielums mainīts — platums: <xliff:g id="NUMBER_0">%1$s</xliff:g>, augstums: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
 </resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index dcc55d7..8c276e3 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Почетна страница"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Основни апликации на Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Апликацијата не е инсталирана."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Апликацијата не е достапна"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преземената апликација е оневозможена во безбеден режим"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Додатоците се оневозможени во безбеден режим"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виџети"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виџети"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Прикажи „Мени“"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Допри и задржи за да се избере виџетот."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Не можеше да се спушти елемент на овој екран на почетната страница."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Избери виџет за да се создаде"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Име на папка"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Преименувај папка"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Во ред"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Откажи"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Додај во екран на почетна страница"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Апликации"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Кратенки"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виџети"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Нема повеќе простор на вашите екрани на почетна страница."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пребарување апликации"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Се вчитуваат апликации…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Не се најдени апликации што одговараат на „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Нема повеќе простор на овој екран на почетната страница."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема повеќе простор на лентата „Омилени“"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Овој виџет е премногу голем за лентата „Омилени“"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ е создадена."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ е отстранета."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Кратенката „<xliff:g id="NAME">%s</xliff:g>“ веќе постои."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Избери кратенка"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Избери апликација"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апликации"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна страница"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Отстрани"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Деинсталирај"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Отстрани"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Деинсталирај"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Информации за апликацијата"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Апликации"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Отстрани"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Деинсталирај ажурирање"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Деинсталирај апликација"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Детали за апликација"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 апликација е избрана"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виџет е избран"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 папка е избрана"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 кратенка е избрана"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирај кратенки"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Овозможува апликацијата да додава кратенки без интервенција на корисникот."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"деинсталирај кратенки"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Овозможува апликацијата да ги отстрани кратенките без интервенција на корисникот."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"прочитај подесувања и кратенки на почетна страница"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Овозможува апликацијата да ги менува подесувањата и кратенките на почетната страница."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"напиши подесувања и кратенки на почетна страница"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при вчитувањето на виџетот"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Поставување"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ова е системска апликација и не може да се деинсталира."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Неименувана папка"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Екран на почетна страница %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Страница на апликации %1$d од %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Страница на виџети %1$d од %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Добредојдовте"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Чувствувајте се како дома."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Создади повеќе екрани за апликации и папки"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Копирај икони за апликација"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Зачувај икони и папки од твоите стари почетни страни?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПИРАЈ ИКОНИ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"СТАРТУВАЈ ОД ПОЧЕТОК"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Организирајте го вашиот простор"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Допри и задржи ја заднината за управување со тапети, виџети и подесувања."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Тапети, додатоци и поставки"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Допрете и задржете на заднината за да приспособите"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"СФАТИВ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Еве папка"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"За да создадете ваква, допрете и држете ја апликацијата, а потоа поместете ја врз другата."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Во ред"</string>
     <string name="folder_opened" msgid="94695026776264709">"Отворена е папка, <xliff:g id="WIDTH">%1$d</xliff:g> на <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Допри за да се затвори папката"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Допри за да се зачува преименувањето"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Тапети"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Подесувања"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"На чекање"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Се презема"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Се инсталира"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Дозволи ротација"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Не е обновено"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Отстрани ги сите"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Отстрани"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Барај"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Апликацијата не е инсталирана"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликацијата за оваа икона не е инсталирана. Може да ја отстраните или да се обидете да ја најдете апликацијата и да ја инсталирате рачно."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Додај на Почетен екран"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Премести ја ставката овде"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставката е додадена на почетниот екран"</string>
+    <string name="item_removed" msgid="851119963877842327">"Ставката е отстранета"</string>
+    <string name="action_move" msgid="4339390619886385032">"Премести ја ставката"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Премести во ред <xliff:g id="NUMBER_0">%1$s</xliff:g> колона <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Премести на место <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Премести на место <xliff:g id="NUMBER">%1$s</xliff:g> во омилени"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Ставката е преместена"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Додај во папката: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додај во папка со <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Ставката е додадена во папката"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Создај папка со: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Папката е создадена"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Премести на Почетен екран"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Движи го екранот налево"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Движи го екранот надесно"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Екранот е преместен"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Промени големина"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Зголеми ширина"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Зголеми висина"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Намали ширина"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Намали висина"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Големината на виџетот е променета на ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> висина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 8778844..59ad153 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"ഹോം"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core അപ്ലിക്കേഷനുകൾ"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ഔദ്യോഗികം"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"അപ്ലിക്കേഷൻ ഇൻസ്‌റ്റാളുചെ‌യ്‌തിട്ടില്ല."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"അപ്ലിക്കേഷൻ ലഭ്യമല്ല"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ഡൗൺലോഡുചെയ്‌ത അപ്ലിക്കേഷൻ സുരക്ഷാ മോഡിൽ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"സുരക്ഷിത മോഡിൽ വിജറ്റുകൾ പ്രവർത്തനരഹിതമാക്കി"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"വിജറ്റുകൾ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"വിജറ്റുകൾ"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"മെമ്മറി കാണിക്കുക"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ഒരു വിജറ്റ് ചേർക്കുന്നതിന് അത് സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ഹോം സ്‌ക്രീനിൽ ഇനം വലിച്ചിടാനായില്ല."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"സൃഷ്‌ടിക്കുന്നതിന് വിജറ്റ് തിരഞ്ഞെടുക്കുക"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ഫോൾഡറിന്റെ പേര്"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ഫോൾഡറിന്റെ പേരുമാറ്റുക"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ശരി"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"റദ്ദാക്കുക"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string>
-    <string name="group_applications" msgid="3797214114206693605">"അപ്ലിക്കേഷനുകൾ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"കുറുക്കുവഴികൾ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"വിജറ്റുകൾ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"നിങ്ങളുടെ ഹോം സ്‌ക്രീനുകളിൽ സ്ഥലമില്ല."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ആപ്പ്‌സ് തിരയുക"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ആപ്പ്‌സ് ലോഡുചെയ്യുന്നു..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പ്‌സൊന്നും കണ്ടെത്തിയില്ല"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ഈ ഹോം സ്‌ക്രീനിൽ ഒഴിവൊന്നുമില്ല."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ഈ വിജറ്റ് പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഉൾക്കൊള്ളിക്കാവുന്നതിലും വളരെ വലുതാണ്"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" സൃഷ്‌ടിച്ചു."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" നീക്കംചെയ്‌തു."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"കുറുക്കുവഴി \"<xliff:g id="NAME">%s</xliff:g>\" ഇതിനകം നിലവിലുണ്ട്."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"കുറുക്കുവഴി തിരഞ്ഞെടുക്കുക"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"അപ്ലിക്കേഷൻ തിരഞ്ഞെടുക്കുക"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"അപ്ലിക്കേഷനുകൾ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ഹോം"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"നീക്കംചെയ്യുക"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"അണ്‍ഇസ്റ്റാളുചെയ്യുക"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"നീക്കംചെയ്യുക"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"അണ്‍ഇസ്റ്റാളുചെയ്യുക"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ആപ്പ് വിവരം"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"അപ്ലിക്കേഷനുകൾ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"നീക്കംചെയ്യുക"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"അപ്‌ഡേറ്റ് അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"അപ്ലിക്കേഷൻ അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"അപ്ലിക്കേഷൻ വിശദാംശങ്ങൾ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"ഒരു അപ്ലിക്കേഷൻ തിരഞ്ഞെടുത്തു"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"ഒരു വിജറ്റ് തിരഞ്ഞെടുത്തു"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"ഒരു ഫോൾഡർ തിരഞ്ഞെടുത്തു"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുത്തു"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"കുറുക്കുവഴികൾ ഇൻസ്റ്റാളുചെയ്യുക"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ ചേർക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"കുറുക്കുവഴികൾ അൺഇൻസ്റ്റാളുചെയ്യുക"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ഉപയോക്തൃ ഇടപെടൽ ഇല്ലാതെ കുറുക്കുവഴികൾ നീക്കംചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യുക"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ഹോമിലെ ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ഹോം ക്രമീകരണങ്ങളും കുറുക്കുവഴികളും റൈറ്റുചെയ്യുക"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"വിജറ്റ് ലോഡുചെയ്യുന്നതിൽ പ്രശ്നമുണ്ട്"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"സജ്ജീകരിക്കുക"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ഇതൊരു സിസ്‌റ്റം അപ്ലിക്കേഷനായതിനാൽ അൺഇൻസ്‌റ്റാളുചെയ്യാനാവില്ല."</string>
-    <string name="dream_name" msgid="1530253749244328964">"റോക്കറ്റ് ലോഞ്ചർ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"പേരുനൽകാത്ത ഫോൾഡർ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ഹോം സ്‌ക്രീൻ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"അപ്ലിക്കേഷനുകളുടെ പേജ് %1$d / %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"വിജറ്റുകളുടെ പേജ് %1$d / %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"സ്വാഗതം"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ഹോം നിങ്ങളുടേതാക്കി മാറ്റുക."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"അപ്ലിക്കേഷനുകൾക്കും ഫോൾഡറുകൾക്കും വേണ്ടി കൂടുതൽ സ്‌ക്രീനുകൾ സൃഷ്‌ടിക്കുക"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"നിങ്ങളുടെ അപ്ലിക്കേഷൻ ഐക്കണുകൾ പകർത്തുക"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"നിങ്ങളുടെ പഴയ ഹോം സ്ക്രീനുകളിൽ നിന്ന് ഐക്കണുകളും ഫോൾഡറുകളും ഇമ്പോർട്ടുചെയ്യണോ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ഐക്കണുകൾ പകർത്തുക"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"പുതുതായി ആരംഭിക്കുക"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"നിങ്ങളുടെ ഇടം ഓർഗനൈസുചെയ്യുക"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"വാൾപേപ്പർ, വിജറ്റുകൾ, ക്രമീകരണങ്ങൾ എന്നിവ നിയന്ത്രിക്കുന്നതിന് പശ്ചാത്തലം സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"വാൾപേപ്പറുകൾ, വിജറ്റുകൾ, ക്രമീകരണങ്ങൾ എന്നിവ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ഇഷ്‌ടാനുസൃതമാക്കുന്നതിന് പശ്‌ചാത്തലം സ്‌പർശിച്ചുപിടിക്കുക"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"മനസ്സിലായി"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ഇവിടെയൊരു ഫോൾഡർ ഉണ്ട്"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ഇതുപോലൊന്ന് സൃഷ്‌ടിക്കുന്നതിന്, ഒരു അപ്ലിക്കേഷൻ സ്‌പർശിച്ച് പിടിച്ചുകൊണ്ട് അത് മറ്റൊന്നിലേക്ക് നീക്കുക."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ശരി"</string>
     <string name="folder_opened" msgid="94695026776264709">"ഫോൾഡർ തുറന്നു, <xliff:g id="WIDTH">%1$d</xliff:g> / <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ഫോൾഡർ അടയ്ക്കാൻ സ്‌പർശിക്കുക"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"പേരുമാറ്റം സംരക്ഷിക്കുന്നതിന് സ്‌പർശിക്കുക"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"വിജറ്റുകൾ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"വാൾപേപ്പറുകൾ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ക്രമീകരണങ്ങൾ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"കാത്തിരിക്കുന്നു"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ഡൗൺലോഡുചെയ്യുന്നു"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ഇൻസ്‌റ്റാൾ ചെയ്യുന്നു"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"തിരിക്കൽ അനുവദിക്കുക"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"അജ്ഞാതം"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"പുനഃസ്ഥാപിച്ചിട്ടില്ല"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"എല്ലാം നീക്കം ചെയ്യുക"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"നീക്കംചെയ്യുക"</string>
     <string name="abandoned_search" msgid="891119232568284442">"തിരയുക"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ഈ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്‌തിട്ടില്ല"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ഈ ഐക്കണുവേണ്ടി അപ്ലിക്കേഷൻ ഇൻസ്റ്റാളുചെയ്‌തിട്ടില്ല. നിങ്ങൾക്കത് നീക്കംചെയ്യാനാകും അല്ലെങ്കിൽ അപ്ലിക്കേഷനുവേണ്ടി തിരഞ്ഞുകൊണ്ട് അത് സ്വമേധയാ ഇൻസ്റ്റാളുചെയ്യുക."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ഹോം സ്ക്രീനിൽ ചേർക്കുക"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ഇനം ഇവിടേക്ക് നീക്കുക"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ഹോം സ്‌ക്രീനിൽ ഇനം ചേർത്തു"</string>
+    <string name="item_removed" msgid="851119963877842327">"ഇനം നീക്കംചെയ്‌തു"</string>
+    <string name="action_move" msgid="4339390619886385032">"ഇനം നീക്കുക"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"വരി <xliff:g id="NUMBER_0">%1$s</xliff:g> നിര <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-ലേക്ക് നീക്കുക"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ഇഷ്‌ടമുള്ള <xliff:g id="NUMBER">%1$s</xliff:g> സ്ഥാനത്തേക്ക് നീക്കുക"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ഇനം നീക്കി"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ഫോൾഡറിൽ ചേർക്കുക: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ഉള്ള ഫോൾഡറിൽ ചേർക്കുക"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ഫോൾഡറിൽ ഇനം ചേർത്തു"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ഇതുപയോഗിച്ച് ഫോൾഡർ സൃഷ്‌ടിക്കുക: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ഫോൾഡർ സൃഷ്‌ടിച്ചു"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ഹോം സ്‌ക്രീനിലേക്ക് നീക്കുക"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"സ്‌ക്രീൻ ഇടത്തേക്ക് നീക്കുക"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"സ്‌ക്രീൻ വലത്തേക്ക് നീക്കുക"</string>
+    <string name="screen_moved" msgid="266230079505650577">"സ്‌ക്രീൻ നീക്കി"</string>
+    <string name="action_resize" msgid="1802976324781771067">"വലുപ്പംമാറ്റുക"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"വീതി കൂട്ടുക"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ഉയരം കൂട്ടുക"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"വീതി കുറയ്‌ക്കുക"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ഉയരം കുറയ്‌ക്കുക"</string>
+    <string name="widget_resized" msgid="9130327887929620">"വീതി <xliff:g id="NUMBER_0">%1$s</xliff:g> ഉയരം <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് വിഡ്‌ജെറ്റിന്റെ വലുപ്പം മാറ്റി"</string>
 </resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index f258b4c..fafb37b 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Нүүр"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Андройд үндсэн апп"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Ажил"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Апп суугаагүй байна."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Апп-г ашиглах боломжгүй"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Татаж авсан апп-г Аюулгүй горим дотроос идэвхгүйжүүлсэн"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Safe горимд виджетүүдийг идэвхгүйжүүлсэн"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виджет"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виджет"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Мем харуулах"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Виджетийг авах бол хүрээд барина уу."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Энэ Нүүр дэлгэцэнд буулгах боломжгүй."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Үүсгэх виджетээ сонгоно уу"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Фолдерын нэр"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Фолдерын нэр өөрчлөх"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Тийм"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Цуцлах"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Нүүр дэлгэцэнд нэмэх"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Апп"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Товчлол"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виджет"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Таны Нүүр дэлгэц зайгүй."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Апп хайх"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Аппликейшныг ачаалж байна..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"-тай нийцэх апп олдсонгүй"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Энэ Нүүр дэлгэц зайгүй."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"\"Дуртай\" трей дээр өөр зай байхгүй байна"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Энэ виджет трей дээр хэт томдож байна"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" товчлол үүсэв."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" товчлол устгагдав."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" товчлол өмнө үүссэн байна."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Товчлол сонгох"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Апп сонгох"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апп"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Нүүр"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Устгах"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Устгах"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Устгах"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Устгах"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Апп мэдээлэл"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Апп"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Устгах"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Шинэчлэлийг устгах"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Апп устгах"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Апп дэлгэрэнгүй"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 апп сонгогдсон"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 виджет сонгогдсон"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 фолдер сонгогдсон"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 товчлол сонгогдсон"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"товчлол суулгах"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг нэмэж чадна"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"товчлолыг устгах"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Апп нь хэрэглэгчийн оролцоогүйгээр товчлолыг устгаж чадна"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Нүүрний тохиргоо болон товчлолыг унших"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Апп нь Нүүрэндэх товчлол болон тохиргоог уншиж чадна."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Нүүрний тохиргоо болон товчлолыг бичих"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Виджет ачаалахад асуудал гарав"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Тохируулга"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Энэ апп нь системийн апп ба устгах боломжгүй."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Пуужин хөөргөгч"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Нэргүй фолдер"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Нүүр дэлгэц %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d-н %1$d апп хуудас"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d-н %1$d виджет хуудас"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Тавтай морилно уу"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Гэртээ байгаа мэт тухлаарай."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Апп болон фолдеруудад зориулан өөр дэлгэцүүд үүсгээрэй"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Таны апп дүрсүүдийг хуулах"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Таны хуучин Үндсэн дэлгэц дээрх дүрсүүдийг импорт хийх үү?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ДҮРСҮҮДИЙГ ХУУЛАХ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ШИНЭЭР ЭХЛЭХ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Өөрийнхөө зайг тохируулаарай"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Арын дэвсгэр дээр хүрээд &amp; дарснаар ханын зураг, виджет болон тохиргоог өөрчилж болно."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Дэвсгэр зураг, виджет, &amp; тохиргоо"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Тааруулахын тулд арын дэлгэцэнд хүрээд &amp; барина уу"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"Ойлголоо"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Фолдер энд байна"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Үүнтэй адилханыг үүсгэхийн тулд апп дээр хүрч &amp; бариад нөгөөхийн дээр зөөнө үү."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Тийм"</string>
     <string name="folder_opened" msgid="94695026776264709">"<xliff:g id="WIDTH">%1$d</xliff:g> <xliff:g id="HEIGHT">%2$d</xliff:g> фолдер нээгдэв"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Фолдер хаах бол хүрнэ үү"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Шинэ нэрийг хадгалах бол хүрнэ үү"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виджет"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ханын зураг"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Тохиргоо"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Хүлээж байна"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Татаж авч байна"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Суулгаж байна"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Эргүүлэхийг зөвшөөрөх"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Тодорхойгүй"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Сэргээгээгүй"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Бүгдийг устгах"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Устгах"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Хайх"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Энэ апп-г суулгаагүй байна"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Энэ дүрсний апп-г суулгаагүй байна. Та үүнийг устгах буюу апп-г хайж суулгах боломжтой."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Нүүр дэлгэц нэмэх"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Энд байршуулах"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Нүүр дэлгэцэнд нэмсэн зүйл"</string>
+    <string name="item_removed" msgid="851119963877842327">"Арилгасан зүйл"</string>
+    <string name="action_move" msgid="4339390619886385032">"Зөөх"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> мөр <xliff:g id="NUMBER_1">%2$s</xliff:g> баганад зөөх"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Байршил <xliff:g id="NUMBER">%1$s</xliff:g>-д зөөх"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Дуртай байршил болох <xliff:g id="NUMBER">%1$s</xliff:g>-д зөөх"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Зөөвөрлөсөн зүйл"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Хавтас: <xliff:g id="NAME">%1$s</xliff:g> руу нэм"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g>-тай хавтас нэмэх"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Хавтсанд нэмэгдсэн зүйл"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Хавтсыг: <xliff:g id="NAME">%1$s</xliff:g> нэрээр үүсгэ"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Үүсгэсэн хавтас"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Нүүр дэлгэц рүү зөөх"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Дэлгэцийг зүүн тийш зөөх"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Дэлгэцийг баруун тийш зөөх"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Дэлгэцийг зөөсөн"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Хэмжээг өөрчлөх"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Өргөсгөх"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Өндөрсгөх"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Нарийсгах"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Намсгах"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Виджэтийн өргөн <xliff:g id="NUMBER_0">%1$s</xliff:g>, өндөр <xliff:g id="NUMBER_1">%2$s</xliff:g> болсон"</string>
 </resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 098e830..657010d 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"मुख्‍यपृष्‍ठ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"कार्य"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"अॅप स्थापित केलेला नाही."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"अॅप उपलब्ध नाही"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"डाउनलोड केलेला अ‍ॅप सुरक्षित मोड मध्‍ये अक्षम केला"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोडमध्ये अक्षम झाले"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"विजेट"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"विजेट"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem दर्शवा"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"या मुख्य स्क्रीनवर आयटम ड्रॉप करू शकलो नाही."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"तयार करण्यासाठी विजेट निवडा"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"फोल्डर नाव"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"फोल्डरचे नाव बदला"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ठीक"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"रद्द करा"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"मुख्य स्क्रीनवर जोडा"</string>
-    <string name="group_applications" msgid="3797214114206693605">"अॅप्स"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"शॉर्टकट"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"विजेट"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"आपल्या मुख्य स्क्रीनवर अधिक जागा नाही."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"अॅप्स शोधा"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"अॅप्स लोड करीत आहे..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
     <string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"हे विजेट आवडत्या ट्रे साठी खूप मोठे आहे"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट तयार केला."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट काढला."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" शॉर्टकट आधीपासून अस्तित्वात आहे."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"शॉर्टकट निवडा"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"अॅप निवडा"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"अॅप्स"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"मुख्‍यपृष्‍ठ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"काढा"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"विस्थापित करा"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"काढा"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"विस्थापित करा"</string>
     <string name="info_target_label" msgid="8053346143994679532">"अॅप माहिती"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"अॅप्स"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"काढा"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"अद्यतन विस्थापित करा"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"अॅप विस्थापित करा"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"अॅप तपशील"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 अॅप निवडला"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 विजेट निवडले"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 फोल्डर निवडले"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 शॉर्टकट निवडला"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"शॉर्टकट स्‍थापित करा"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"शॉर्टकट विस्‍थापित करा"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट काढण्यास अॅप ला अनुमती देते."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट वाचा"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट लिहा"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"विजेट लोड करण्यात समस्या"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"हा सिस्टम अॅप आहे आणि विस्थापित केला जाऊ शकत नाही."</string>
-    <string name="dream_name" msgid="1530253749244328964">"रॉकेट लाँचर"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"अनामित फोल्डर"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"मुख्य स्क्रीन %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d पैकी %1$d Apps पृष्ठ"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$d पैकी %1$d विजेट पृष्ठ"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"सुस्वागतम"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"जसे पाहिजे तसे वापरा."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"अॅप्स आणि फोल्डरसाठी आणखी स्क्रीन तयार करा"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"आपली अॅप चिन्हे कॉपी करा"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"आपल्या जुन्या मुख्य स्क्रीनवरून चिन्हे आणि फोल्डर आयात करायची?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"चिन्हे कॉपी करा"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"नव्याने प्रारंभ करा"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"आपले स्थान व्यवस्थापित करा"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"वॉलपेपर, विजेट आणि सेटिंग्ज व्यवस्थापित करण्यासाठी पार्श्वभूमीस स्पर्श करा आणि धरून ठेवा."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वॉलपेपर, विजेट आणि सेटिंग्ज"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"सानुकूल करण्यासाठी पार्श्वभूमीस स्पर्श करा आणि धरुन ठेवा"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"समजले"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"येथे एक फोल्डर आहे"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"यासारखे एखादे तयार करण्यासाठी अॅप ला स्पर्श करा आणि धरून ठेवा, नंतर तो दुसर्‍यावर हलवा."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ठीक"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर उघडले, <xliff:g id="WIDTH">%1$d</xliff:g> बाय <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"फोल्डर बंद करण्यासाठी स्पर्श करा"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"नवे नाव जतन करण्यासाठी स्पर्श करा"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"विजेट"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वॉलपेपर"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"सेटिंग्ज"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"प्रतीक्षारत"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड करत आहे"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"स्थापित करत आहे"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"फिरविण्‍यास अनुमती द्या"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"पुनर्स्थापित झाले नाही"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"सर्व काढा"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"काढा"</string>
     <string name="abandoned_search" msgid="891119232568284442">"शोधा"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"हा अॅप स्थापित केलेला नाही"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"या चिन्हासाठी अॅप स्थापित केलेला नाही. आपण ते काढू शकता किंवा अॅपचा शोध घेऊ शकता आणि त्यास व्यक्तिचलितपणे स्थापित करू शकता."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"मुख्य स्क्रीनवर जोडा"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
+    <string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
+    <string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"पंक्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तंभ <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये हलवा"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"आवडत्या <xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
+    <string name="item_moved" msgid="4606538322571412879">"आयटम हलविला"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"फोल्‍डरवर जोडा: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> सह फोल्डरमध्ये जोडा"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"फोल्‍डरमध्‍ये आयटम जोडले"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"यासह फोल्‍डर तयार करा: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"फोल्‍डर तयार केले"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"मुख्य स्क्रीनवर हलवा"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रीन डावीकडे हलवा"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रीन उजवीकडे हलवा"</string>
+    <string name="screen_moved" msgid="266230079505650577">"स्क्रीन हलविली"</string>
+    <string name="action_resize" msgid="1802976324781771067">"आकार बदला"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"रूंदी वाढवा"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"उंची वाढवा"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"रुंदी कमी करा"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"उंची कमी करा"</string>
+    <string name="widget_resized" msgid="9130327887929620">"विजेटचा आकार रुंदी <xliff:g id="NUMBER_0">%1$s</xliff:g> उंची <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये बदलला"</string>
 </resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index 532b6ad..0c6a5f5 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Laman Utama"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Apl Teras Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Kerja"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Apl tidak dipasang."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Apl tidak tersedia"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Apl yang dimuat turun dilumpuhkan dalam mod Selamat"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widget dilumpuhkan dalam mod Selamat"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widget"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widget"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Papar Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh &amp; tahan untuk mengambil widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Tidak dapat melepaskan item pada Skrin Utama."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Pilih widget yang hendak dibuat"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nama folder"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Namakan semula folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Batal"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Tambah ke skrin Laman Utama"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apl"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Pintasan"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widget"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Tiada lagi ruang pada skrin Laman Utama anda."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Cari Apl"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Memuatkan Apl…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Tiada Apl yang ditemui sepadan dengan \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Tiada lagi ruang pada skrin Laman Utama ini."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Tiada ruang dalam dulang Kegemaran lagi"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Widget ini terlalu besar untuk dulang Kegemaran"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" telah dibuat."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" telah dialih keluar."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" sudah wujud."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Pilih jalan pintas"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Pilih apl"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apl"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Laman Utama"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Alih keluar"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Nyahpasang"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Alih keluar"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Nyahpasang"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Maklumat apl"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apl"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Alih keluar"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Nyahpasang kemas kini"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Nyahpasang apl"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Butiran apl"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 apl dipilih"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget dipilih"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder dipilih"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 pintasan dipilih"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"pasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Membenarkan apl menambah pintasan tanpa campur tangan pengguna."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"nyahpasang pintasan"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Membenarkan apl mengalih keluar pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"baca tetapan dan pintasan Laman Utama"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Membenarkan apl membaca tetapan dan pintasan di Laman Utama."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"tulis tetapan dan pintasan Laman Utama"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Masalah memuatkan widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Persediaan"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini ialah apl sistem dan tidak boleh dinyahpasang."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Pelancar Roket"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder Tanpa Nama"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Skrin Laman Utama %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Halaman apl %1$d daripada %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Halaman widget %1$d daripada %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Selamat datang"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Buat seperti berada di rumah sendiri."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Buat lebih banyak skrin untuk apl dan folder"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Salin ikon apl anda"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Import ikon dan folder dari skrin Laman Utama lama anda?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"SALIN IKON"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"MULAKAN YANG BAHARU"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Susun ruang anda"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Sentuh &amp; tahan latar belakang untuk mengurus kertas dinding, widget dan tetapan."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Kertas dinding, widget &amp; tetapan"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Sentuh &amp; tahan latar belakang untuk memperibadikan"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"FAHAM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ini ada folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Untuk membuat satu folder seperti ini, sentuh &amp; tahan apl, kemudian alihkan ke atas folder lain."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> kali <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Sentuh untuk menutup folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Sentuh untuk menyimpan penamaan semula"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widget"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Tetapan"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Menunggu"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Memuat turun"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Memasang"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Benarkan putaran"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Tidak diketahui"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Tak dipulihkan"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Buang Semua"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Alih keluar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Carian"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Apl ini tidak dipasang"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Apl untuk ikon ini tidak dipasang. Anda boleh mengalih keluar atau mencari dan memasang apl itu secara manual."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Tambahkan pada Skrin Utama"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Alihkan item ke sini"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item ditambahkan pada skrin utama"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item dialih keluar"</string>
+    <string name="action_move" msgid="4339390619886385032">"Alihkan Item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Alihkan ke baris <xliff:g id="NUMBER_0">%1$s</xliff:g> lajur <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Alihkan ke kedudukan <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Alihkan ke kedudukan kegemaran <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item dialihkan"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Tambahkan pada folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Tambahkan pada folder dengan <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item ditambahkan pada folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Buat folder dengan: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder dibuat"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Alihkan ke Skrin Utama"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Alihkan skrin ke kiri"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Alihkan skrin ke kanan"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skrin dialihkan"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ubah saiz"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Tambahkan kelebaran"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Tambahkan ketinggian"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Kurangkan kelebaran"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Kurangkan ketinggian"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Saiz widget diubah menjadi <xliff:g id="NUMBER_0">%1$s</xliff:g> lebar <xliff:g id="NUMBER_1">%2$s</xliff:g> tinggi"</string>
 </resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f50a5db..7335605 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -20,95 +20,34 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="8424725141379931883">"Pelancar"</string>
-    <string name="home" msgid="5921706419368316758">"Laman Utama"</string>
-    <string name="uid_name" msgid="3371120195364560632">"Apl Teras Android"</string>
     <string name="folder_name" msgid="8551881338202938211"></string>
-    <string name="chooser_wallpaper" msgid="6063168087625352235">"Pilih kertas dinding dari"</string>
     <string name="wallpaper_instructions" msgid="4215640646180727542">"Tetapkan kertas dinding"</string>
     <string name="pick_wallpaper" msgid="5630222540525626723">"Kertas dinding"</string>
     <string name="activity_not_found" msgid="217823393239365967">"Aplikasi tidak dipasang."</string>
-    <string name="widgets_tab_label" msgid="9145860100000983599">"Widget"</string>
     <string name="long_press_widget_to_add" msgid="7395697462851217506">"Sentuh &amp; tahan untuk mengambil widget."</string>
-    <string name="market" msgid="2652226429823445833">"Kedai"</string>
     <string name="widget_dims_format" msgid="1386418557719032947">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="2285187188524172774">"Tidak dapat melepaskan item pada skrin Utama ini."</string>
-    <string name="external_drop_widget_pick_title" msgid="7040647073452295370">"Pilih widget untuk dibuat"</string>
-    <string name="rename_folder_label" msgid="5646236631298452787">"Nama folder"</string>
-    <string name="rename_folder_title" msgid="4544573104191526550">"Namakan semula folder"</string>
-    <string name="rename_action" msgid="6016003384693240896">"OK"</string>
-    <string name="cancel_action" msgid="3811860427489435048">"Batal"</string>
-    <string name="menu_item_add_item" msgid="6233177331075781114">"Tambah ke Skrin utama"</string>
-    <string name="group_applications" msgid="2103752818818161976">"Aplikasi"</string>
-    <string name="group_shortcuts" msgid="9133529424900391877">"Pintasan"</string>
-    <string name="group_widgets" msgid="6704978494073105844">"Widget"</string>
-    <string name="completely_out_of_space" msgid="1759078539443491182">"Tiada lagi ruang pada skrin Utama anda."</string>
     <string name="out_of_space" msgid="8365249326091984698">"Tiada lagi ruang pada skrin Utama ini"</string>
     <string name="hotseat_out_of_space" msgid="6304886797358479361">"Tiada lagi ruang pada kerusi panas."</string>
-    <string name="invalid_hotseat_item" msgid="6545340627805449250">"Widget ini terlalu besar untuk kerusi panas."</string>
-    <string name="shortcut_installed" msgid="7071557296331322355">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" diwujudkan."</string>
-    <string name="shortcut_uninstalled" msgid="2129499669449749995">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" telah dialih keluar."</string>
-    <string name="shortcut_duplicate" msgid="4757756326465060694">"Pintasan \"<xliff:g id="NAME">%s</xliff:g>\" sudah pun wujud."</string>
-    <string name="title_select_shortcut" msgid="1873670208166882222">"Pilih pintasan"</string>
-    <string name="title_select_application" msgid="1793455815754848652">"Pilih aplikasi"</string>
     <string name="all_apps_button_label" msgid="2578400570124163469">"Apl"</string>
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Laman Utama"</string>
-    <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Alih keluar"</string>
-    <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Nyahpasang"</string>
     <string name="delete_target_label" msgid="665300185123139530">"Alih keluar"</string>
     <string name="delete_target_uninstall_label" msgid="748894921183769150">"Nyahpasang"</string>
     <string name="info_target_label" msgid="4019495079517426980">"Maklumat apl"</string>
-    <string name="accessibility_search_button" msgid="816822994629942611">"Carian"</string>
-    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Carian Suara"</string>
-    <string name="accessibility_all_apps_button" msgid="8803738611398979849">"Aplikasi"</string>
-    <string name="accessibility_delete_button" msgid="3628162007991023603">"Alih keluar"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Nyahpasang kemas kini"</string>
-    <string name="menu_add" msgid="3065046628354640854">"Tambah"</string>
-    <string name="menu_manage_apps" msgid="2308685199463588895">"Mengurus apl"</string>
-    <string name="menu_wallpaper" msgid="5837429080911269832">"Kertas dinding"</string>
-    <string name="menu_search" msgid="4826514464423239041">"Cari"</string>
-    <string name="menu_notifications" msgid="6424587053194766192">"Pemberitahuan"</string>
-    <string name="menu_settings" msgid="3946232973327980394">"Tetapan sistem"</string>
-    <string name="menu_help" msgid="4901160661634590633">"Bantuan"</string>
-    <string name="cab_menu_delete_app" msgid="4089398025537640349">"Nyahpasang aplikasi"</string>
-    <string name="cab_menu_app_info" msgid="914548323652698884">"Butiran aplikasi"</string>
-    <string name="cab_app_selection_text" msgid="6378522164293415735">"1 aplikasi dipilih"</string>
-    <string name="cab_widget_selection_text" msgid="962527270506951955">"1 widget dipilih"</string>
-    <string name="cab_folder_selection_text" msgid="8916111874189565067">"1 folder dipilih"</string>
-    <string name="cab_shortcut_selection_text" msgid="8115847384500412878">"1 pintasan dipilih"</string>
     <string name="permlab_install_shortcut" msgid="1201690825493376489">"pasang pintasan"</string>
     <string name="permdesc_install_shortcut" msgid="8634424803272077038">"Membenarkan aplikasi menambah pintasan tanpa campur tangan pengguna."</string>
-    <string name="permlab_uninstall_shortcut" msgid="7696645932555926449">"nyahpasang pintasan"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="274355570620220977">"Membenarkan apl mengalih keluar pintasan tanpa campur tangan pengguna."</string>
     <string name="permlab_read_settings" msgid="3452408290738106747">"membaca tetapan dan pintasan Laman Utama"</string>
     <string name="permdesc_read_settings" msgid="5788109303585403679">"Membenarkan apl membaca tetapan dan pintasan di Laman Utama."</string>
     <string name="permlab_write_settings" msgid="1360567537236705628">"menulis tetapan dan pintasan Laman Utama"</string>
     <string name="permdesc_write_settings" msgid="8530105489115785531">"Membenarkan apl menukar tetapan dan pintasan di Laman Utama."</string>
     <string name="gadget_error_text" msgid="8359351016167075858">"Masalah memuatkan widget"</string>
     <string name="uninstall_system_app_text" msgid="6429814133777046491">"Ini adalah aplikasi sistem dan tidak boleh dinyahpasang."</string>
-    <string name="dream_name" msgid="2847171357608437154">"Pelancar Roket"</string>
     <string name="folder_hint_text" msgid="8633351560105748141">"Folder Tanpa Nama"</string>
-    <string name="workspace_description_format" msgid="2968608205939373034">"Skrin utama %1$d"</string>
     <string name="default_scroll_format" msgid="4057140866420001240">"Halaman %1$d dari %2$d"</string>
     <string name="workspace_scroll_format" msgid="1704767047951143301">"Skrin utama %1$d dari %2$d"</string>
-    <string name="apps_customize_apps_scroll_format" msgid="5494241912377704885">"Halaman apl %1$d dari %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="5383009742241717437">"Halaman widget %1$d dari %2$d"</string>
-    <string name="workspace_cling_title" msgid="738396473989890567">"Buat diri anda seperti di rumah"</string>
-    <string name="workspace_cling_move_item" msgid="791013895761065070">"Anda boleh meletakkan aplikasi kegemaran anda di sini."</string>
-    <string name="workspace_cling_open_all_apps" msgid="2459977609848572588">"Untuk melihat semua aplikasi anda, sentuh bulatan."</string>
-    <string name="all_apps_cling_title" msgid="2559734712581447107">"Pilih beberapa aplikasi"</string>
-    <string name="all_apps_cling_add_item" msgid="5665035103260318891">"Untuk menambahkan aplikasi pada skrin Utama anda, sentuh &amp; tahankannya."</string>
-    <string name="folder_cling_title" msgid="4308949882377840953">"Susun aplikasi anda dengan folder"</string>
-    <string name="folder_cling_move_item" msgid="270598675060435169">"Untuk memindahkan aplikasi, sentuh &amp; tahankannya."</string>
-    <string name="folder_cling_create_folder" msgid="8352867485656129478">"Untuk membuat folder baharu pada skrin Utama anda, tindihkan satu aplikasi di atas yang lain."</string>
-    <string name="cling_dismiss" msgid="2780907108735868381">"OK"</string>
     <string name="folder_opened" msgid="1262064100943801533">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> kali <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1335478160661137579">"Sentuh untuk menutup folder"</string>
     <string name="folder_tap_to_rename" msgid="5201612989905472442">"Sentuh untuk menyimpan penamaan semula"</string>
     <string name="folder_closed" msgid="3130534551370511932">"Folder ditutup"</string>
     <string name="folder_renamed" msgid="7951233572858053642">"Folder dinamakan semula kepada <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="folder_name_format" msgid="3051680259794759037">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="custom_workspace_cling_title_1" msgid="1433009175359948587"></string>
-    <string name="custom_workspace_cling_description_1" msgid="6875529190849858047"></string>
-    <string name="custom_workspace_cling_title_2" msgid="5516006164661020362"></string>
-    <string name="custom_workspace_cling_description_2" msgid="2758258454975288377"></string>
 </resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 544ecdc..19ec3a6 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher၃"</string>
-    <string name="home" msgid="7658288663002113681">"ပင်မစာမျက်နှာ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Androidပင်မ အပ်ပလီကေးရှင်းများ"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"အလုပ်"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"အပ်ပလီကေးရှင်း မထည့်သွင်းထားပါ"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App လက်လှမ်း မမှီပါ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ဒေါင်းလုဒ် appကို လုံခြုံရေး မုဒ်ထဲမှာ ပိတ်ထား"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"လုံခြုံရေး မုဒ်ထဲမှာ ဝီဂျက်များကို ပိတ်ထား"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ဝဒ်ဂျက်များ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ဝဒ်ဂျက်များ"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem ကိုပြရန်"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ဝဒ်ဂျက်တစ်ခုကို ကောက်ယူရန် ဖိနှိပ်ထားပါ"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ပင်မမျက်နှာစာတွင် အရာများ ချ လို့ မရတော့ပါ"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ဝဒ်ဂျက်တစ်ခုအား ပြုဖန်တီးရန် ရွေးပါ"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"အကန့်အမည်"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"အကန့်အမည်ပြောင်းရန်"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ကောင်းပြီ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ထားတော့"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ပင်မမျက်နှာစာသို့ ထည့်ပါ"</string>
-    <string name="group_applications" msgid="3797214114206693605">"အပ်ပလီကေးရှင်းများ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"အတိုကောက်မှတ်သားမှုများ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ဝဒ်ဂျက်များ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ရှာဖွေမှု Appများ"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"App များ ရယူနေစဉ်..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" နှင့်ကိုက်ညီသည့် အပ်ဖ်များမတွေ့ပါ"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ဤဝဒ်ဂျက်မှာ အနှစ်သက်ဆုံးအရာများထားရာနေရာ အတွက် ကြီးလွန်းနေပါသည်"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ကို ပြုလုပ်ပြီးပါပြီ"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ကို ဖယ်ရှားပြီးပါပြီ"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"အတိုကောက်မှတ်သားမှု \"<xliff:g id="NAME">%s</xliff:g>\" ရှိပြီးသား ဖြစ်နေပါသည်"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"အတိုကောက်မှတ်သားမှုကို ရွေးရန်"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"အပလီကေးရှင်း တစ်ခုခုကို ရွေးချယ်ပါ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"အပ်ပလီကေးရှင်းများ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ပင်မစာမျက်နှာ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ဖယ်ရှာခြင်း"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ဖယ်ရှားခြင်း"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ဖယ်ရှာခြင်း"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ဖယ်ရှားခြင်း"</string>
     <string name="info_target_label" msgid="8053346143994679532">"အပ်ပလီကေးရှင်း အချက်အလက်များ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"အပ်ပလီကေးရှင်းများ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ဖယ်ရှာခြင်း"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"အဆင့်မြှင့်ခြင်းကို ဖယ်ရှားပါ"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"အပ်ပလီကေးရှင်းကို ဖယ်ရှားပါ"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"အပ်ပလီကေးရှင်း အသေးစိတ် အချက်အလက်"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"အပ်ပလီကေးရှင်းတစ်ခု ရွေးချယ်ထားပြီး"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"ဝဒ်ဂျက်တစ်ခု ရွေးချယ်ထားပြီး"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"အကန့် တစ်ခု ရွေးချယ်ထားပြီး"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"အတိုကောက်မှတ်သားမှုတစ်ခု ရွေးချယ်ထားပြီး"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"အတိုကောက်မှတ်သားမှုများအား ထည့်သွင်းခြင်း"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"အသုံးပြုသူ လုပ်ဆောင်မှုမရှိပဲ အပ်ပလီကေးရှင်းကို အတိုကောက်မှတ်သားမှုများ ပြုလုပ်ခွင့် ပေးခြင်း"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"အတိုကောက်မှတ်သားမှုများ ဖယ်ထုတ်ခြင်း"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"အပ်ပလီကေးရှင်းအား အသုံးပြုသူ မပါဝင်ပဲ အတိုကောက်မှတ်သားမှုများ ဖယ်ရှားခွင့် ပြုခြင်း"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ဖတ်ခြင်း"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ပင်မမျက်နှာစာတွင်ရှိသော အပြင်အဆင်နှင့် အတိုကောက်မှတ်သားမှုများကို အပ်ပလီကေးရှင်းအား ဖတ်ခွင့်ပြုခြင်း"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ပင်မမျက်နှာစာ အပြင်အဆင် နှင့် အတိုကောက်မှတ်သားမှုများအား ရေးသားခြင်း"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ဝဒ်ဂျက် တင်ရာတွင် ပြသနာ ရှိပါသည်"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"စဖွင့်သတ်မှတ်ရန်"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ဤအပ်ပလီကေးရှင်းမှာ စစ်စတန်ပိုင်းဆိုင်ရာ အပ်ပလီကေးရှင်းဖြစ်ပါသည်။ ထုတ်ပစ်၍ မရပါ"</string>
-    <string name="dream_name" msgid="1530253749244328964">"ဒုံပျံ ပစ်လွှတ်သောအရာ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"အမည်မရှိအကန့်"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ပင်မစာမျက်နှာ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"အပ်ပလီကေးရှင်းပြ စာမျက်နှာ %1$d မှ %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ဝဒ်ဂျက်ပြ စာမျက်နှာ %1$d မှ %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"မင်္ဂလာပါ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ကိုယ့်အိမ်လို သဘောထားပါ"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"အပ်ပလီကေးရှင်း နှင့် အကန့်များအတွက် ဖန်သားပြင်မှာ ထပ်ထည့်ပါ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"အပ်ပလီကေးရှင်းပုံညွှန်းများကို ကူးယူပါ"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"ပင်မစာမျက်နှာအဟောင်းမှ ပုံညွှန်းများ နှင့် အကန့်များကို ယူလာပါမလား"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPY ICONS"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"စနစ်တကျဖြစ်အောင် ပြုလုပ်ပါ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"နောက်ခံကို ဖိကိုင်၍ နောက်ခံပုံ၊ဝဒ်ဂျက်များ၊အပြင်အဆင်များကို ထိန်းချုပ်ပါ"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"နောက်ခံများ၊ ဝီဂျက်များ&amp; ဆက်တင်များ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"နောက်ခံကို စိတ်တိုင်းကျ ပြုလုပ်ရန် ထိလျက် &amp; ကိုင်ထားပါ"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ရပြီ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ဒီမှာ အကန့်တစ်ခုဖြစ်ပါသည်"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ဤကဲ့သို့လုပ်ရန်အတွက်၊ အပ်ပလီကေးရှင်းတစ်ခုကို ဖိကိုင်ပြီး နောက်တစ်ခုပေါ်သို့ ရွှေ့လိုက်ပါ"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ကောင်းပြီ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ဖွင့်ထားသောအကန့်, <xliff:g id="WIDTH">%1$d</xliff:g> နှင့် <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"အကန့်ကို ပိတ်ရန် ဖိကိုင်ပါ"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"အမည်ပြောင်းခြင်း အတည်ပြုရန် ဖိကိုင်ပါ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ဝဒ်ဂျက်များ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"နောက်ခံများ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"အပြင်အဆင်များ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"စောင့်နေ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ဒေါင်းလုဒ် လုပ်နေ"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"တပ်ဆင်နေ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"လှည့်ရန် ခွင့်ပြုမည်"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"မသိရ"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ပြန်မဖေါ်ခဲ့"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"အားလုံး ဖယ်ရှားရန်"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ဖယ်ရှားရန်"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ရှာဖွေရန်"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"App မတပ်ဆင်ရသေးပါ"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ဤအိုင်ကွန်အတွက် app အားမထည့်သွင်းထားပါ။ You can remove it, or search for the app and install it manually."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ပင်မမျက်နှာစာသို့ ထည့်ပါ"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"၎င်းအား ဤသို့ ရွှေ့ပါ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ပင်မ ဖန်မျက်နှာပြင်သို့ ထည့်ပြီး၏"</string>
+    <string name="item_removed" msgid="851119963877842327">"၎င်းအား ဖယ်ရှားပြီး၏"</string>
+    <string name="action_move" msgid="4339390619886385032">"၎င်းအား ရွှေ့ပါ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"အတန်း <xliff:g id="NUMBER_0">%1$s</xliff:g> အတိုင် <xliff:g id="NUMBER_1">%2$s</xliff:g> သို့ ရွှေ့ပါ"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> သို့ နေရာရွှေ့ပါ"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"စိတ်ကြိုက်နေရာ <xliff:g id="NUMBER">%1$s</xliff:g> သို့ ရွှေ့ပါ"</string>
+    <string name="item_moved" msgid="4606538322571412879">"၎င်းအားရွှေ့ပြီး"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ဖိုလ်ဒါသို့ ထည့်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> အမည်ရှိ ဖိုလ်ဒါသို့ ထည့်ပြီး၏"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ဖိုလ်ဒါသို့ ထည့်ပြီး"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ဖိုလ်ဒါ ပြုလုပ်ရန်- <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ဖိုလ်ဒါ ပြုလုပ်ပြီး"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ပင်မမျက်နှာပြင်သို့ ရွှေ့ပါ"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"မျက်နှာပြင် ဘယ်ဘက်သို့ ရွှေ့ပါ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"မျက်နှာပြင် ညာဘက်သို့ ရွှေ့ပါ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ဖန်မျက်နှာပြင် ပြောင်းရွှေ့ပြီး၏"</string>
+    <string name="action_resize" msgid="1802976324781771067">"အရွယ်အစားပြောင်းပါ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"အကျယ်အား တိုးပါ"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"အမြင့်အား တိုးပါ"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"အကျယ်အား လျှော့ပါ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"အမြင့်အား လျှော့ပါ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget အား အကျယ် <xliff:g id="NUMBER_0">%1$s</xliff:g> အမြင့် <xliff:g id="NUMBER_1">%2$s</xliff:g> အရွယ်အစားပြန်လည်ချိန်ညှိပြီး၏"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index a9bbe08..21b87c8 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Startside"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Kjerneapper for Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Jobb"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Appen er ikke installert."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Appen er ikke tilgjengelig"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"En nedlastet app er deaktivert i sikker modus"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Moduler er deaktivert i sikker modus"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Moduler"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Moduler"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Vis minne"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Trykk og hold inne for å plukke opp en modul."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Kunne ikke slippe elementet på denne startsiden."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Velg modul for oppretting"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mappenavn"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Gi mappen nytt navn"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Avbryt"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Legg til på startsiden"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apper"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Snarveier"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Moduler"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Ikke mer plass på startsidene dine."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Søk i apper"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Laster inn apper …"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Fant ingen apper som samsvarer med «<xliff:g id="QUERY">%1$s</xliff:g>»"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Denne startsiden er full."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritter-skuffen er full"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Denne modulen er for stor for Favoritter-skuffen."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Snarveien «<xliff:g id="NAME">%s</xliff:g>» er opprettet."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Snarveien «<xliff:g id="NAME">%s</xliff:g>» er fjernet."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Snarveien «<xliff:g id="NAME">%s</xliff:g>» fins allerede."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Valg av snarvei"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Velg app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apper"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startside"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Fjern"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Avinstaller"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Fjern"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Avinstaller"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App-info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apper"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Fjern"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Avinstaller oppdateringen"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Avinstaller appen"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Informasjon om appen"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Én app er valgt"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Én modul er valgt"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Én mappe er valgt"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Én snarvei er valgt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installere snarveier"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Gir apper tillatelse til å legge til snarveier uten innblanding fra brukeren."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"avinstallere snarveier"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Lar appen fjerne snarveier uten innblanding fra brukeren."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lese startsideinnstillinger og -snarveier"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Lar appen lese innstillingene og snarveiene på startsiden."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"angi startsideinnstillinger og -snarveier"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem ved innlasting av modul"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfigurering"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dette er en systemapp som ikke kan avinstalleres."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Mappe uten navn"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Startside %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Appside %1$d av %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Modulside %1$d av %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Velkommen"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Føl deg som hjemme."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Opprett flere sider for apper og mapper"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiér appikonene dine"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Vil du importere ikoner og mapper fra dine gamle startsider?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIÉR IKONENE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START PÅ NYTT"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organiser plassen din"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Trykk og hold på bakgrunnen for å administrere bakgrunnen, moduler og innstillinger."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Bakgrunner, moduler og innstillinger"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Trykk og hold på bakgrunnen for å tilpasse den"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"SKJØNNER"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Dette er en mappe"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"For å opprette en som denne, trykker og holder du på en app og flytter den over en annen."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen er åpnet – <xliff:g id="WIDTH">%1$d</xliff:g> ganger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Trykk for å lukke mappen"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Trykk for å lagre det nye navnet"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Moduler"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunner"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Innstillinger"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Venter …"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Laster ned …"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installerer …"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Tillat rotasjon"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ukjent"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ikke gjenoppr."</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Fjern alle"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Fjern"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Søk"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Denne appen er ikke installert"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen for dette ikonet er ikke installert. Du kan fjerne det, eller prøve å søke etter appen og installere den manuelt."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Legg til på startskjermen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Flytt elementet hit"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Elementet er lagt til på startskjermen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Elementet er fjernet"</string>
+    <string name="action_move" msgid="4339390619886385032">"Flytt elementet"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Flytt til rad <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolonne <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Flytt til posisjon <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Flytt til posisjonen for favoritter <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Elementet er flyttet"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Legg til i mappe: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Legg til mappen med <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Elementet er lagt til i mappen"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Opprett mappe med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mappen er opprettet"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Flytt til startskjermen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Flytt skjermen til venstre"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Flytt skjermen til høyre"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skjermen er flyttet"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Endre størrelse"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Øk bredden"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Øk høyden"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reduser bredden"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reduser høyden"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Størrelsen på modulen er endret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og høyde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index 4c72ebb..dd3b3f3 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"गृह"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android मूल अनुप्रयोगहरू"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"कार्य"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"अनुप्रयोग स्थापित छैन।"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"अनुप्रयोग उपलब्ध छैन"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"सुरक्षित मोडमा डाउनलोड गरेको अनुप्रयोग अक्षम गरिएको छ"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"सुरक्षित मोडमा विगेटहरू अक्षम गरियो"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"विजेटहरू"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"विजेटहरू"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem देखाउनुहोस्"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"एउटा विजेटलाई टिप्नको लागि टच गरेर होल्ड गर्नुहोस्।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"यो गृह स्क्रिनमा वस्तु खसाउन सकिँदैन।"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"सृजना गर्नको लागि विजेट छान्नुहोस्"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"फोल्डरको नाम"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"फोल्डरलाई पुनःनामाकरण गर्नुहोस्"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ठिक छ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"रद्द गर्नुहोस्"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"गृह स्क्रिनमा थप्नुहोस्"</string>
-    <string name="group_applications" msgid="3797214114206693605">"अनुप्रयोगहरू"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"सर्टकटहरू"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"विजेटहरू"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"यो गृह स्क्रिनहरूमा कुनै थप ठाउँ छैन"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"अनुप्रयोगहरू खोज्नुहोस्"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"अनुप्रयोगहरू लोड गरिँदै..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै अनुप्रयोगहरू फेला परेनन्"</string>
     <string name="out_of_space" msgid="4691004494942118364">"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"मनपर्ने ट्रे अब कुनै ठाँउ छैन"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"यो विजेट मनपर्ने ट्रे को लागि निकै ठूलो छ"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" सिर्जित गरियो।"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" हटाइयो।"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"सर्टकट \"<xliff:g id="NAME">%s</xliff:g>\" पहिल्यै अवस्थित छ।"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"सर्टकट छान्नुहोस्"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"अनुप्रयोग छनौट गर्नुहोस्"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"अनुप्रयोगहरू"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"गृह"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"हटाउनुहोस्"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"हटाउनुहोस्"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"हटाउनुहोस्"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"हटाउनुहोस्"</string>
     <string name="info_target_label" msgid="8053346143994679532">"अनुप्रयोग जानकारी"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"अनुप्रयोगहरू"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"हटाउनुहोस्"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"अद्यावधिक अस्थापित गर्नुहोस्"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"अनुप्रयोग अस्थापना गर्नुहोस्"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"अनुप्रयोग विवरणहरु"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"१ अनुप्रयोग चयन गरियो"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"१ विजेट चयन गरियो"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"१ फोल्डर चयन गरियो"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"१ सर्टकट चयन गरियो"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"सर्टकटहरूको स्थापन रद्द गर्नुहोस्"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"अनुप्रयोगलाई उपयोगकर्ताको हस्तक्षेप बिना सर्टकटहरूलाई हटाउन अनुमति दिनुहोस्।"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string>
@@ -78,32 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो प्रणाली अनुप्रयोग हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string>
-    <string name="dream_name" msgid="1530253749244328964">"रकेट लन्चर"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"बेनाम फोल्डर"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"गृह स्क्रिन %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"अनुप्रयोग पृष्ठ %2$d को %1$d"</string>
-    <!-- String.format failed for translation -->
-    <!-- no translation found for apps_customize_widgets_scroll_format (3106209519974971521) -->
-    <skip />
     <string name="first_run_cling_title" msgid="2459738000155917941">"स्वागतम"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"गृह आरामसँग बस्नुहोस्"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"अनुप्रयोगहरु र फोल्डरहरुलाई थप स्क्रीनहरु सिर्जना गर्नुहोस्"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"तपाईँको अनुप्रयोग आईकनको प्रतिलिप गर्नुहोस्"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"आफ्नो पुरानो गृह स्क्रीनबाट अाईकन र फोल्डरहरू आयात गर्नुहोस्?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ICONS प्रतिलिप गर्नुहोस्"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"START FRESH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"आफ्नो ठाउँ व्यवस्थापन गर्नुहोस्"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"वालपेपर, विजेट र सेटिङ्स प्रबन्ध गर्न पृष्ठभूमिलाई टच गरेर होल्ड गर्नुहोस्।"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"वालपेपरहरू, विजेट; सेटिङहरू"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"छुनुहोस् ; अनुकूलन पृष्ठभूमि होल्ड गर्नुहोस्"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"बुझियो"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"यहाँ एउटा फोल्डर छ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"यस्तै एक किसिमका सिर्जना गर्न, अनुप्रयोगलाई टच गरेर होल्ड गर्नुहोस्, त्यसपछि यसलाई अर्को माथि सार्नुहोस्।"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ठिक छ"</string>
     <string name="folder_opened" msgid="94695026776264709">"फोल्डर खुल्यो <xliff:g id="WIDTH">%1$d</xliff:g> बाट <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"फोल्डर बन्द गर्नको लागि टच गर्नुहोस्"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"पुन: नामाकरण बचत गर्न टच गर्नुहोस्।"</string>
@@ -113,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"विजेटहरू"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"वालपेपरहरु"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"सेटिंङहरू"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"पर्खँदै"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"डाउनलोड हुँदै"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"स्थापना गर्दै"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"परिक्रमणलाई अनुमति दिनुहोस्"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"पुनर्स्थापित भएन"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"सबै हटाउनुहोस्"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"हटाउनुहोस्"</string>
     <string name="abandoned_search" msgid="891119232568284442">"खोजी गर्नुहोस्"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"यो अनुप्रयोग स्थापित छैन"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"यो प्रतिमाका लागि अनुप्रयोगलाई स्थापना गरिएको छैन। तपाईँ यसलाई हटाउन, वा अनुप्रयोग खोजी र स्वयं यो स्थापित गर्न सक्नुहुन्छ।"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"गृह स्क्रिनमा थप्नुहोस्"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"वस्तु यहाँ सार्नुहोस्"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"वस्तु गृह स्क्रिनमा थपियो"</string>
+    <string name="item_removed" msgid="851119963877842327">"वस्तु हटाइयो"</string>
+    <string name="action_move" msgid="4339390619886385032">"वस्तु सार्नुहोस्"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"पङ्क्ति <xliff:g id="NUMBER_0">%1$s</xliff:g> स्तम्भ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा सार्नुहोस्"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"मनपर्ने स्थिति <xliff:g id="NUMBER">%1$s</xliff:g> मा सार्नुहोस्"</string>
+    <string name="item_moved" msgid="4606538322571412879">"वस्तु सारियो"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"फोल्डर: <xliff:g id="NAME">%1$s</xliff:g> मा थप्नुहोस्"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"फोल्डरमा <xliff:g id="NAME">%1$s</xliff:g> सँग थप्नुहोस्"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"वस्तु फोल्डरमा थपियो"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g>: मार्फत फोल्डर सिर्जना गर्नुहोस्"</string>
+    <string name="folder_created" msgid="6409794597405184510">"फोल्डर सिर्जना गरियो"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"गृह स्क्रिनमा सार्नुहोस्"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"स्क्रिनलाई बायाँ सार्नुहोस्"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"स्क्रिनलाई दायाँ सार्नुहोस्"</string>
+    <string name="screen_moved" msgid="266230079505650577">"स्क्रिन सारियो"</string>
+    <string name="action_resize" msgid="1802976324781771067">"पुनःआकार मिलाउनुहोस्"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"चौडाइ बढाउनुहोस्"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"उँचाइ बढाउनुहोस्"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"चौडाइ घटाउनुहोस्"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"उँचाइ घटाउनुहोस्"</string>
+    <string name="widget_resized" msgid="9130327887929620">"विजेट चौडाइ <xliff:g id="NUMBER_0">%1$s</xliff:g> उचाइ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा पुनः आकार मिलाइयो"</string>
 </resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 2a21bd6..fcbe375 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Startpagina"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android-kernapps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Werk"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"App is niet geïnstalleerd."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"App is niet beschikbaar"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Gedownloade app uitgeschakeld in veilige modus"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets uitgeschakeld in Veilige modus"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Geheugen weergeven"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Blijf aanraken om een widget toe te voegen."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Kan item niet neerzetten in dit startscherm."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Widget selecteren om te maken"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mapnaam"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Naam van map wijzigen"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Annuleren"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Toevoegen aan startscherm"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Snelkoppelingen"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Er is geen ruimte meer op uw startschermen."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Apps zoeken"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Apps laden…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Er zijn geen apps gevonden die overeenkomen met \'<xliff:g id="QUERY">%1$s</xliff:g>\'"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Er is geen ruimte meer op dit startscherm."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Geen ruimte meer in het vak \'Favorieten\'"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Deze widget is te groot voor het vak \'Favorieten\'"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Snelkoppeling \'<xliff:g id="NAME">%s</xliff:g>\' is gemaakt."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Snelkoppeling \'<xliff:g id="NAME">%s</xliff:g>\' is verwijderd."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Snelkoppeling \'<xliff:g id="NAME">%s</xliff:g>\' bestaat al."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Snelkoppeling selecteren"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"App selecteren"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startpagina"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Verwijderen"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Verwijderen"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Verwijderen"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Verwijderen"</string>
     <string name="info_target_label" msgid="8053346143994679532">"App-info"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Verwijderen"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Update verwijderen"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"App verwijderen"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"App-details"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app geselecteerd"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget geselecteerd"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 map geselecteerd"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 snelkoppeling geselecteerd"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelkoppelingen instellen"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"snelkoppelingen verwijderen"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"De app toestaan snelkoppelingen te verwijderen zonder tussenkomst van de gebruiker."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"instellingen en snelkoppelingen op de startpagina lezen"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"De app toestaan de instellingen en snelkoppelingen op de startpagina te lezen."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"instellingen en snelkoppelingen op de startpagina schrijven"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Probleem bij het laden van widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuratie"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Dit is een systeemapp die niet kan worden verwijderd."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Naamloze map"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Startscherm %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"App-pagina %1$d van %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widgetpagina %1$d van %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Welkom"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Personaliseer uw startscherm."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Meer schermen maken voor apps en mappen"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Uw app-pictogrammen kopiëren"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Pictogrammen en mappen importeren uit uw oude startschermen?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"PICTOGRAMMEN KOPIËREN"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"OPNIEUW BEGINNEN"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Uw ruimte indelen"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Blijf de achtergrond aanraken om de achtergrond, widgets en instellingen te beheren."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Achtergronden, widgets en instellingen"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Blijf de achtergrond aanraken om deze aan te passen"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Dit is een map"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Als u een map zoals deze wilt maken, blijft u een app aanraken en schuift u deze boven op een andere app."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Map geopend, <xliff:g id="WIDTH">%1$d</xliff:g> bij <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Raak dit aan om de map te sluiten"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Raak dit aan om de gewijzigde naam op te slaan"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Achtergronden"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Instellingen"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Wachten"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Downloaden"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installeren"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Draaien toestaan"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Niet hersteld"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Alles verwijderen"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwijderen"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Zoeken"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Deze app is niet geïnstalleerd"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"De app voor dit pictogram is niet geïnstalleerd. U kunt het pictogram verwijderen of de app zoeken en handmatig installeren."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Toevoegen aan startpagina"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Item hier naartoe verplaatsen"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item toegevoegd aan startscherm"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item verwijderd"</string>
+    <string name="action_move" msgid="4339390619886385032">"Item verplaatsen"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Verplaatsen naar rij <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolom <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Verplaatsen naar positie <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Verplaatsen naar positie <xliff:g id="NUMBER">%1$s</xliff:g> voor favorieten"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item verplaatst"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Toevoegen aan map: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Toevoegen aan map met <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item toegevoegd aan map"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Map maken met: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Map gemaakt"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Verplaatsen naar startscherm"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Scherm naar links verplaatsen"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Scherm naar rechts verplaatsen"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Scherm verplaatst"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Formaat aanpassen"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Breedte vergroten"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Hoogte vergroten"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Breedte verkleinen"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Hoogte verkleinen"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Formaat van widget gewijzigd in breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> en hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml
index fbb27b3..d510dc7 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"ਲਾਂਚਰ3"</string>
-    <string name="home" msgid="7658288663002113681">"ਹੋਮ"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core ਐਪਸ"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"ਦਫ਼ਤਰ"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ਡਾਊਨਲੋਡ ਕੀਤਾ ਐਪ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ਵਿਜੇਟਸ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ਵਿਜੇਟਸ"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ਵਿਜੇਟਸ"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"ਮੈਮ ਦਿਖਾਓ"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"ਇੱਕ ਵਿਜੇਟ ਚੁਣਨ ਲਈ ਛੋਹਵੋT &amp; ਹੋਲਡ ਕਰੋ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਤੇ ਆਈਟਮ ਡ੍ਰੌਪ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"ਬਣਾਉਣ ਲਈ ਵਿਜੇਟ ਚੁਣੋ"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ਫੋਲਡਰ ਨਾਮ"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ਫੋਲਡਰ ਨੂੰ ਦੁਬਾਰਾ ਨਾਮ ਦਿਓ"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ਠੀਕ"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ਰੱਦ ਕਰੋ"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜੋ"</string>
-    <string name="group_applications" msgid="3797214114206693605">"ਐਪਸ"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ਸ਼ੌਰਟਕਟਸ"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ਵਿਜੇਟਸ"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ਤੁਹਾਡੀਆਂ ਹੋਮ ਸਕ੍ਰੀਨਾਂ ਤੇ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ਐਪਸ ਖੋਜੋ"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ਐਪਸ ਲੋਡ ਕਰ ਰਿਹਾ ਹੈ..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮਿਲਦੀ ਕੋਈ ਵੀ ਐਪਸ ਨਹੀਂ ਲੱਭੀਆਂ"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ਇਹ ਵਿਜੇਟ ਮਨਪਸੰਦ ਟ੍ਰੇ ਲਈ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡਾ ਹੈ"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"ਸ਼ੌਰਟਕਟ \"<xliff:g id="NAME">%s</xliff:g>\" ਬਣਾਇਆ ਗਿਆ।"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"ਸ਼ੌਰਟਕਟ \"<xliff:g id="NAME">%s</xliff:g>\" ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਸੀ।"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"ਸ਼ੌਰਟਕਟ \"<xliff:g id="NAME">%s</xliff:g>\" ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ।"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"ਸ਼ੌਰਟਕਟ ਚੁਣੋ"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"ਐਪ ਚੁਣੋ"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ਐਪਸ"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ਹੋਮ"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ਹਟਾਓ"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ਅਣਇੰਸਟੌਲ ਕਰੋ"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ਹਟਾਓ"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ਅਣਇੰਸਟੌਲ ਕਰੋ"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ਐਪ ਜਾਣਕਾਰੀ"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ਐਪਸ"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ਹਟਾਓ"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ਅਪਡੇਟ ਅਣਇੰਸਟੌਲ ਕਰੋ"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ਐਪ ਅਣਇੰਸਟੌਲ ਕਰੋ"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ਐਪ ਵੇਰਵੇ"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ਐਪ ਚੁਣਿਆ"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ਵਿਜੇਟ ਚੁਣਿਆ"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ਫੋਲਡਰ ਚੁਣਿਆ"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ਸ਼ੌਰਟਕਟ ਚੁਣਿਆ"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ਸ਼ੌਰਟਕਟ ਇੰਸਟੌਲ ਕਰੋ"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"ਇੱਕ ਐਪ ਨੂੰ ਉਪਭੋਗਤਾ ਦੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ੌਰਟਕਟ ਜੋੜਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ਸ਼ੌਰਟਕਟ ਅਣਇੰਸਟੌਲ ਕਰੋ"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ਐਪ ਨੂੰ ਉਪਭੋਗਤਾ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਸ਼ੌਰਟਕਟ ਹਟਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਪੜ੍ਹੋ"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ਐਪ ਨੂੰ ਹੋਮ ਵਿੱਚ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ਹੋਮ ਸੈਟਿੰਗਾਂ ਅਤੇ ਸ਼ੌਰਟਕਟ ਲਿਖੋ"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ਵਿਜੇਟ ਲੋਡ ਕਰਨ ਵਿੱਚ ਸਮੱਸਿਆ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ਸੈਟਅਪ"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ਇਹ ਇੱਕ ਸਿਸਟਮ ਐਪ ਹੈ ਅਤੇ ਇਸਨੂੰ ਅਣਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।"</string>
-    <string name="dream_name" msgid="1530253749244328964">"ਰੌਕੇਟ ਲਾਂਚਰ"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"ਬਿਨਾਂ ਨਾਮ ਦਿੱਤਾ ਫੋਲਡਰ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"ਹੋਮ ਸਕ੍ਰੀਨ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"ਐਪਸ ਸਫ਼ਾ %2$d ਦਾ %1$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"ਵਿਜੇਟ ਸਫਾ %2$d ਦਾ %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ਸੁਆਗਤ ਹੈ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ਆਪਣੇ ਹੋਮ ਵਰਗਾ ਸਮਝੋ।"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ਐਪਸ ਅਤੇ ਫੋਲਡਰ ਲਈ ਹੋਰ ਸਕ੍ਰੀਨਾਂ ਬਣਾਓ"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ਆਪਣੇ ਐਪ ਆਈਕਨਾਂ ਨੂੰ ਕਾਪੀ ਕਰੋ"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"ਕੀ ਆਪਣੀਆਂ ਪੁਰਾਣੀਆਂ ਹੋਮ ਸਕ੍ਰੀਨਾਂ ਤੋਂ ਆਈਕਨਾਂ ਅਤੇ ਫੋਲਡਰ ਆਯਾਤ ਕਰਨੇ ਹਨ?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ਆਈਕਨਾਂ ਨੂੰ ਕਾਪੀ ਕਰੋ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ਤਾਜ਼ਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ਆਪਣਾ ਸਪੇਸ ਵਿਵਸਥਿਤ ਕਰੋ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"ਵਾਲਪੇਪਰ, ਵਿਜੇਟ, ਸੈਟਿੰਗਾਂ ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਪਿਛੋਕੜ ਛੋਹਵੋ &amp; ਹੋਲਡ ਕਰੋ।"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"ਵਾਲਪੇਪਰ, ਵਿਜੇਟ, &amp; ਸੈਟਿੰਗਾਂ"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"ਅਨੁਕੂਲ ਕਰਨ ਲਈ ਪਿਛੋਕੜ ਛੋਹਵੋ &amp; ਹੋਲਡ ਕਰੋ"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ਸਮਝ ਗਿਆ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ਇੱਥੇ ਇੱਕ ਫੋਲਡਰ ਹੈ"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ਇਸ ਵਰਗਾ ਇੱਕ ਬਣਾਉਣ ਲਈ, ਇੱਕ ਐਪ ਨੂੰ ਛੋਹਵੋ &amp; ਹੋਲਡ ਕਰੋ, ਫਿਰ ਇਸਨੂੰ ਦੂਜੇ ਤੇ ਮੂਵ ਕਰੋ।"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ਠੀਕ"</string>
     <string name="folder_opened" msgid="94695026776264709">"ਫੋਲਡਰ ਖੋਲ੍ਹਿਆ, <xliff:g id="WIDTH">%1$d</xliff:g> ਬਾਇ <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ਫੋਲਡਰ ਬੰਦ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"ਮੁੜ ਨਾਮ ਦਿਓ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਛੋਹਵੋ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ਵਿਜੇਟਸ"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ਵਾਲਪੇਪਰ"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ਸੈਟਿੰਗਾਂ"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ਡਾਊਨਲੋਡ ਕਰ ਰਿਹਾ ਹੈ"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ਇੰਸਟੌਲ ਕਰ ਰਿਹਾ ਹੈ"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"ਰੋਟੇਸ਼ਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"ਅਗਿਆਤ"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ਰੀਸਟੋਰ ਨਹੀਂ ਕੀਤਾ"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ਸਾਰੇ ਹਟਾਓ"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ਹਟਾਓ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ਖੋਜੋ"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ਇਹ ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ਇਸ ਆਈਕਨ ਲਈ ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ ਜਾਂ ਐਪ ਖੋਜ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਮੈਨੂਅਲੀ ਇੰਸਟੌਲ ਕਰ ਸਕਦੇ ਹੋ।"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜੋ"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"ਆਈਟਮ ਨੂੰ ਮੁੱਖ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
+    <string name="item_removed" msgid="851119963877842327">"ਅਈਟਮ ਹਟਾਈ ਗਈ"</string>
+    <string name="action_move" msgid="4339390619886385032">"ਆਈਟਮ ਨੂੰ ਮੂਵ ਕਰੋ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ਕਤਾਰ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਕਾਲਮ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ਮਨਪਸੰਦ ਸਥਿਤੀ <xliff:g id="NUMBER">%1$s</xliff:g> ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ਆਈਟਮ ਮੂਵ ਕੀਤੀ ਗਈ"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ਇਸ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜੋ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ਦੇ ਨਾਲ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜੋ"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"ਆਈਟਮ ਨੂੰ ਫੋਲਡਰ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ਇਸਦੇ ਨਾਲ ਫੋਲਡਰ ਬਣਾਓ: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ਫੋਲਡਰ ਬਣਾਇਆ ਗਿਆ"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ਮੁੱਖ ਸਕ੍ਰੀਨ ਵਿੱਚ ਮੂਵ ਕਰੋ"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"ਸਕ੍ਰੀਨ ਨੂੰ ਖੱਬੇ ਮੂਵ ਕਰੋ"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"ਸਕ੍ਰੀਨ ਨੂੰ ਸੱਜੇ ਮੂਵ ਕਰੋ"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ਸਕ੍ਰੀਨ ਨੂੰ ਮੂਵ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ਮੁੜ ਆਕਾਰ ਦਿਓ"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"ਚੌੜਾਈ ਵਧਾਓ"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ਉਂਚਾਈ ਵਧਾਓ"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ਚੌੜਾਈ ਘਟਾਓ"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ਉਂਚਾਈ ਘਟਾਓ"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ਵਿਜੈਟ ਨੂੰ ਚੌੜਾਈ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਉਂਚਾਈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਨੂੰ ਮੁੜ ਆਕਾਰ ਦਿੱਤਾ"</string>
 </resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 4eabae9..b3b761d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Ekran główny"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Główne aplikacje Androida"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Praca"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacja nie jest zainstalowana."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacja niedostępna"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Pobrana aplikacja została wyłączona w trybie awaryjnym"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widżety są wyłączone w trybie bezpiecznym"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widżety"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widżety"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Pokaż pamięć"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Aby dodać widżet, kliknij go i przytrzymaj."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nie można upuścić elementu na tym ekranie głównym."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Wybierz widżet, który chcesz dodać"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nazwa folderu"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Zmień nazwę folderu"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Anuluj"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Dodaj do ekranu głównego"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikacje"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Skróty"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widżety"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Brak miejsca na ekranach głównych."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Szukaj w aplikacjach"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Wczytuję aplikacje…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nie znaleziono aplikacji pasujących do zapytania „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Brak miejsca na tym ekranie głównym."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Brak miejsca w Ulubionych"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ten widżet jest za duży, by zmieścił się w Ulubionych"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Skrót „<xliff:g id="NAME">%s</xliff:g>” został utworzony."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Skrót „<xliff:g id="NAME">%s</xliff:g>” został usunięty."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Skrót „<xliff:g id="NAME">%s</xliff:g>” już istnieje."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Wybierz skrót"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Wybierz aplikację"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacje"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ekran główny"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Usuń"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Odinstaluj"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Usuń"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Odinstaluj"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informacje o aplikacji"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikacje"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Usuń"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Odinstaluj aktualizację"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Odinstaluj aplikację"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Szczegóły aplikacji"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Wybrano 1 aplikację"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Wybrano 1 widżet"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Wybrano 1 folder"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Wybrano 1 skrót"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalowanie skrótów"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pozwala aplikacji dodawać skróty bez interwencji użytkownika."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"odinstalowywanie skrótów"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Pozwala aplikacji usuwać skróty bez interwencji użytkownika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"odczytywanie ustawień i skrótów na ekranie głównym"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Pozwala aplikacji na odczytywanie ustawień i skrótów na ekranie głównym."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"zapisywanie ustawień i skrótów na ekranie głównym"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem podczas ładowania widżetu"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguracja"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To aplikacja systemowa i nie można jej odinstalować."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Wyrzutnia rakiet"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folder bez nazwy"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Ekran główny %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Strona aplikacji: %1$d z %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Strona widżetów: %1$d z %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Witamy"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Poczuj się jak u siebie."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Dodaj więcej ekranów na aplikacje i foldery"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiuj ikony aplikacji"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Zaimportować ikony i foldery ze starych ekranów głównych?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIUJ IKONY"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ZACZNIJ OD NOWA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Uporządkuj obszar roboczy"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Kliknij i przytrzymaj tło, by zmienić tapetę, widżety lub ustawienia."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Tapety, widżety i ustawienia"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Kliknij i przytrzymaj tło, by dostosować"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Tu jest folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Aby utworzyć taki sam, kliknij i przytrzymaj aplikację, a następnie przenieś ją na następną."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folder otwarty, <xliff:g id="WIDTH">%1$d</xliff:g> na <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Kliknij, by zamknąć folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Kliknij, by zapisać zmianę nazwy"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widżety"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ustawienia"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Oczekiwanie"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Pobieranie"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalowanie"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Zezwól na obrót"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Brak informacji"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nie przywrócono"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Usuń wszystkie"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Usuń"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Szukaj"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacja nie jest zainstalowana"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacja, której odpowiada ta ikona, nie jest zainstalowana. Możesz usunąć ikonę lub wyszukać aplikację i zainstalować ją ręcznie."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodaj do strony głównej"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Przenieś element tutaj"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Element został dodany do ekranu głównego"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element został usunięty"</string>
+    <string name="action_move" msgid="4339390619886385032">"Przenieś element"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Przenieś do wiersza <xliff:g id="NUMBER_0">%1$s</xliff:g> w kolumnie <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Przenieś do pozycji <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Przenieś do pozycji ulubionych: <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element został przeniesiony"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Dodaj do folderu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj do folderu z: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element został dodany do folderu"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Utwórz folder z: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder został utworzony"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Przenieś na ekran główny"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Przenieś ekran w lewo"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Przenieś ekran w prawo"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekran został przeniesiony"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Zmień rozmiar"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Zwiększ szerokość"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Zwiększ wysokość"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Zmniejsz szerokość"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Zmniejsz wysokość"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Szerokość i wysokość widżetu zmieniła się na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
deleted file mode 100644
index c20f57b..0000000
--- a/res/values-port/dimens.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-<!-- AppsCustomize -->
-    <integer name="apps_customize_widget_cell_count_x">2</integer>
-    <integer name="apps_customize_widget_cell_count_y">3</integer>
-</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 4397ebf..9140b62 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Iniciador3"</string>
-    <string name="home" msgid="7658288663002113681">"Ecrã principal"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplicações principais do Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"A aplicação não está instalada."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"A aplicação não está disponível"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicação transferida desativada no Modo de segurança"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no Modo de segurança"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Prima sem soltar para escolher um widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Não foi possível largar o item neste Ecrã Principal."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Escolher um widget para criar"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nome da pasta"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Mudar o nome da pasta"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Adicionar ao Ecrã principal"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicações"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Atalhos"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Sem espaço suficiente nos Ecrãs principais."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar aplicações"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"A carregar aplicações..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Não foram encontradas aplic. que correspondam a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Sem espaço suficiente neste Ecrã principal."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Não existe mais espaço no tabuleiro de Favoritos"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Este widget é demasiado grande para o tabuleiro de Favoritos"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Atalho “<xliff:g id="NAME">%s</xliff:g>” criado."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"O atalho “<xliff:g id="NAME">%s</xliff:g>” foi removido."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"O atalho “<xliff:g id="NAME">%s</xliff:g>” já existe."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Escolher atalho"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Escolher aplicação"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicações"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ecrã principal"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remover"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Remover"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informações da aplicação"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicações"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Remover"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar atualização"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar a aplicação"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalhes da aplicação"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicação selecionada"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selecionado"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 pasta selecionada"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 atalho selecionado"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite a uma aplicação adicionar atalhos sem a intervenção do utilizador."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar atalhos"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite à aplicação remover atalhos sem intervenção do utilizador."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler definições e atalhos do Ecrã Principal"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite à aplicação ler as definições e os atalhos no Ecrã Principal."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"escrever definições e atalhos do Ecrã principal"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema ao carregar o widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"É uma aplicação de sistema e não pode ser desinstalada."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Lança-mísseis"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Ecrã principal %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de aplicações %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Página de widgets %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bem-vindo(a)"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Sinta-se em casa."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crie mais ecrãs para aplicações e pastas"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar ícones das aplicações"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importar ícones e pastas dos ecrãs principais antigos?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ÍCONES"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEÇAR DO INÍCIO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizar o seu espaço"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Toque sem soltar no fundo para gerir a imagem de fundo, os widgets e as definições."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Imagens de fundo, widgets e definições"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Toque sem soltar no fundo para personalizar"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"COMPREENDI"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Eis uma pasta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para criar uma pasta, toque sem soltar numa aplicação e arraste-a para cima de outra aplicação."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Pasta aberta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toque para fechar a pasta"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toque para guardar o nome novo"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagens de fundo"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Definições"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"A aguardar"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"A transferir "</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"A instalar"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permitir rotação"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Não restaurado"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Remover todos"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Esta aplicação não está instalada"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"A aplicação deste ícone não está instalada. Pode removê-lo ou pesquisar a aplicação e instalá-la manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar ao Ecrã principal"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mover o item para aqui"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado ao ecrã principal"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item removido"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mover item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover para a linha <xliff:g id="NUMBER_0">%1$s</xliff:g>, coluna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g> dos favoritos"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item movido"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Adicionar à pasta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Adicionar à pasta com <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item adicionado à pasta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Criar pasta com: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Pasta criada"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover para o Ecrã principal"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover ecrã para a esquerda"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mover ecrã para a direita"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ecrã movido"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Redimensionar"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumentar largura"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Diminuir largura"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 07c8214..c8e6458 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Início"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Principais apps do Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"O app não está instalado."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"O app não está disponível"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"App transferido por download desativado no modo de segurança"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no modo de segurança"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgets"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgets"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mostrar memória"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Toque e pressione para selecionar um widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Não foi possível soltar o item nesta tela inicial."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Selecione um widget para criar"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Nome da pasta"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Renomear pasta"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Ok"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Cancelar"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Adicionar à tela inicial"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Atalhos"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgets"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Não há mais espaço nas telas iniciais."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Pesquisar apps"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Carregando apps…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenhum app encontrado que corresponda a \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Não há mais espaço na tela inicial."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Sem espaço na bandeja de favoritos"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"O widget é muito grande para a bandeja de favoritos"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Atalho \"<xliff:g id="NAME">%s</xliff:g>\" criado."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"O atalho \"<xliff:g id="NAME">%s</xliff:g>\" foi removido."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"O atalho \"<xliff:g id="NAME">%s</xliff:g>\" já existe."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Selecione um atalho"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Selecione um app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Início"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Remover"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Desinstalar"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Remover"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Desinstalar"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informações do app"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Remover"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Desinstalar atualização"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Desinstalar app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalhes do app"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Um app selecionado"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Um widget selecionado"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Uma pasta selecionada"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Um atalho selecionado"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalar atalhos"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite que um app adicione atalhos sem intervenção do usuário."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"desinstalar atalhos"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite que o app remova atalhos sem a intervenção do usuário."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ler configurações e atalhos da tela inicial"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite que o app leia as configurações e os atalhos na tela inicial."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"gravar configurações e atalhos da tela inicial"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema ao carregar o widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configuração"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Este é um app do sistema e não pode ser desinstalado."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Pasta sem nome"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Tela inicial %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Página de apps, %1$d de %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Página de widgets, %1$d de %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bem-vindo"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Fique à vontade."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Crie mais telas para apps e pastas"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiar ícones de apps"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Importar ícones e pastas de suas telas iniciais antigas?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAR ÍCONES"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"COMEÇAR DO ZERO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organize seu espaço"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Toque e mantenha pressionada a tela de fundo para gerenciar o plano de fundo, os widgets e as configurações."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Plano de fundo, widgets e configurações"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Toque e mantenha pressionado o segundo plano para personalizar"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ENTENDI"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Aqui está uma pasta"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Para criar uma pasta como esta, mantenha pressionado um app e mova-o para cima de outro."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Ok"</string>
     <string name="folder_opened" msgid="94695026776264709">"Pasta aberta, <xliff:g id="WIDTH">%1$d</xliff:g> por <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Toque para fechar a pasta"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Toque para salvar o novo nome"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgets"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Planos de fundo"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Configurações"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Aguardando"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Transferindo"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Instalando"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permitir rotação"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconhecido"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Não restaurado"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Remover tudo"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Remover"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Pesquisar"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Este app não está instalado"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"O app deste ícone não está instalado. Você pode remover o ícone, ou procurar o app e instalá-lo manualmente."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Adicionar à tela inicial"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mover item para cá"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Item adicionado à tela inicial"</string>
+    <string name="item_removed" msgid="851119963877842327">"Item removido"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mover item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mover para a linha <xliff:g id="NUMBER_0">%1$s</xliff:g>, coluna <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mover para a posição <xliff:g id="NUMBER">%1$s</xliff:g> dos favoritos"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Item movido"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Adicionar à pasta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Adicionar à pasta com <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Item adicionado à pasta"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Criar pasta com: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Pasta criada"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mover para a tela inicial"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mover tela para a esquerda"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mover tela para a direita"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Tela movida"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Redimensionar"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Aumentar largura"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Aumentar altura"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Diminuir largura"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index be35c6b..0758148 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -152,8 +152,6 @@
     <skip />
     <!-- no translation found for first_run_cling_description (6447072552696253358) -->
     <skip />
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
     <!-- no translation found for first_run_cling_create_screens_hint (6950729526680114157) -->
     <skip />
     <!-- no translation found for migration_cling_title (9181776667882933767) -->
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 54cb46c..88cbc79 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Ecran de pornire"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplicația nu este instalată."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplicația nu este disponibilă"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplicația descărcată este dezactivată în modul de siguranță"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgeturile sunt dezactivate în modul de siguranță"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgeturi"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgeturi"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Afișați memoria"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Atingeți lung un widget pentru a-l alege."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nu se poate plasa articolul pe ecranul de pornire."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Alegeți widgetul de creat"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Numele dosarului"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Redenumiți dosarul"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Anulați"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Adăugați la Ecranul de pornire"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplicații"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Comenzi rapide"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgeturi"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Nu mai este loc pe ecranele de pornire."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Căutați aplicații"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Se încarcă aplicațiile..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nu s-a găsit nicio aplicație pentru „<xliff:g id="QUERY">%1$s</xliff:g>”"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nu mai este loc pe acest Ecran de pornire."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Spațiu epuizat în bara Preferate"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Acest widget este prea mare pentru bara Preferate"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Comanda rapidă „<xliff:g id="NAME">%s</xliff:g>\" a fost creată."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Comanda rapidă „<xliff:g id="NAME">%s</xliff:g>” a fost eliminată."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Comanda rapidă „<xliff:g id="NAME">%s</xliff:g>” există deja."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Alegeți comanda rapidă"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Alegeți aplicația"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplicații"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ecran de pornire"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Eliminați"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Dezinstalați"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Eliminați"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Dezinstalați"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informații despre aplicație"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplicații"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Eliminați"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Dezinstalați actualizarea"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Dezinstalați aplicația"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detalii despre aplicație"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 aplicație selectată"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget selectat"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 dosar selectat"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 comandă rapidă selectată"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalează comenzi rapide"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permite unei aplicații să adauge comenzi rapide fără intervenția utilizatorului."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"dezinstalează comenzi rapide"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Permite aplicației să elimine comenzi rapide fără intervenția utilizatorului."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"citește setări și comenzi rapide pentru ecranul de pornire"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Permite aplicației să citească setările și comenzile rapide din ecranul de pornire."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"scrie setări și comenzi rapide pentru ecranul de pornire"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problemă la încărcarea widgetului"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Configurați"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Aceasta este o aplicație de sistem și nu poate fi dezinstalată."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosar fără nume"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Ecran de pornire %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Pagina de aplicații %1$d din %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Pagina de widgeturi %1$d din %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Bun venit"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Simțiți-vă ca acasă."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Creați mai multe ecrane pentru aplicații și dosare"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Copiați pictogr. aplicațiilor"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Import. pictogr. și dosare de pe ecranele de pornire anter.?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"COPIAȚI PICTOGRAMELE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"REÎNCEPEȚI"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizați-vă spațiul"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Atingeți lung fundalul pentru a gestiona imaginea de fundal, widgeturile și setările."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Imagini de fundal, widgeturi și setări"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Atingeți lung fundalul pentru a-l personaliza"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"AM ÎNȚELES"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Iată un dosar"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Pentru a crea un dosar similar, atingeți și țineți degetul pe o aplicație, apoi mutați-o deasupra alteia."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dosar deschis, <xliff:g id="WIDTH">%1$d</xliff:g> pe <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Atingeți pentru a închide dosarul"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Atingeți pentru a salva redenumirea"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgeturi"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imagini de fundal"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Setări"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"În așteptare"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Se descarcă"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Se instalează"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Permiteți rotirea"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Necunoscut"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nerestabilit"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Eliminați-le pe toate"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminați"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Căutați"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplicația nu este instalată"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplicația pentru această pictogramă nu este instalată. Puteți să ștergeți pictograma sau să căutați aplicația și s-o instalați manual."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Adăugați pe ecranul de pornire"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Mutați elementul aici"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Element adăugat pe ecranul de pornire"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element eliminat"</string>
+    <string name="action_move" msgid="4339390619886385032">"Mutați elementul"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Mutați pe rândul <xliff:g id="NUMBER_0">%1$s</xliff:g>, coloana <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Mutați pe poziția <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Mutați în preferate, pe poziția <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element mutat"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Adăugați în dosar: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Adăugați în dosarul cu <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element adăugat în dosar"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Creați dosar cu: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Dosar creat"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Mutați pe ecranul de pornire"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Mutați ecranul la stânga"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Mutați ecranul la dreapta"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ecran mutat"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Redimensionați"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Creșteți lățimea"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Creșteți înălțimea"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Reduceți lățimea"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Reduceți înălțimea"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widgetul a fost redimensionat la lățimea <xliff:g id="NUMBER_0">%1$s</xliff:g> și înălțimea <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 70ef0f5..5b492fe 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Главный экран"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Основные приложения Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Работа"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Приложение удалено"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Приложение недоступно"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Скачанное приложение отключено в безопасном режиме"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Виджеты отключены в безопасном режиме"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виджеты"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виджеты"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Сведения о памяти"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Чтобы выбрать виджет, нажмите на значок и удерживайте его."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Не удалось добавить элемент на главный экран"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Выберите виджет"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Название папки"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Переименование папки"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ОК"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Отмена"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Добавление на главный экран"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Приложения"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Ярлыки"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виджеты"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"На главных экранах все занято"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Поиск приложений"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Загрузка…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"По запросу \"<xliff:g id="QUERY">%1$s</xliff:g>\" ничего не найдено"</string>
     <string name="out_of_space" msgid="4691004494942118364">"На этом экране все занято"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В разделе \"Избранное\" больше нет места"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Виджет слишком велик для раздела \"Избранное\""</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Ярлык \"<xliff:g id="NAME">%s</xliff:g>\" создан"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Ярлык \"<xliff:g id="NAME">%s</xliff:g>\" удален"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Ярлык \"<xliff:g id="NAME">%s</xliff:g>\" уже существует"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Выбор ярлыка"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Выбор приложения"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Приложения"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Главный экран"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Удалить"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Удалить"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Удалить"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Удалить"</string>
     <string name="info_target_label" msgid="8053346143994679532">"О приложении"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Приложения"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Удалить"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Удалить обновление"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Удалить приложение"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"О приложении"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Выбрано 1 приложение"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Выбран 1 виджет"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Выбрана 1 папка"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Выбран 1 ярлык"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Создание ярлыков"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Приложение сможет самостоятельно добавлять ярлыки."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"Удаление ярлыков"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Приложение сможет самостоятельно удалять ярлыки."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Доступ к настройкам и ярлыкам главного экрана"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Приложение получит доступ к данным о настройках и ярлыках на главном экране."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Изменение настроек и ярлыков главного экрана"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Не удалось загрузить виджет"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Настройка"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Это системное приложение, его нельзя удалить."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без названия"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Главный экран %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Приложения: стр. %1$d из %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Виджеты: стр. %1$d из %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Добро пожаловать!"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Будьте как дома"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Создание дополнительных экранов для приложений и папок"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Копировать значки приложений"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Импортировать значки и папки со старого главного экрана?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПИРОВАТЬ ЗНАЧКИ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ИСПОЛЬЗОВАТЬ СТАНДАРТНЫЙ МАКЕТ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Организация рабочего пространства"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Чтобы перейти к управлению обоями, виджетами и настройками, нажмите на фоновое изображение и удерживайте его."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Обои, виджеты и настройки"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Чтобы выполнить настройку, коснитесь фона и удерживайте его"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ОК"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Это папка"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Чтобы создать папку, нажмите и удерживайте значок приложения, а затем перетащите его на другой значок."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ОК"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папка открыта, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Нажмите, чтобы закрыть папку"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Нажмите, чтобы подтвердить переименование"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виджеты"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Обои"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Настройки"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Ожидается"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Скачивается"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Устанавливается"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Разрешить автоповорот"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Неизвестно"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Не восстановлен"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Удалить все"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Удалить"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Найти"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Приложение не установлено"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Приложение не установлено. Вы можете удалить значок или найти приложение и установить его вручную."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Добавить на главный экран"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Переместить элемент сюда"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Элемент добавлен на главный экран"</string>
+    <string name="item_removed" msgid="851119963877842327">"Элемент удален"</string>
+    <string name="action_move" msgid="4339390619886385032">"Переместить элемент"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Переместить в ячейку <xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Переместить в позицию <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Переместить в Избранное (<xliff:g id="NUMBER">%1$s</xliff:g>)"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Элемент перемещен."</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Добавить в папку <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Добавить в папку с приложением \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Элемент добавлен в папку."</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Создать папку с элементом <xliff:g id="NAME">%1$s</xliff:g>."</string>
+    <string name="folder_created" msgid="6409794597405184510">"Папка создана."</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Переместить на главный экран"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Переместить экран влево"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Переместить экран вправо"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Экран перемещен"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Изменить размер"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Увеличить ширину"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Увеличить высоту"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Уменьшить ширину"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Уменьшить высоту"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Изменен размер виджета: до <xliff:g id="NUMBER_0">%1$s</xliff:g> в ширину и <xliff:g id="NUMBER_1">%2$s</xliff:g> в высоту"</string>
 </resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index ab3abb8..68e3178 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"මුල් පිටුව"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android මධ්‍ය යෙදුම්"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"කාර්යාලය"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"යෙදුම ස්ථාපනය කර නැත."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"යෙදුම නොතිබේ"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ආරක්ෂිත ආකාරය තුළ බාගන්න ලද යෙදුම් අබල කරන්න"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"සුරක්ෂිත ආකාරය තුළ විජටය අබල කරන ලදි"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"විජට්"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"විජට්"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Mem පෙන්වන්න"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"විජට් එක ස්පර්ශ කර අහුලා ගැනීමට අල්ලාගෙන සිටින්න."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"මෙම මුල් පිටු තිරය වෙත අයිතමය ඇද හෙළිය නොහැකි විය."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"සැදීමට විජට් එක තෝරන්න"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ෆෝල්ඩරයේ නම"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ෆෝල්ඩරය නැවත නම් කරන්න"</string>
-    <string name="rename_action" msgid="5559600076028658757">"හරි"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"අවලංගු කරන්න"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"මුල් පිටු තිරය වෙත එක් කරන්න"</string>
-    <string name="group_applications" msgid="3797214114206693605">"යෙදුම්"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"කෙටිමං"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"විජට්"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"මෙම මුල් පිටු තිර මත තවත් ඉඩ නැත."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"යෙදුම් සෙවීම"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"යෙදුම් පූරණය වෙමින්…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"</string>
     <string name="out_of_space" msgid="4691004494942118364">"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ප්‍රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ප්‍රියතම දෑ ඇති තැටිය සඳහා මෙම විජටය ඉතා විශාලය"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග සාදන ලදි."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග ඉවත් කෙරිණි."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" කෙටිමග දැනටමත් පවතී."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"කෙටිමග තේරීම"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"යෙදුම තේරීම"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"යෙදුම්"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"මුල් පිටුව"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ඉවත් කරන්න"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"අස්ථාපනය කරන්න"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ඉවත් කරන්න"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"අස්ථාපනය කරන්න"</string>
     <string name="info_target_label" msgid="8053346143994679532">"යෙදුම් තොරතුරු"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"යෙදුම්"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ඉවත් කරන්න"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"යාවත්කාලිනය අස්ථාපනය කරන්න"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"යෙදුම අස්ථාපනය කරන්න"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"යෙදුම් විස්තර"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 යෙදුමක් තෝරා ඇත"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 විජටයක් තෝරා ඇත"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ෆෝල්ඩරයක් තෝරා ඇත"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 කෙටිමඟක් තෝරා ඇත"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"කෙටිමං ස්ථාපනය කරන්න"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"පරිශීලක මැදිහත්වීමෙන් තොරව කෙටිමං එක් කිරීමට යෙදුමකට අවසර දෙයි."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"කෙටිමං අස්ථාපනය කරන්න"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"පරිශීලකයාගේ මැදිහත්වීමෙන් තොරව කෙටිමං ඉවත් කිරීමට යෙදුමකට අවසර දෙයි."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"මුල් පිටු සැකසීම් සහ කෙටිමං කියවන්න"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"මුල් පිටුවේ ඇති සැකසීම් සහ කෙටිමං කියවීමට යෙදුමකට අවසර දෙයි."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"මුල් පිටු සැකසීම් සහ කෙටිමං ලියන්න"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ගැටලු පූරණ විජට් එක"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ස්ථාපනය කරන්න"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"මෙය පද්ධති යෙදුමක් වන අතර අස්ථාපනය කළ නොහැක."</string>
-    <string name="dream_name" msgid="1530253749244328964">"රොකට් ආරම්භකය"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"නම් නොකළ ෆෝල්ඩරය"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"මුල් පිටු තිරය %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$d හි %1$d යෙදුම් පිටුව"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"විජට් පිටුව %2$d හි %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"සාදරයෙන් පිළිගනිමු"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ගෙදර ඉන්නවා වගේ ඉන්න."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"යෙදුම් සහ ෆෝල්ඩර සඳහා තවත් තිර සාදන්න"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"ඔබේ යෙදුම් නිරූපක පිටපත් කිරීම"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"ඔබගේ පැරණි මුල් තිර වල නිරූපක සහ ෆෝල්ඩර ආයාත කරන්නද?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"නිරූපක පිටපත් කරන්න"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"අලුතින් පටන්ගන්න"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"ඔබගේ ඉඩ සංවිධානය කරගන්න"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"බිතුපත, විජට් සහ සැකසීම් කළමනාකරණය කිරීමට පසුබිම ස්පර්ශ කර අල්ලාගෙන සිටින්න."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"වෝල්පේපර, විජට්, සහ සැකසීම්"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"පසුබිම අභිරුචිකරණය කිරීමට ස්පර්ශ කර අල්ලා සිටින්න"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"තේරුණා"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"මෙන්න ෆෝල්ඩරයක්"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"මෙවැනි එකක් තැනීමට, යෙදුමක් තට්ටු කර අල්ලාගෙන සිටින්න, අනතුරුව එය තවත් එකක් උඩින් ගෙන යන්න."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"හරි"</string>
     <string name="folder_opened" msgid="94695026776264709">"ෆෝල්ඩරය විවෘත විය, <xliff:g id="WIDTH">%1$d</xliff:g> හි <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ෆෝල්ඩරය වැසීමට ස්පර්ශ කරන්න"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"නැවත නම් කිරීම සුරැකීමට ස්පර්ශ කරන්න"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"විජට්"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"වෝල්පේපර"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"සැකසීම්"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"රැඳී සිටිමින්"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"බාගනිමින්"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ස්ථාපනය කරමින්"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"කරකැවීමට ඉඩ දෙන්න"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"නොදනී"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ප්‍රතිස්ථාපනය කළේ නැත"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"සියල්ල ඉවත් කරන්න"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ඉවත් කරන්න"</string>
     <string name="abandoned_search" msgid="891119232568284442">"සොයන්න"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"මෙම යෙදුම ස්ථාපනය කර නොමැත"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"මෙම නිරුපකයට යෙදුම ස්ථාපනය කර නොමැත. ඔබට එය ඉවත් කළ හැක, හෝ යෙදුම් සඳහා සොයන්න සහ අතින් ස්ථාපනය කරන්න."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"මුල් තිරය වෙත එක් කරන්න"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"මෙතනට අයිතමය ගෙන එන්න"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"අයිතමය මුල් තිරය වෙත එකතු කරන ලදි"</string>
+    <string name="item_removed" msgid="851119963877842327">"අයිතමය ඉවත් කරන ලදි"</string>
+    <string name="action_move" msgid="4339390619886385032">"අයිතමය ගෙනයන්න"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"පේළිය <xliff:g id="NUMBER_0">%1$s</xliff:g> තීරුව <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ගෙන යන්න"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ස්ථානය වෙත ගෙන යන්න"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ප්‍රියතම ස්ථානය <xliff:g id="NUMBER">%1$s</xliff:g> වෙත ගෙන යන්න"</string>
+    <string name="item_moved" msgid="4606538322571412879">"අයිතමය ගෙන යන ලදි"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ෆෝල්ඩරය එක් කරන්න: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> සමග ෆෝල්ඩරය වෙත එකතු කරන්න"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"අයිතමය ෆෝඩරය වෙතට එක් කරන ලදි"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"මේ සමග ෆෝල්ඩරය සාදන්න: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ෆෝල්ඩරය සාදන ලදි"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"මුල් තිරය වෙත ගෙන යන්න"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"තිරය වම් පැත්තට ගෙනයන්න"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"තිරය දකුණු පැත්තට ගෙනයන්න"</string>
+    <string name="screen_moved" msgid="266230079505650577">"තිරය ගෙන යන ලදි"</string>
+    <string name="action_resize" msgid="1802976324781771067">"නැවත ප්‍රමාණගත කිරීම"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"පළල වැඩි කරන්න"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"උස වැඩි කරන්න"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"පළල අඩු කරන්න"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"උස අඩු කරන්න"</string>
+    <string name="widget_resized" msgid="9130327887929620">"විජට් පළල <xliff:g id="NUMBER_0">%1$s</xliff:g> උස <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ප්‍රමාණකරණය කරන ලදි"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 05c5fc0..1cb76e3 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Plocha"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Pracovné"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikácia nie je nainštalovaná."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikácia nie je k dispozícii"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Stiahnutá aplikácia je v núdzovom režime zakázaná"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Miniaplikácie sú v núdzovom režime zakázané"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Miniaplikácie"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Miniaplikácie"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Zobraziť pamäť"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Miniaplikáciu pridáte stlačením a podržaním."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Položku sa nepodarilo presunúť na túto plochu."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Zvoľte miniaplikáciu na vytvorenie"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Názov priečinka"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Premenovať priečinok"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Zrušiť"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Pridať na plochu"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikácie"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Skratky"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Miniaplikácie"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Na plochách už nie je miesto."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Vyhľadávanie v aplikáciách"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Načítavajú sa aplikácie..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nenašli sa žiadne aplikácie zodpovedajúce dopytu <xliff:g id="QUERY">%1$s</xliff:g>"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tejto ploche už nie je miesto"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Na paneli Obľúbené položky už nie je miesto"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Táto miniaplikácia je príliš veľká pre panel Obľúbené položky"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Odkaz <xliff:g id="NAME">%s</xliff:g> bol vytvorený."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Odkaz <xliff:g id="NAME">%s</xliff:g> bol odstránený."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Odkaz <xliff:g id="NAME">%s</xliff:g> už existuje."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Vybrať odkaz"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Vybrať aplikáciu"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikácie"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Domovská stránka"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Odstrániť"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Odinštalovať"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Odstrániť"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Odinštalovať"</string>
     <string name="info_target_label" msgid="8053346143994679532">"O aplikácii"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikácie"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Odstrániť"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Odinštalovať aktualizáciu"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Odinštalovať aplikáciu"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Podrobnosti o aplikácii"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Vybratá 1 aplikácia"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Vybratá 1 miniaplikácia"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Vybratý 1 priečinok"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Vybratý 1 odkaz"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"inštalovať odkazy"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Povoľuje aplikácii pridať odkazy bez zásahu používateľa."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"odinštalovať odkazy"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Povoľuje aplikácii odstrániť odkazy bez zásahu používateľa."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"čítanie nastavení a odkazov plochy"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Povoľuje aplikácii čítať nastavenia a odkazy na ploche."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"zápis nastavení a odkazov plochy"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problém s načítaním miniaplikácií"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavenie"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Toto je systémová aplikácia a nedá sa odinštalovať."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Raketomet"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nepomenovaný priečinok"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Plocha %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Stránka aplikácií %1$d z %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Stránka miniaplikácií %1$d z %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Vitajte!"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Cíťte sa tu ako doma."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Vytvorte viac obrazoviek pre aplikácie a priečinky"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopírovanie ikon aplikácií"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Chcete importovať ikony a priečinky zo starých plôch?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"SKOPÍROVAŤ IKONY"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ZAČAŤ ODZNOVA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Usporiadajte svoj priestor"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Ak chcete spravovať tapetu, miniaplikácie a nastavenia, dotknite sa pozadia a podržte."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Pozadia, miniaplikácie a nastavenia"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Ak si chcete pozadie prispôsobiť, klepnite naň a podržte ho"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"DOBRE"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Tu je priečinok"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ak chcete vytvoriť takýto priečinok, dotknite sa príslušnej aplikácie a podržte ju. Potom ju presuňte na druhú aplikáciu."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Otvorený priečinok, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Dotykom zavriete priečinok"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Dotykom premenovanie uložíte"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikácie"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Nastavenia"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Čaká sa"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Sťahovanie"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Inštalácia"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Povoliť otáčanie"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznáme"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nebolo obnovené"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstrániť všetky"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrániť"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Vyhľadať"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Táto aplikácia nie je nainštalovaná"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikácia, ktorú zastupuje táto ikona, nie je nainštalovaná. Ikonu môžete odstrániť alebo vyhľadajte aplikáciu a ručne ju nainštalujte."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Pridať na plochu"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Presunúť položku sem"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Položka bola pridaná na plochu"</string>
+    <string name="item_removed" msgid="851119963877842327">"Položka bola odstránená"</string>
+    <string name="action_move" msgid="4339390619886385032">"Presunúť položku"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Presunúť do stĺpca <xliff:g id="NUMBER_1">%2$s</xliff:g> v riadku <xliff:g id="NUMBER_0">%1$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Presunúť na <xliff:g id="NUMBER">%1$s</xliff:g>. miesto"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Presunúť na <xliff:g id="NUMBER">%1$s</xliff:g>. miesto v obľúbených položkách"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Položka bola presunutá"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Pridať do priečinka: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Pridať do priečinka <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Položka bola pridaná do priečinka"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Vytvoriť priečinok pomocou: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Priečinok bol vytvorený"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Presunúť na plochu"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Presunúť obrazovku doľava"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Presunúť obrazovku doprava"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Obrazovka bola posunutá"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Zmeniť veľkosť"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Zvýšiť šírku"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Zväčšiť výšku"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Znížiť šírku"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Znížiť výšku"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Veľkosť miniaplikácie bola zmenená na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g> (šírka x výška)"</string>
 </resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index d5a34d5..92c69a5 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Zaganjalnik3"</string>
-    <string name="home" msgid="7658288663002113681">"Začetni zaslon"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Osnovne aplikacije sistema Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Služba"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija ni nameščena."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija ni na voljo"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Prenesena aplikacija je onemogočena v Varnem načinu"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Pripomočki so onemogočeni v varnem načinu"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Pripomočki"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Pripomočki"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Pokaži pomnilnik"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Za izbiro pripomočka se ga dotaknite in pridržite."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Elementa ni mogoče spustiti na začetni zaslon."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Izberite pripomoček za ustvarjanje"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Ime mape"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Preimenovanje mape"</string>
-    <string name="rename_action" msgid="5559600076028658757">"V redu"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Prekliči"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Dodaj na začetni zaslon"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikacije"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Bližnjice"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Pripomočki"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Na začetnih zaslonih ni več prostora."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Iskanje po aplikacijah"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Nalaganje aplikacij …"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Ni aplikacij, ki bi ustrezale poizvedbi »<xliff:g id="QUERY">%1$s</xliff:g>«"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Na tem začetnem zaslonu ni več prostora."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"V vrstici za priljubljene ni več prostora"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ta pripomoček je prevelik za vrstico s priljubljenimi"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Bližnjica »<xliff:g id="NAME">%s</xliff:g>« je ustvarjena."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Bližnjica »<xliff:g id="NAME">%s</xliff:g>« je bila odstranjena."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Bližnjica »<xliff:g id="NAME">%s</xliff:g>« že obstaja."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Izberite bližnjico"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Izberite aplikacijo"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacije"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Začetni zaslon"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Odstrani"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Odstrani"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Odstrani"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Odstrani"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Podatki o aplikaciji"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikacije"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Odstrani"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Odstrani posodobitev"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Odstrani aplikacijo"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Podrobnosti o aplikaciji"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Izbrana je 1 aplikacija"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Izbran je 1 pripomoček"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Izbrana je 1 mapa"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Izbrana je 1 bližnjica"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"namestitev bližnjic"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Aplikaciji dovoli dodajanje bližnjic brez posredovanja uporabnika."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"odstranitev bližnjic"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Aplikaciji dovoli odstranjevanje bližnjic brez posredovanja uporabnika."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"branje nastavitev in bližnjic na začetnem zaslonu"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Aplikaciji dovoli branje nastavitev in bližnjic na začetnem zaslonu."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"zapis nastavitev in bližnjic na začetnem zaslonu"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Težava pri nalaganju pripomočka"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Nastavitev"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"To je sistemska aplikacija in je ni mogoče odstraniti."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Raketno izstrelišče"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Neimenovana mapa"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Začetni zaslon %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Stran aplikacij %1$d od %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Stran pripomočkov %1$d od %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Pozdravljeni"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Počutite se kot doma."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Ustvarite več zaslonov za aplikacije in mape"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiranje ikon aplikacij"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Želite uvoziti ikone in mape iz starih začetnih zaslonov?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIRAJ IKONE"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"SVEŽ ZAČETEK"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizirajte svoj prostor"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Če želite upravljati ozadje, pripomočke in nastavitve, se dotaknite ozadja in ga pridržite."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Ozadja, pripomočki in nastavitve"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Za prilagajanje se dotaknite ozadja in ga pridržite"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"V REDU"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"To je mapa"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Če želite ustvariti mapo, podobno tej, se dotaknite aplikacije in jo pridržite, nato pa jo premaknite nad drugo."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"V redu"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mapa je odprta, <xliff:g id="WIDTH">%1$d</xliff:g> krat <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Dotaknite se, da zaprete mapo"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Dotaknite se, da shranite preimenovanje"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Pripomočki"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Ozadja"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Nastavitve"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Čakanje"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Prenašanje"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Nameščanje"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Omogočanje zasuka"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Neznano"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ni obnovljen"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Odstrani vse"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Odstrani"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Iskanje"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ta aplikacija ni nameščena."</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za to ikono ni nameščena. Lahko jo odstranite ali poiščete aplikacijo in to namestite ročno."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Dodajanje na začetni zaslon"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Premik elementa sem"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Element je bil dodan na začetni zaslon"</string>
+    <string name="item_removed" msgid="851119963877842327">"Element je bil odstranjen"</string>
+    <string name="action_move" msgid="4339390619886385032">"Premik elementa"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Premik v <xliff:g id="NUMBER_0">%1$s</xliff:g>. vrstico <xliff:g id="NUMBER_1">%2$s</xliff:g>. stolpca"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Premk na mesto št. <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Premik na mesto priljubljenih št. <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element je premaknjen"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Dodajanje v mapo: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodajanje v mapo z aplikacijo <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element je dodan v mapo"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Ustvarjanje mape s tem: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mapa je ustvarjena"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Premik na začetni zaslon"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Premik zaslona levo"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Premika zaslona desno"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Zaslon je bil premaknjen"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Spreminjanje velikosti"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Povečanje širine"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Povečanje višine"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Zmanjšanje širine"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Zmanjšanje višine"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Velikost pripomočka je bila spremenjena na <xliff:g id="NUMBER_0">%1$s</xliff:g> širine in <xliff:g id="NUMBER_1">%2$s</xliff:g> višine"</string>
 </resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml
index 16afcf3..65aabf6 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq-rAL/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Nisësi3"</string>
-    <string name="home" msgid="7658288663002113681">"Ekrani bazë"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Aplikacionet bazë të androidit"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Puna"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Aplikacioni nuk është i instaluar."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Aplikacioni nuk mundësohet"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Aplikacioni i shkarkuar është i çaktivizuar në modalitetin e sigurt"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Miniaplikacionet janë të çaktivizuara në modalitetin e sigurt"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Miniaplikacionet"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Miniaplikacionet"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Trego memorandumin"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Prek dhe mbaj shtypur për të zgjedhur një miniaplikacion."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Nuk mundi ta lëshonte artikullin në këtë ekran bazë."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Zgjidh miniaplikacionin për të krijuar"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Emri i dosjes"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Riemërto dosjen"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Në rregull"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Anulo"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Shto në ekranin bazë"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Aplikacionet"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Shkurtoret"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Miniaplikacionet"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Nuk ka më hapësirë në ekranet e tua bazë."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Kërko për aplikacione"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Po ngarkon aplikacionet..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Nuk u gjet asnjë aplikacion që përputhet me \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Nuk ka më hapësirë në këtë ekran bazë."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ky miniaplikacion është shumë i madh për tabakanë \"Të preferuarat\""</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Shkurtorja \"<xliff:g id="NAME">%s</xliff:g>\" u krijua."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Shkurtorja \"<xliff:g id="NAME">%s</xliff:g>\" u hoq."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Shkurtorja \"<xliff:g id="NAME">%s</xliff:g>\" ekziston."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Zgjidh shkurtoren"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Zgjidh aplikacionin"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Aplikacionet"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Faqja kryesore"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Hiq"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Çinstalo"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Hiq"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Çinstalo"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Informacion mbi aplikacionin"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Aplikacionet"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Hiq"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Çinstalo përditësimin"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Çinstalo aplikacionin"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Detajet e aplikacionit"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"U përzgjodh 1 aplikacion"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 miniaplikacion i përzgjedhur"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"U përzgjodh 1 dosje"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 shkurtore e përzgjedhur"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"instalo shkurtore"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Lejon një aplikacion të shtojë shkurtore pa ndërhyrjen e përdoruesit."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"çinstalo shkurtoret"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Lejon aplikacionin të heqë shkurtore pa ndërhyrjen e përdoruesit."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"lexo cilësimet dhe shkurtoret e ekranit bazë"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Lejon aplikacionin të lexojë cilësimet dhe shkurtoret në ekranin bazë."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"shkruaj cilësimet dhe shkurtoret e ekranit bazë"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problem në ngarkimin e miniaplikacionit"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguro"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ky është aplikacion sistemi dhe nuk mund të çinstalohet."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Nisësi raketor"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Dosje e paemërtuar"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Ekrani bazë: %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Faqja e aplikacioneve: %1$d nga gjithsej %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Faqja e miniaplikacioneve: %1$d nga gjithsej %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Mirë se erdhe"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Ndihu si në shtëpinë tënde."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Krijo më shumë ekrane për aplikacione dhe dosje"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopjo ikonat e aplikacionit"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Të importohen ikona dhe dosje nga ekranet e vjetra bazë?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPJO IKONA"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"FILLO NGA E PARA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organizo hapësirën tënde"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Prek dhe mbaj shtypur sfondin për të menaxhuar imazhin në sfond, miniaplikacionet dhe cilësimet."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Imazhe në sfond, miniaplikacione dhe cilësime"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Prek dhe mbaj shtypur sfondin për ta personalizuar."</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"E KUPTOVA!"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Këtu ka një dosje"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Për të krijuar një të tillë, prek dhe mbaje aplikacionin, pastaj kaloje në një tjetër."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Në rregull"</string>
     <string name="folder_opened" msgid="94695026776264709">"Dosja u hap, <xliff:g id="WIDTH">%1$d</xliff:g> me <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Prek për të afruar dosjen"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Prek për të ruajtur riemërtimin"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Miniaplikacionet"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Imazhet e sfondit"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Cilësimet"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Po pret"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Po shkarkohet"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Po instalohet"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Lejo rotacionin"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"I panjohur"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Nuk u restaurua"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Hiqi të gjitha"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Hiq"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Kërko"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Aplikacioni nuk është i instaluar"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacioni për këtë ikonë nuk është i instaluar. Mund ta heqësh ose të kërkosh aplikacionin dhe ta instalosh atë në mënyrë manuale."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Shto në Ekranin bazë"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Zhvendose artikullin këtu"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Artikulli u shtua tek ekrani bazë"</string>
+    <string name="item_removed" msgid="851119963877842327">"Artikulli u hoq"</string>
+    <string name="action_move" msgid="4339390619886385032">"Zhvendose artikullin"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Zhvendos te rreshti <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolona <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Zhvendos te pozicioni <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Zhvendos te pozicioni <xliff:g id="NUMBER">%1$s</xliff:g> i preferencave"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Artikulli u zhvendos"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Shto te dosja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Shto te dosja me <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Artikulli u shtua te dosja"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Krijo një dosje me: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Dosja u krijua"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Zhvendose në Ekranin bazë"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Zhvendose ekranin në të majtë"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Zhvendose ekranin në të djathtë"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekrani u zhvendos"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ndrysho madhësinë"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Rrit gjerësinë"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Rrit lartësinë"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Zvogëlo gjerësinë"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Zvogëlo lartësinë"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Madhësia e miniaplikacionit u ndryshua me gjerësinë <xliff:g id="NUMBER_0">%1$s</xliff:g> dhe lartësinë <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 9f40890..0f93bf3 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Почетна"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Основне Android апликације"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Апликација није инсталирана."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Апликација није доступна"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преузета апликација је онемогућена у Безбедном режиму"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Виџети су онемогућени у Безбедном режиму"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Виџети"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Виџети"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Прикажи меморију"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Додирните и задржите да бисте изабрали виџет."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Није могуће отпустити ставку на почетни екран."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Избор виџета за прављење"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Назив директоријума"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Преименовање директоријума"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Потврди"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Откажи"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Додавање на почетни екран"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Апликације"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Пречице"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Виџети"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Нема више простора на почетним екранима."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Претражите апликације"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Апликације се учитавају..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Нема више простора на овом почетном екрану."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема више простора на траци Омиљено"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Виџет је превелик за траку Омиљено"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Пречица „<xliff:g id="NAME">%s</xliff:g>“ је направљена."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Пречица „<xliff:g id="NAME">%s</xliff:g>“ је уклоњена."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Пречица „<xliff:g id="NAME">%s</xliff:g>“ већ постоји."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Избор пречице"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Избор апликације"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Апликације"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Почетна"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Уклони"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Деинсталирај"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Уклони"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Деинсталирај"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Информације о апликацији"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Апликације"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Уклони"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Деинсталирај ажурирање"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Деинсталирање апликације"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Детаљи о апликацији"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Изабрана је 1 апликација"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Изабран је 1 виџет"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Изабран је 1 директоријум"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Изабрана је 1 пречица"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"деинсталирање пречица"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Дозвољава апликацији да уклања пречице без интервенције корисника."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"читање подешавања и пречица на почетном екрану"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Дозвољава апликацији да чита подешавања и пречице на почетном екрану."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"уписивање подешавања и пречица на почетном екрану"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Проблем при учитавању виџета"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Подешавање"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ово је системска апликација и не може да се деинсталира."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Лансер ракета"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Неименовани директоријум"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Почетни екран %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%1$d. страница апликација од %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%1$d. страница виџета од %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Добро дошли"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Осећајте се као код куће."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Направите још екрана за апликације и директоријуме"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Копирајте иконе апликација"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Увести иконе и директоријуме са старих почетних екрана?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПИРАЈТЕ ИКОНЕ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ПОЧНИТЕ ИСПОЧЕТКА"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Организујте простор"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Додирните позадину и задржите да бисте управљали позадином, виџетима и подешавањима."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Позадине, виџети и подешавања"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Додирните и задржите позадину да бисте прилагодили"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ВАЖИ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Ево једног директоријума"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Да бисте направили директоријум попут овога, додирните и задржите апликацију, па је превуците преко друге."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Потврди"</string>
     <string name="folder_opened" msgid="94695026776264709">"Директоријум је отворен, <xliff:g id="WIDTH">%1$d</xliff:g> пута <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Додирните да бисте затворили директоријум"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Додирните да бисте сачували промену имена"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Позадине"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Подешавања"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Чека се"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Преузима се"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Инсталира се"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Дозволи ротацију"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Није враћено"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Уклони све"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Уклони"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Претражи"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ова апликација није инсталирана"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликација за ову икону није инсталирана. Можете да је уклоните или да потражите апликацију и инсталирате је ручно."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Додај на почетни екран"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Премести ставку овде"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставка је додата на почетни екран"</string>
+    <string name="item_removed" msgid="851119963877842327">"Ставка је уклоњена"</string>
+    <string name="action_move" msgid="4339390619886385032">"Премести ставку"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Премести у ред <xliff:g id="NUMBER_0">%1$s</xliff:g> и колону <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију у омиљеним"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Ставка је премештена"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Додај у директоријум: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додај у директоријум у коме је <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Ставка је додата у директоријум"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Направите директоријум са: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Директоријум је направљен"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Премести на почетни екран"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Помери екран улево"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Помери екран удесно"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Екран је померен"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Промени величину"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Повећај ширину"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Повећај висину"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Смањи ширину"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Смањи висину"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Величина виџета је промењена на ширину <xliff:g id="NUMBER_0">%1$s</xliff:g> и висину <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 25f4d26..93fce80 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Startskärm"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Arbete"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Appen är inte installerad."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Appen är inte tillgänglig"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Den hämtade appen inaktiverades i säkert läge"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets är inaktiverade i felsäkert läge"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widgetar"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widgetar"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Visa Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Tryck länge om du vill flytta en widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Objektet kunde inte släppas på startskärmen."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Ange vilken widget du vill använda"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Mappnamn"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Byt namn på mapp"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Avbryt"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Lägg till på startskärmen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Appar"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Genvägar"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widgetar"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Det finns inte plats för mer på dina startsidor."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sök efter appar"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Läser in appar …"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Det gick inte att hitta några appar som matchar <xliff:g id="QUERY">%1$s</xliff:g>"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Det finns inte plats för mer på den här startskärmen."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoritfältet är fullt"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Denna widget är för stor för favoritfältet"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Genvägen <xliff:g id="NAME">%s</xliff:g> har skapats."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Genvägen <xliff:g id="NAME">%s</xliff:g> har tagits bort."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Genvägen <xliff:g id="NAME">%s</xliff:g> finns redan."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Välj genväg"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Välj app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Appar"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Startskärm"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Ta bort"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Avinstallera"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Ta bort"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Avinstallera"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Info om appen"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Appar"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Ta bort"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Avinstallera uppdatering"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Avinstallera appen"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Information om appen"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"En app har valts"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"En widget har valts"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"En mapp har valts"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"En genväg har valts"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"installera genvägar"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Tillåter att en app lägger till genvägar utan åtgärd från användaren."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"avinstallera genvägar"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Tillåter att appen tar bort genvägar utan åtgärd från användaren."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"läsa inställningar och genvägar för startsidan"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Tillåter att appen läser inställningar och genvägar på startsidan."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"skriva inställningar och genvägar för startsidan"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Det gick inte att läsa in widgeten"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Konfiguration"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Det här är en systemapp som inte kan avinstalleras."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Namnlös mapp"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Startskärmen %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Appsida %1$d av %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widget-sida %1$d av %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Välkommen"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Känn dig som hemma."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Skapa fler skärmar för appar och mappar"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopiera appikoner"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Vill du importera ikoner och mappar från gamla startskärmar?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPIERA IKONER"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"BÖRJA OM"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Organisera ditt utrymme"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Tryck länge på bakgrunden om du vill hantera bakgrundsbilder, widgetar och inställningar."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Bakgrunder, widgetar och inställningar"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Tryck länge på bakgrunden om du vill anpassa den"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Det här är en mapp"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Skapa en till mapp av det här slaget genom att trycka och hålla ned en app och sedan dra den ovanpå en annan."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Mappen är öppen, <xliff:g id="WIDTH">%1$d</xliff:g> gånger <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Tryck om du vill stänga mappen"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Tryck om du vill spara det nya namnet"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widgetar"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Bakgrunder"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Inställningar"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Väntar"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Hämtas"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Installerar"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Tillåt rotering"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Okänt"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Inte återställt"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Ta bort alla"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ta bort"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Sök"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Appen är inte installerad"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Appen för den här ikonen har inte installerats. Du kan ta bort den eller söka efter appen och installera den manuellt."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Lägg till på startskärmen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Flytta objekt hit"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Objektet har lagts till på startskärmen"</string>
+    <string name="item_removed" msgid="851119963877842327">"Objektet har tagits bort"</string>
+    <string name="action_move" msgid="4339390619886385032">"Flytta objekt"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Flytta till rad <xliff:g id="NUMBER_0">%1$s</xliff:g>, kolumn <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Flytta till plats <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Flytta till favoritplats <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Objektet har flyttats"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Lägg till i mapp: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Lägg till i mappen med <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Objektet har lagts till i mappen"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Skapa mapp med: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Mappen har skapats"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Flytta till startskärmen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Flytta skärmen till vänster"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Flytta skärmen till höger"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skärmen har flyttats"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Ändra storlek"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Öka bredden"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Öka höjden"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Minska bredden"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Minska höjden"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widgetens storlek har ändrats till: bredd <xliff:g id="NUMBER_0">%1$s</xliff:g>, höjd <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index fa81061..297b731 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Kizindua3"</string>
-    <string name="home" msgid="7658288663002113681">"Mwanzo"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Programu Msingi za Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Kazini"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Programu haijasakinishwa."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Programu haipatikani"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Programu iliyopakuliwa imezimwa katika Hali Salama"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Wijeti zimezimwa katika hali ya Usalama"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Wijeti"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Wijeti"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Onyesha Kumbukumbu"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Gusa na ushikilie ili kuteua wijeti."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Haikuweza kudondosha kipengee kwenye skrini hii ya Kwanza."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Chagua wijeti ili uunde"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Jina la folda"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"lipe folda jina jipya"</string>
-    <string name="rename_action" msgid="5559600076028658757">"SAWA"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Ghairi"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Ongeza kwenye skrini ya Mwanzo"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Programu"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Njia za mkato"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Wijeti"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Hakuna nafasi zaidi kwenye skrini zako za Nyumbani."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tafuta Programu"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Inapakia Programu..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Haikupata programu zinazolingana na \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Hakuna nafasi katika skrini hii ya Mwanzo."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Hakuna nafasi zaidi katika treya ya Vipendeleo"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Wijeti hii ni kubwa mno kwa treya ya Vipendeleo"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Njia ya mkato ya \"<xliff:g id="NAME">%s</xliff:g>\" imeundwa."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Njia ya mkato ya \"<xliff:g id="NAME">%s</xliff:g>\" iliondolewa."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" la njia ya mkato tayari lipo."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Chagua njia ya mkato"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Chagua programu"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Programu"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Mwanzo"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Ondoa"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Ondoa"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Ondoa"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Ondoa"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Maelezo ya programu"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Programu"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Ondoa"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Ondoa sasisho"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Ondoa programu"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Maelezo ya programu"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Programu 1 imechaguliwa"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Wijeti 1 imechaguliwa"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Folda 1 limechaguliwa"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Njia 1 ya mkato imechaguliwa"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kuweka njia za mkato"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Huruhusu programu kuongeza njia za mkato bila mtumiaji kuingilia kati."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ondoa njia za mikato"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Huruhusu programu kuondoa njia za mikato bila mtumiaji kuingilia kati."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"soma mipangilio ya Mwanzo na njia za mkato"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Huruhusu programu kusoma mipangilio na njia za mikato zilizo katika skirini ya Mwanzo."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"andika mipangilio ya skrini ya Mwanzo na njia za mkato"</string>
@@ -78,32 +48,19 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Tatizo la kupakia wijeti"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sanidi"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Hii ni programu ya mfumo na haiwezi kuondolewa."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Kizinduzi cha Roketi"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Folda isiyo na jina"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Skrini ya mwazo %1$d"</string>
     <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) -->
     <skip />
-    <string name="apps_customize_apps_scroll_format" msgid="370005296147130238">"Ukurasa wa programu %1$d ya %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Ukurasa wa wijeti %1$d ya %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Karibu"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Jisikie huru."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Unda skrini zaidi za programu na folda"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Nakili ikoni za programu yako"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Je, ungependa kuingiza ikoni na folda kutoka kwenye skrini zako za Mwanzo za zamani?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"NAKILI IKONI"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ANZA UPYA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Panga nafasi yako"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Gusa na ushikilie mandharinyuma ili udhibiti mandhari, wijeti, na mipangilio."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Mandhari, wijeti, na mipangilio"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Gusa na ushikilie mandhari ili uweke mapendeleo"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NIMEELEWA"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Hii ni folda"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ili kuunda kama hii, gusa na ushikilie programu, kisha ipitishe juu ya nyingine."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"SAWA"</string>
     <string name="folder_opened" msgid="94695026776264709">"Folda imefunguliwa, <xliff:g id="WIDTH">%1$d</xliff:g> kwa <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Gusa ili ufunge folda"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Gusa ili uhifadhi jina jipya"</string>
@@ -113,14 +70,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Wijeti"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Mandhari"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Mipangilio"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Inasubiri"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Inapakua"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Inasakinisha"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Ruhusu kuzungusha"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Yasiyojulikana"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Haijarejeshwa"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Ondoa Zote"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Ondoa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Tafuta"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Programu hii haijasakinishwa"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Programu ya ikoni hii haijasakinishwa. Unaweza kuiondoa, au utafute programu na uisakinishe wewe mwenyewe."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Ongeza kwenye skrini ya Kwanza"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Hamishia kipengee hapa"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Kipengee kimeongezwa kwenye skrini ya kwanza"</string>
+    <string name="item_removed" msgid="851119963877842327">"Kipengee kimeondolewa"</string>
+    <string name="action_move" msgid="4339390619886385032">"Hamisha kipengee"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Hamishia safu mlalo <xliff:g id="NUMBER_0">%1$s</xliff:g> safu wima <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Hamishia nafasi ya <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Hamishia nafasi inayopendwa ya <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Kipengee kimesogezwa"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Ongeza kwenye folda: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Ongeza kwenye folda iliyo na <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Kipengee kimeongezwa kwenye folda"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Unda folda ukitumia: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folda imeundwa"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Hamishia Skrini ya kwanza"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Sogeza skrini kushoto"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Sogeza skrini kulia"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Skrini imesogezwa"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Badilisha ukubwa"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Ongeza upana"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Ongeza urefu"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Punguza upana"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Punguza urefu"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Wijeti imepunguzwa hadi upana <xliff:g id="NUMBER_0">%1$s</xliff:g> urefu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index 15d5725..a7345a7 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -4,8 +4,4 @@
 
 <!-- DragController -->
     <integer name="config_flingToDeleteMinVelocity">-1000</integer>
-
-    <!-- Camera distance for the overscroll effect. We use a higher value here because the 
-         workspace screens run nearly flush to the edge of the screen-->
-    <integer name="config_cameraDistance">14000</integer>
 </resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 28679be..2651fbb 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -15,14 +15,10 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">64dp</dimen>
-
-<!-- AppsCustomize -->
-    <dimen name="apps_customize_tab_bar_height">60dp</dimen>
-    <dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
-    <dimen name="app_widget_preview_label_margin_top">8dp</dimen>
-    <dimen name="app_widget_preview_label_margin_left">@dimen/app_widget_preview_padding_left</dimen>
-    <dimen name="app_widget_preview_label_margin_right">@dimen/app_widget_preview_padding_right</dimen>
+<!-- All Apps -->
+    <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
+    <dimen name="all_apps_grid_section_text_size">26sp</dimen>
+    <dimen name="all_apps_icon_top_bottom_padding">12dp</dimen>
 
 <!-- Cling -->
     <dimen name="cling_migration_logo_height">400dp</dimen>
diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml
deleted file mode 100644
index bcbbafd..0000000
--- a/res/values-sw600dp/styles.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2012 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT 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>
-</resources>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index ca13db0..514980f 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -15,10 +15,6 @@
 -->
 
 <resources>
-<!-- AppsCustomize -->
-    <integer name="apps_customize_widget_cell_count_x">4</integer>
-    <integer name="apps_customize_widget_cell_count_y">2</integer>
-
     <!-- the area at the edge of the screen that makes the workspace go left
          or right while you're dragging. -->
     <dimen name="scroll_zone">100dip</dimen>
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index c00b594..94cffcb 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -2,17 +2,10 @@
     <bool name="config_largeHeap">true</bool>
     <bool name="is_large_tablet">true</bool>
 
-<!-- AllApps/Customize/AppsCustomize -->
+<!-- All Apps & Widgets -->
     <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
     <integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
 
-<!-- Workspace -->
-    <!-- Whether or not the drop targets drop down as opposed to fade in -->
-    <bool name="config_useDropTargetDownTransition">false</bool>
-
-    <!-- Camera distance for the overscroll effect -->
-    <integer name="config_cameraDistance">18000</integer>
-
 <!-- Hotseat -->
     <bool name="hotseat_transpose_layout_with_orientation">false</bool>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 8be9964..d48f9ee 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -15,17 +15,14 @@
 -->
 
 <resources>
-    <dimen name="app_icon_size">72dp</dimen>
+<!-- All Apps -->
+    <dimen name="all_apps_search_bar_height">54dp</dimen>
+    <dimen name="all_apps_icon_top_bottom_padding">14dp</dimen>
 
 <!-- QSB -->
     <dimen name="toolbar_button_vertical_padding">8dip</dimen>
     <dimen name="toolbar_button_horizontal_padding">8dip</dimen>
 
-    <!-- When dragging items on the workspace, the number of dps by which the position of
-     the drag view should be offset from the position of the original view. -->
-    <dimen name="dragViewOffsetX">0dp</dimen>
-    <dimen name="dragViewOffsetY">0dp</dimen>
-
 <!-- Cling -->
     <dimen name="cling_migration_content_margin">96dp</dimen>
     <dimen name="cling_migration_content_width">320dp</dimen>
diff --git a/res/values-sw720dp/styles.xml b/res/values-sw720dp/styles.xml
index cbc1e29..e8b706e 100644
--- a/res/values-sw720dp/styles.xml
+++ b/res/values-sw720dp/styles.xml
@@ -27,7 +27,7 @@
         <item name="android:layout_height">match_parent</item>
     </style>
 
-    <style name="DropTargetButton" parent="DropTargetButton.Base">
+    <style name="DropTargetButton" parent="DropTargetButtonBase">
         <item name="android:paddingLeft">60dp</item>
         <item name="android:paddingRight">60dp</item>
         <item name="android:shadowColor">#393939</item>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 9dba6f6..1f2a6f9 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"லாஞ்சர்3"</string>
-    <string name="home" msgid="7658288663002113681">"முகப்பு"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android முக்கியப் பயன்பாடுகள்"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"பணியிடம்"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"பயன்பாடு நிறுவப்படவில்லை."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"பயன்பாடு இல்லை"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"இறக்கிய பயன்பாடு பாதுகாப்பு முறையில் முடக்கப்பட்டது"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"பாதுகாப்புப் பயன்முறையில் விட்ஜெட்கள் முடக்கப்பட்டுள்ளன"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ஷார்ட்கட்ஸ்"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ஷார்ட்கட்ஸ்"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"நினைவகத்தைக் காட்டு"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"விட்ஜெட்டைத் தேர்வுசெய்ய தொட்டுப் பிடிக்கவும்."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"உருப்படியை இந்த முகப்புத் திரையில் விட முடியவில்லை."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"உருவாக்குவதற்கு விட்ஜெட்டைத் தேர்வுசெய்யவும்"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"கோப்புறையின் பெயர்"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"கோப்புறைக்கு மறுபெயரிடு"</string>
-    <string name="rename_action" msgid="5559600076028658757">"சரி"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ரத்துசெய்"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"முகப்புத் திரையில் சேர்"</string>
-    <string name="group_applications" msgid="3797214114206693605">"பயன்பாடுகள்"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"குறுக்குவழிகள்"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ஷார்ட்கட்ஸ்"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"உங்கள் முகப்புத் திரைகளில் வேறு இடம் இல்லை."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"பயன்பாடுகளில் தேடுக"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"பயன்பாடுகளை ஏற்றுகிறது..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"</string>
     <string name="out_of_space" msgid="4691004494942118364">"முகப்புத் திரையில் இடமில்லை."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"பிடித்தவை ட்ரேயில் இடமில்லை"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"பிடித்தவை ட்ரேவிற்கு விட்ஜெட் மிகவும் பெரியது"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி உருவாக்கப்பட்டது."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி அகற்றப்பட்டது."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" குறுக்குவழி ஏற்கனவே உள்ளது."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"குறுக்குவழியைத் தேர்வுசெய்யவும்"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"பயன்பாட்டைத் தேர்வுசெய்யவும்"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"பயன்பாடுகள்"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"முகப்பு"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"அகற்று"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"நிறுவல் நீக்கு"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"அகற்று"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"நிறுவல் நீக்கு"</string>
     <string name="info_target_label" msgid="8053346143994679532">"பயன்பாட்டுத் தகவல்"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"பயன்பாடுகள்"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"அகற்று"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"புதுப்பிப்பை நிறுவல் நீக்கு"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"பயன்பாட்டை நிறுவல் நீக்கு"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"பயன்பாட்டின் விவரங்கள்"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 பயன்பாடு தேர்ந்தெடுக்கப்பட்டது"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 விட்ஜெட் தேர்ந்தெடுக்கப்பட்டது"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 கோப்புறை தேர்ந்தெடுக்கப்பட்டது"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 குறுக்குவழி தேர்ந்தெடுக்கப்பட்டது"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"குறுக்குவழிகளை நிறுவுதல்"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளைச் சேர்க்கப் பயன்பாட்டை அனுமதிக்கிறது."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"குறுக்குவழிகளை நிறுவல் நீக்குதல்"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"பயனரின் அனுமதி இல்லாமல் குறுக்குவழிகளை அகற்ற பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"முகப்பின் அமைப்பு மற்றும் குறுக்குவழிகளைப் படித்தல்"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"முகப்பில் உள்ள அமைப்பு மற்றும் குறுக்குவழிகளைப் படிக்க பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"முகப்பின் அமைப்பு மற்றும் குறுக்குவழிகளை எழுதுதல்"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"விட்ஜெட்டை ஏற்றுவதில் சிக்கல்"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"அமைவு"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"இது அமைப்பு பயன்பாடு என்பதால் நிறுவல் நீக்கம் செய்ய முடியாது."</string>
-    <string name="dream_name" msgid="1530253749244328964">"ராக்கெட் லாஞ்சர்"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"பெயரிடப்படாத கோப்புறை"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"முகப்புத் திரை %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"பயன்பாடுகளின் பக்கம் %1$d / %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"விட்ஜெட்களின் பக்கம் %1$d / %2$d"</string>
-    <string name="first_run_cling_title" msgid="2459738000155917941">"வரவேற்கிறோம்"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"உங்களுக்கேற்ற முறையில் உருவாக்கவும்."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"பயன்பாடுகள் மற்றும் கோப்புறைகளுக்காகக் கூடுதல் திரைகளை உருவாக்கவும்"</string>
+    <string name="first_run_cling_title" msgid="2459738000155917941">"நல்வரவு"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"பயன்பாட்டின் ஐகான்களை நகலெடுக்கவும்"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"பழைய முகப்புத் திரைகளிலிருந்து ஐகான்களையும் கோப்புறைகளையும் இறக்குமதி செய்யவா?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"ஐகான்களை நகலெடு"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"புதிதாகத் தொடங்கு"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"இடத்தை ஒழுங்கமைக்கவும்"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"வால்பேப்பர், விட்ஜெட்கள், அமைப்பை நிர்வகிக்க பின்புலத்தைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"வால்பேப்பர்கள், விட்ஜெட்கள் &amp; அமைப்புகள்"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"தனிப்பயனாக்க, பின்னணியைத் தொட்டுப் பிடிக்கவும்"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"புரிந்தது"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"இதோ கோப்புறை"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"இதுபோன்ற ஒன்றை உருவாக்க பயன்பாட்டைத் தொட்டுப் பிடிக்கவும், பிறகு அதை வேறொன்றிற்கு நகர்த்தவும்."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"சரி"</string>
     <string name="folder_opened" msgid="94695026776264709">"திறக்கப்பட்டக் கோப்புறை, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"கோப்புறையை மூட, தொடவும்"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"மறுபெயரிட்டதைச் சேமிக்க, தொடவும்"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ஷார்ட்கட்ஸ்"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"வால்பேப்பர்கள்"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"அமைப்பு"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"காத்திருக்கிறது"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"பதிவிறக்குகிறது"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"நிறுவுகிறது"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"சுழற்ற அனுமதி"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"தெரியாதது"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"மீட்டெடுக்க முடியாது"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"அனைத்தையும் அகற்று"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"அகற்று"</string>
     <string name="abandoned_search" msgid="891119232568284442">"தேடு"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"பயன்பாடு நிறுவப்படவில்லை"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ஐகானுக்கான பயன்பாடு நிறுவப்படவில்லை. இதை அகற்றலாம் அல்லது பயன்பாட்டைத் தேடி கைமுறையாக நிறுவலாம்."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"முகப்புத் திரையில் சேர்"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"இங்கு நகர்த்து"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
+    <string name="item_removed" msgid="851119963877842327">"அகற்றப்பட்டது"</string>
+    <string name="action_move" msgid="4339390619886385032">"நகர்த்து"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> வரிசை, <xliff:g id="NUMBER_1">%2$s</xliff:g> நெடுவரிசைக்கு நகர்த்து"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"நிலை <xliff:g id="NUMBER">%1$s</xliff:g>க்கு நகர்த்து"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"விரும்பும் நிலை <xliff:g id="NUMBER">%1$s</xliff:g>க்கு நகர்த்து"</string>
+    <string name="item_moved" msgid="4606538322571412879">"உருப்படி நகர்த்தப்பட்டது"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"இந்தக் கோப்புறையில் சேர்க்கும்: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> உள்ள கோப்புறையில் சேர்க்கும்"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"கோப்புறையில் உருப்படி சேர்க்கப்பட்டது"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"இதனுடன் கோப்புறையை உருவாக்கும்: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"கோப்புறை உருவாக்கப்பட்டது"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"முகப்புத் திரைக்கு நகர்த்து"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"திரையை இடப்புறம் நகர்த்து"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"திரையை வலப்புறம் நகர்த்து"</string>
+    <string name="screen_moved" msgid="266230079505650577">"திரை நகர்த்தப்பட்டது"</string>
+    <string name="action_resize" msgid="1802976324781771067">"அளவு மாற்று"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"அகலத்தை அதிகரி"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"உயரத்தை அதிகரி"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"அகலத்தைக் குறை"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"உயரத்தைக் குறை"</string>
+    <string name="widget_resized" msgid="9130327887929620">"அகலம் <xliff:g id="NUMBER_0">%1$s</xliff:g> மற்றும் உயரம் <xliff:g id="NUMBER_1">%2$s</xliff:g>க்கு விட்ஜெட் அளவு மாற்றப்பட்டது"</string>
 </resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index bfbc792..bd5fd70 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"లాంచర్3"</string>
-    <string name="home" msgid="7658288663002113681">"హోమ్"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android ప్రధాన అనువర్తనాలు"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"కార్యాలయం"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"అనువర్తనం ఇన్‌స్టాల్ చేయబడలేదు."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"అనువర్తనం అందుబాటులో లేదు"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"డౌన్‌లోడ్ చేసిన అనువర్తనం సురక్షిత మోడ్‌లో నిలిపివేయబడింది"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"సురక్షిత మోడ్‌లో విడ్జెట్‌లు నిలిపివేయబడ్డాయి"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"విడ్జెట్‌లు"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"విడ్జెట్‌లు"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"మెమరీ చూపు"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"విడ్జెట్‌ను ఎంచుకోవడానికి తాకి &amp; నొక్కి పెట్టండి."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ఈ హోమ్ స్క్రీన్‌లో అంశాన్ని వదలడం సాధ్యపడలేదు."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"సృష్టించాల్సిన విడ్జెట్ ఎంచుకోండి"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ఫోల్డర్ పేరు"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"ఫోల్డర్‌ పేరు మార్చండి"</string>
-    <string name="rename_action" msgid="5559600076028658757">"సరే"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"రద్దు చేయి"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"హోమ్ స్క్రీన్‌కు జోడించు"</string>
-    <string name="group_applications" msgid="3797214114206693605">"అనువర్తనాలు"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"సత్వరమార్గాలు"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"విడ్జెట్‌లు"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"మీ హోమ్ స్క్రీన్‌ల్లో ఖాళీ లేదు."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"అనువర్తనాలను శోధించండి"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"అనువర్తనాలను లోడ్ చేస్తోంది…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"కి సరిపోలే అనువర్తనాలేవీ కనుగొనబడలేదు"</string>
     <string name="out_of_space" msgid="4691004494942118364">"ఈ హోమ్ స్క్రీన్‌లో ఖాళీ లేదు."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"ఇష్టమైనవి ట్రే కోసం ఈ విడ్జెట్ చాలా పెద్దదిగా ఉంది"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" సృష్టించబడింది."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" తీసివేయబడింది."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"సత్వరమార్గం \"<xliff:g id="NAME">%s</xliff:g>\" ఇప్పటికే ఉంది."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"సత్వరమార్గాన్ని ఎంచుకోండి"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"అనువర్తనాన్ని ఎంచుకోండి"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"అనువర్తనాలు"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"హోమ్"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"తీసివేయి"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"అన్ఇన్‌స్టాల్ చేయి"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"తీసివేయి"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"అన్ఇన్‌స్టాల్ చేయి"</string>
     <string name="info_target_label" msgid="8053346143994679532">"అనువర్తన సమాచారం"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"అనువర్తనాలు"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"తీసివేయి"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"నవీకరణను అన్‌ఇన్‌స్టాల్ చేయి"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"అనువర్తనాన్ని అన్‌ఇన్‌స్టాల్ చేయి"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"అనువర్తన వివరాలు"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 అనువర్తనం ఎంచుకోబడింది"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 విడ్జెట్ ఎంచుకోబడింది"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ఫోల్డర్ ఎంచుకోబడింది"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 సత్వరమార్గం ఎంచుకోబడింది"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"సత్వరమార్గాలను ఇన్‌స్టాల్ చేయడం"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను జోడించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"సత్వరమార్గాలను అన్ఇన్‌స్టాల్ చేయడం"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"వినియోగదారు ప్రమేయం లేకుండా సత్వరమార్గాలను తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"హోమ్ సెట్టింగ్‌లు మరియు సత్వరమార్గాలను చదవడం"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"హోమ్‌లో సెట్టింగ్‌లు మరియు సత్వరమార్గాలను చదవడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"హోమ్ సెట్టింగ్‌లు మరియు సత్వరమార్గాలను వ్రాయడం"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"విడ్జెట్‌ను లోడ్ చేయడంలో సమస్య"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"సెటప్ చేయి"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"ఇది సిస్టమ్ అనువర్తనం మరియు దీన్ని అన్‌ఇన్‌స్టాల్ చేయడం సాధ్యపడదు."</string>
-    <string name="dream_name" msgid="1530253749244328964">"రాకెట్ లాంచర్"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"పేరు లేని ఫోల్డర్"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"హోమ్ స్క్రీన్ %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"%2$dలో %1$dవ అనువర్తనాల పేజీ"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"%2$dలో %1$dవ విడ్జెట్‌‌ల పేజీ"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"స్వాగతం"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"మీ స్వంత స్థలంగా భావించండి."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"అనువర్తనాలు మరియు ఫోల్డర్‌ల కోసం మరిన్ని స్క్రీన్‌లు సృష్టి."</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"మీ అనువర్తన చిహ్నాలను కాపీ చేయండి"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"మీ పాత హోమ్ స్క్రీన్‌ల నుండి చిహ్నాలు మరియు ఫోల్డర్‌లను దిగుమతి చేయాలా?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"చిహ్నాలను కాపీ చేయి"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"తాజాగా ప్రారంభించు"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"మీ స్థలాన్ని నిర్వహించండి"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"వాల్‌., విడ్జె., సెట్టి. నిర్వ. నేపథ్యం తాకి &amp; నొక్కి పెట్టండి."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"వాల్‌పేపర్‌లు, విడ్జెట్‌లు &amp; సెట్టింగ్‌లు"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"అనుకూలీకరించడానికి నేపథ్యాన్ని నొక్కి &amp; ఉంచండి"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"అర్థమైంది"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"ఇక్కడ ఫోల్డర్ ఉంది"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"ఇలాంటిది సృష్టించడానికి అనువర్తనాన్ని తాకి &amp; నొక్కి పెట్టండి, ఆపై మరోదాని పైన ఉంచండి."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"సరే"</string>
     <string name="folder_opened" msgid="94695026776264709">"ఫోల్డర్ తెరవబడింది, <xliff:g id="WIDTH">%1$d</xliff:g> X <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"ఫోల్డర్‌ను మూసివేయడానికి తాకండి"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"పేరు మార్పును సేవ్ చేయడానికి తాకండి"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"విడ్జెట్‌లు"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"వాల్‌పేపర్‌లు"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"సెట్టింగ్‌లు"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"వేచి ఉంది"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"డౌన్‌లోడ్ చేస్తోంది"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"ఇన్‌స్టాల్ చేస్తోంది"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"భ్రమణాన్ని అనుమతించండి"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"తెలియదు"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"పునరుద్ధరించబడలేదు"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"అన్నీ తీసివేయి"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"తీసివేయి"</string>
     <string name="abandoned_search" msgid="891119232568284442">"శోధించు"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ఈ అనువర్తనం ఇన్‌స్టాల్ చేయబడలేదు"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ఈ చిహ్నం యొక్క అనువర్తనం ఇన్‌స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ అనువర్తనం కోసం శోధించి దాన్ని మాన్యువల్‌గా ఇన్‌స్టాల్ చేయవచ్చు."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"హోమ్ స్క్రీన్‌కు జోడించు"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"అంశాన్ని ఇక్కడికి తరలించు"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"అంశం హోమ్‌స్క్రీన్‌కి జోడించబడింది"</string>
+    <string name="item_removed" msgid="851119963877842327">"అంశం తీసివేయబడింది"</string>
+    <string name="action_move" msgid="4339390619886385032">"అంశాన్ని తరలించు"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"అడ్డు వరుస <xliff:g id="NUMBER_0">%1$s</xliff:g> నిలువు వరుస <xliff:g id="NUMBER_1">%2$s</xliff:g>కి తరలించు"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ఇష్టమైనవిలో <xliff:g id="NUMBER">%1$s</xliff:g>వ స్థానానికి తరలించు"</string>
+    <string name="item_moved" msgid="4606538322571412879">"అంశం తరలించబడింది"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"ఈ ఫోల్డర్‌కి జోడించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> గల ఫోల్డర్‌కు జోడించు"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"అంశం ఫోల్డర్‌కు జోడించబడింది"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"ఈ పేరుతో ఫోల్డర్‌ను సృష్టించండి: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"ఫోల్డర్ సృష్టించబడింది"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"హోమ్‌స్క్రీన్‌కు తరలించు"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"స్క్రీన్‌ను ఎడమవైపుకి జరుపు"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"స్క్రీన్‌ను కుడివైపుకి జరుపు"</string>
+    <string name="screen_moved" msgid="266230079505650577">"స్క్రీన్ జరపబడింది"</string>
+    <string name="action_resize" msgid="1802976324781771067">"పరిమాణం మార్చు"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"వెడల్పును పెంచు"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"ఎత్తును పెంచు"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"వెడల్పును తగ్గించు"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ఎత్తును తగ్గించు"</string>
+    <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ పరిమాణం వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string>
 </resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0fc20d2..85919af 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"หน้าแรก"</string>
-    <string name="uid_name" msgid="7820867637514617527">"แอปหลักของ Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"งาน"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ไม่ได้ติดตั้งแอป"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"แอปไม่พร้อมใช้งาน"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"แอปที่ดาวน์โหลดถูกปิดในโหมดปลอดภัย"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"มีการปิดใช้งานวิดเจ็ตในเซฟโหมด"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"วิดเจ็ต"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"วิดเจ็ต"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"แสดง Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"แตะค้างเพื่อรับวิดเจ็ต"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"ไม่สามารถวางรายการลงในหน้าจอหลักนี้"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"เลือกวิดเจ็ตที่จะสร้าง"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"ชื่อโฟลเดอร์"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"เปลี่ยนชื่อโฟลเดอร์"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ตกลง"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"ยกเลิก"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"เพิ่มลงในหน้าแรก"</string>
-    <string name="group_applications" msgid="3797214114206693605">"แอป"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"ทางลัด"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"วิดเจ็ต"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"ไม่มีที่ว่างในหน้าจอหลักของคุณ"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ค้นหาแอป"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"กำลังโหลดแอป…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"ไม่พบแอปที่ตรงกับ \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"ไม่มีที่ว่างในหน้าจอหลักนี้"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"ไม่มีพื้นที่เหลือในถาดรายการโปรด"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"วิดเจ็ตนี้มีขนาดใหญ่เกินไปสำหรับถาดรายการโปรด"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"สร้างทางลัด \"<xliff:g id="NAME">%s</xliff:g>\" แล้ว"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"นำทางลัด \"<xliff:g id="NAME">%s</xliff:g>\" ออกแล้ว"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"มีทางลัด \"<xliff:g id="NAME">%s</xliff:g>\" อยู่แล้ว"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"เลือกทางลัด"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"เลือกแอป"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"แอป"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"หน้าแรก"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ลบ"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"ถอนการติดตั้ง"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ลบ"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"ถอนการติดตั้ง"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ข้อมูลแอป"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"แอป"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ลบ"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"ถอนการติดตั้งการอัปเดต"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ถอนการติดตั้งแอป"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"รายละเอียดแอป"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"เลือกไว้ 1 แอป"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"เลือกไว้ 1 วิดเจ็ต"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"เลือกไว้ 1 โฟลเดอร์"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"เลือกไว้ 1 ทางลัด"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"ติดตั้งทางลัด"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"อนุญาตให้แอปเพิ่มทางลัดโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"ถอนการติดตั้งทางลัด"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"อนุญาตให้แอปนำทางลัดออกโดยไม่ต้องให้ผู้ใช้จัดการ"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"อ่านการตั้งค่าและทางลัดหน้าแรกแล้ว"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"อนุญาตให้แอปอ่านการตั้งค่าและทางลัดในหน้าแรก"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"เขียนการตั้งค่าและทางลัดหน้าแรกแล้ว"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"มีปัญหาขณะโหลดวิดเจ็ต"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ตั้งค่า"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"นี่เป็นแอประบบและไม่สามารถถอนการติดตั้งได้"</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"โฟลเดอร์ที่ไม่มีชื่อ"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"หน้าจอหลัก %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"แอปหน้า %1$d จาก %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"วิดเจ็ตหน้า %1$d จาก %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"ยินดีต้อนรับ"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ทำตัวตามสบาย"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"สร้างหน้าจอเพิ่มสำหรับแอปและโฟลเดอร์"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"คัดลอกไอคอนแอปของคุณ"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"นำเข้าไอคอนและโฟลเดอร์จากหน้าจอหลักเก่าของคุณ"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"คัดลอกไอคอน"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"เริ่มต้นใหม่"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"จัดระเบียบพื้นที่ของคุณ"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"แตะพื้นหลังค้างไว้เพื่อจัดการวอลเปเปอร์ วิดเจ็ต และการตั้งค่า"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"วอลเปเปอร์ วิดเจ็ต และการตั้งค่า"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"แตะพื้นหลังค้างไว้เพื่อกำหนดค่า"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"รับทราบ"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"นี่คือโฟลเดอร์"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"หากต้องการสร้างโฟลเดอร์ลักษณะนี้ แตะแอปค้างไว้ แล้วย้ายไปทับอีกแอปหนึ่ง"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ตกลง"</string>
     <string name="folder_opened" msgid="94695026776264709">"เปิดโฟลเดอร์ <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"แตะเพื่อปิดโฟลเดอร์"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"แตะเพื่อบันทึกการเปลี่ยนชื่อ"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"วิดเจ็ต"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"วอลเปเปอร์"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"การตั้งค่า"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"กำลังรอ"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"กำลังดาวน์โหลด"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"กำลังติดตั้ง"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"อนุญาตให้ใช้การหมุน"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"ไม่รู้จัก"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"ไม่ได้คืนค่า"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"ลบทั้งหมด"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ลบ"</string>
     <string name="abandoned_search" msgid="891119232568284442">"ค้นหา"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"ไม่ได้ติดตั้งแอปนี้"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"ยังไม่ได้ติดตั้งแอปสำหรับไอคอนนี้ คุณสามารถนำไอคอนออก หรือค้นหาแอปดังกล่าวแล้วติดตั้งด้วยตนเอง"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"เพิ่มลงในหน้าแรก"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"ย้ายรายการมาที่นี่"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"เพิ่มรายการไปยังหน้าจอหลักแล้ว"</string>
+    <string name="item_removed" msgid="851119963877842327">"นำออกรายการออกแล้ว"</string>
+    <string name="action_move" msgid="4339390619886385032">"ย้ายรายการ"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"ย้ายไปที่แถว <xliff:g id="NUMBER_0">%1$s</xliff:g> คอลัมน์ <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"ย้ายไปยังตำแหน่ง <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"ย้ายไปยังตำแหน่งที่ <xliff:g id="NUMBER">%1$s</xliff:g> ของรายการโปรด"</string>
+    <string name="item_moved" msgid="4606538322571412879">"ย้ายรายการแล้ว"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"เพิ่มไปยังโฟลเดอร์: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"เพิ่มไปยังโฟลเดอร์ที่มี <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"เพิ่มรายการไปยังโฟลเดอร์แล้ว"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"สร้างโฟลเดอร์ด้วย: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"สร้างโฟลเดอร์แล้ว"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ย้ายไปที่หน้าจอหลัก"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"เลื่อนหน้าจอไปทางซ้าย"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"เลื่อนหน้าจอไปทางขวา"</string>
+    <string name="screen_moved" msgid="266230079505650577">"ย้ายหน้าจอแล้ว"</string>
+    <string name="action_resize" msgid="1802976324781771067">"ปรับขนาด"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"เพิ่มความกว้าง"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"เพิ่มความสูง"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"ลดความกว้าง"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"ลดความสูง"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ปรับขนาดของวิดเจ็ตเป็นกว้าง <xliff:g id="NUMBER_0">%1$s</xliff:g> สูง <xliff:g id="NUMBER_1">%2$s</xliff:g> แล้ว"</string>
 </resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 4d2f1d4..69a5bb7 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Home"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Core Apps"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Trabaho"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Hindi naka-install ang app."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Hindi available ang app"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Naka-disable ang na-download na app sa Safe mode"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Naka-disable ang mga widget sa Safe mode"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Mga Widget"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Mga Widget"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Ipakita ang Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Pindutin nang matagal upang kumuha ng widget."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Hindi ma-drop ang item sa Home screen na ito."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Pumili ng widget na gagawin"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Pangalan ng folder"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Palitan ang pangalan ng folder"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Kanselahin"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Idagdag sa Home screen"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Apps"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Mga Shortcut"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Mga Widget"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Wala nang lugar sa iyong mga Home screen."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Mga App sa Paghahanap"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Nilo-load ang Mga App…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Walang nakitang Mga App na tumutugma sa \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Wala nang lugar sa Home screen na ito."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Wala nang lugar sa tray ng Mga Paborito"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Masyadong malaki ang widget na ito para sa tray ng Mga Paborito"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Nagawa ang shortcut na \"<xliff:g id="NAME">%s</xliff:g>.\""</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Inalis ang shortcut na \"<xliff:g id="NAME">%s</xliff:g>.\""</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Umiiral na ang shortcut na \"<xliff:g id="NAME">%s</xliff:g>.\""</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Pumili ng shortcut"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Pumili ng app"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Apps"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Home"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Alisin"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"I-uninstall"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Alisin"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"I-uninstall"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Impormasyon ng app"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Apps"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Alisin"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"I-uninstall ang update"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"I-uninstall ang app"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Mga detalye ng app"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 app ang napili"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget ang napili"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 folder ang napili"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 shortcut ang napili"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"i-install ang mga shortcut"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Pinapayagan ang isang app na magdagdag ng mga shortcut nang walang panghihimasok ng user."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"i-uninstall ang mga shortcut"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Pinapayagan ang app na mag-alis ng mga shortcut nang walang panghihimasok ng user."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"basahin ang mga setting at shortcut ng Home"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Pinapayagan ang app na basahin ang mga setting at shortcut sa Home."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"magsulat ng mga setting at shortcut ng Home"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Problema sa pag-load ng widget"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"I-setup"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Isa itong app ng system at hindi maaaring i-uninstall."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Walang Pangalang Folder"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Home screen %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Pahina ng apps %1$d ng %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Pahina ng widget %1$d ng %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Maligayang Pagdating"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Gawing kumportable ang iyong sarili."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Gumawa ng higit pang mga screen para sa apps at mga folder"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopyahin ang mga icon ng app"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"I-import ang icon at folder mula sa luma mong Home screen?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPYAHIN ANG MGA ICON"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"MAGSIMULA NANG BAGO"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Ayusin ang iyong espasyo"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Pindutin nang matagal ang background upang pamahalaan ang wallpaper, mga widget at setting"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Mga wallpaper, widget at setting"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Pindutin nang matagal ang background upang i-customize"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NAKUHA KO"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Narito ang isang folder"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Upang gumawa ng katulad nito, pindutin nang matagal ang isang app, pagkatapos ay ilipat ito sa isa pang folder."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Binuksan ang folder, <xliff:g id="WIDTH">%1$d</xliff:g> by <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Pindutin upang isara ang folder"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Pindutin upang i-save ang pagpapalit ng pangalan"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Mga Widget"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Mga Wallpaper"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Mga Setting"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Naghihintay"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Nagda-download"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Nag-i-install"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Payagan ang pag-rotate"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Hindi kilala"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Hindi naibalik"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Alisin Lahat"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Alisin"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Maghanap"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Hindi naka-install ang app na ito"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Hindi naka-install ang app para sa icon na ito. Maaari mo itong alisin, o maaari mong hanapin ang app at i-install ito nang manu-mano."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Idagdag sa Home screen"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Ilipat ang item dito"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Naidagdag sa home screen ang item"</string>
+    <string name="item_removed" msgid="851119963877842327">"Naalis na ang item"</string>
+    <string name="action_move" msgid="4339390619886385032">"Ilipat ang item"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Ilipat sa row <xliff:g id="NUMBER_0">%1$s</xliff:g> column <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Ilipat sa posisyon <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Ilipat sa posisyon <xliff:g id="NUMBER">%1$s</xliff:g> sa mga paborito"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Nalipat ang item"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Idagdag sa folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Idagdag sa folder kasama ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Idinagdag ang item sa folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Gumawa ng folder na may: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Nagawa ang folder"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Ilipat sa Home screen"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Ilipat sa kaliwa ang screen"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Ilipat sa kanan ang screen"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Nailipat ang screen"</string>
+    <string name="action_resize" msgid="1802976324781771067">"I-resize"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Dagdagan ang lapad"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Dagdagan ang taas"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Bawasan ang lapad"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Bawasan ang taas"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Na-resize ang widget sa lapad <xliff:g id="NUMBER_0">%1$s</xliff:g> taas <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 6c78f6f..d933c87 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Ana ekran"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android Çekirdek Uygulamaları"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"İş"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Uygulama yüklü değil."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Uygulama kullanılamıyor"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"İndirilen uygulama Güvenli modda devre dışı bırakıldı"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Güvenli modda widget\'lar devre dışı"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Widget\'lar"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Widget\'lar"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Belleği Göster"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Widget seçmek için dokunun ve basılı tutun."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Öğe bu Ana ekrana bırakılamadı."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Oluşturmak için widget seçin"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Klasör adı"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Klasörü yeniden adlandırın"</string>
-    <string name="rename_action" msgid="5559600076028658757">"Tamam"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"İptal"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Ana ekrana ekleyin"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Uygulamalar"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Kısayollar"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Widget\'lar"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Ana ekranlarınızda yer kalmadı."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Uygulamalarda Ara"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Uygulamalar Yükleniyor…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ile eşleşen uygulama bulunamadı"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Bu Ana ekranda yer kalmadı."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Favoriler tepsisinde başka yer kalmadı"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Bu widget, Favoriler tepsisi için çok geniş"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" kısayolu oluşturuldu."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" kısayolu kaldırıldı."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" kısayolu zaten var."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Kısayolu seçin"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Uygulama seçin"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Uygulamalar"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ana ekran"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Kaldır"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Yüklemeyi kaldır"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Kaldır"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Yüklemeyi kaldır"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Uygulama bilgileri"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Uygulamalar"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Kaldır"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Güncellemeyi kaldır"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Uygulamanın yüklemesini kaldır"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Uygulama ayrıntıları"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 uygulama seçildi"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 widget seçildi"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 klasör seçildi"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 kısayol seçildi"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"kısayolları yükle"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Uygulamaya, kullanıcı müdahalesi olmadan kısayol ekleme izni verir."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"kısayolların yüklemesini kaldır"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Uygulamaya, kullanıcı müdahalesi olmadan kısayolları kaldırma izni verir."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Ana ekran ayarlarını ve kısayollarını oku"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Uygulamaya, Ana ekrandaki ayarları ve kısayolları okuma izni verir."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Ana ekran ayarlarını ve kısayollarını yaz"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Widget yüklenirken sorun oluştu"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Kurulum"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu bir sistem uygulamasıdır ve yüklemesi kaldırılamaz."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Roket Fırlatıcı"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Adsız Klasör"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Ana ekran %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Uygulama sayfası %1$d / %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Widget sayfası %1$d / %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Hoş geldiniz"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Rahatınıza bakın."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Uygulamalar ve klasörler için daha fazla ekran oluşturun"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Uygulama simgelerini kopyala"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Eski Ana ekranlarınızdaki simgeler ve klasörler içe aktarılsın mı?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"SİMGELERİ KOPYALA"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"VARSAYILANI KULLAN"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Alanınızı düzenleyin"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Duvar kağıdını, widget\'ları ve ayarları yönetmek için arka plana uzun basın."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Duvar kağıtları, widget\'lar ve ayarlar"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Özelleştirmek için arka plana dokunun ve basılı tutun"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"TAMAM"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"İşte bir klasör"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Buna benzer bir klasör oluşturmak için uygulamaya uzun basın ve sonra uygulamayı başka bir uygulamanın üzerine taşıyın."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"Tamam"</string>
     <string name="folder_opened" msgid="94695026776264709">"Klasör açıldı, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Klasörü kapatmak için dokunun"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Yeni adı kaydetmek için dokunun"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Widget\'lar"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Duvar Kağıtları"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Ayarlar"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Bekliyor"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"İndiriliyor"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Yükleniyor"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Döndürmeye izin ver"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Bilinmiyor"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Geri yüklenmedi"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Tümünü Kaldır"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Kaldır"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Ara"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Bu uygulama yüklü değil"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Bu simgenin uygulaması yüklü değil. Uygulamayı kaldırabilir veya arayıp manuel olarak yükleyebilirsiniz."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Ana ekrana ekle"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Öğeyi buraya taşı"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Öğe ana ekrana eklendi"</string>
+    <string name="item_removed" msgid="851119963877842327">"Öğe kaldırıldı"</string>
+    <string name="action_move" msgid="4339390619886385032">"Öğeyi taşı"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g>. satır <xliff:g id="NUMBER_1">%2$s</xliff:g>. sütuna taşı"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>. sıraya taşı"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Favorilerde <xliff:g id="NUMBER">%1$s</xliff:g>. sıraya taşı"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Öğe taşındı"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Klasöre ekle: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> öğesini içeren klasöre ekle"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Öğe, klasöre eklendi"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Şu öğeyle klasör oluştur: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Klasör oluşturuldu"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Ana ekrana taşı"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranı sola taşı"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranı sağa taşı"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekran taşındı"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Yeniden boyutlandır"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Genişliği artır"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Yüksekliği artır"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Genişliği azalt"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Yüksekliği azalt"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Widget, <xliff:g id="NUMBER_0">%1$s</xliff:g> genişlik ve <xliff:g id="NUMBER_1">%2$s</xliff:g> yükseklik değerine yeniden boyutlandırıldı"</string>
 </resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 129b438..b06177e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Головний екран"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Базові програми Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Робоча папка"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Додаток видалено."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Додаток недоступний"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Завантажений додаток вимкнено в безпечному режимі"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"У безпечному режимі віджети вимкнено"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Віджети"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Віджети"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Показати пам’ять"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Натисніть і утримуйте, щоб вибрати віджет."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Не вдалося додати елемент на цей головний екран."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Вибрати віджет для створення"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Назва папки"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Перейменувати папку"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OК"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Скасувати"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Додати на головний екран"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Додатки"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Ярлики"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Віджети"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"На головних екранах більше немає місця."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Пошук додатків"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Завантаження додатків…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Немає додатків для запиту \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"На цьому головному екрані більше немає місця."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"В області \"Вибране\" немає місця"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Цей віджет завеликий для області \"Вибране\""</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Ярлик \"<xliff:g id="NAME">%s</xliff:g>\" створено."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Ярлик \"<xliff:g id="NAME">%s</xliff:g>\" вилучено."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Ярлик \"<xliff:g id="NAME">%s</xliff:g>\" уже існує."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Вибрати ярлик"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Виберіть додаток"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Додатки"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Головний екран"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Вилучити"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Видалити"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Вилучити"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Видалити"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Про програму"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Додатки"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Вилучити"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Видалити оновлення"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Видалити програму"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Відомості про програму"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Вибрано 1 програму"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Вибрано 1 віджет"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Вибрано 1 папку"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Вибрано 1 ярлик"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"створення ярликів"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозволяє програмі самостійно додавати ярлики."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"видаляти ярлики"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Дозволяє програмі самостійно вилучати ярлики."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"читати налаштування та ярлики головного екрана"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Дозволяє програмі читати налаштування та ярлики на головному екрані."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"записувати налаштування та ярлики головного екрана"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Проблема із завантаженням віджета"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Налаштування"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Це системна програма, її неможливо видалити."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Папка без назви"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Головний екран %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Сторінка програм %1$d з %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Сторінка віджетів %1$d з %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Вітаємо"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Будьте як удома."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Створюйте нові екрани для програм і папок"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Копіювати значки програм"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Імпортувати значки та папки зі старих головних екранів?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"КОПІЮВАТИ ЗНАЧКИ"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"ПАНЕЛЬ ЗАПУСКУ ЗА УМОВЧАННЯМ"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Організуйте робочий простір"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Натисніть і утримуйте фон, щоб керувати фоновим малюнком, віджетами та налаштуваннями."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Фонові малюнки, віджети й налаштування"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Натисніть і втримуйте фон, щоб налаштувати робочу область"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"ЗРОЗУМІЛО"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Це папка"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Щоб створити папку, натисніть і утримуйте програму, а потім перетягніть її на іншу."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OК"</string>
     <string name="folder_opened" msgid="94695026776264709">"Папку відкрито (<xliff:g id="WIDTH">%1$d</xliff:g> х <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Торкніться, щоб закрити папку"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Торкніться, щоб зберегти нову назву"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Віджети"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Фонові малюнки"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Налаштування"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Очікування"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Завантаження"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Встановлення"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Дозволити обертання"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Невідомо"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Не відновлено"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Видалити всі"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Видалити"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Шукати"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Цей додаток не встановлено"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Додаток для цього значка не встановлено. Можна видалити значок або знайти додаток і встановити його вручну."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Додати на головний екран"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Перемістити елемент сюди"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Елемент додано на головний екран"</string>
+    <string name="item_removed" msgid="851119963877842327">"Елемент вилучено"</string>
+    <string name="action_move" msgid="4339390619886385032">"Перемістити елемент"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Перемістити в рядок <xliff:g id="NUMBER_0">%1$s</xliff:g>, стовпець <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Перемістити на <xliff:g id="NUMBER">%1$s</xliff:g> місце"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Перемістити у вибране на <xliff:g id="NUMBER">%1$s</xliff:g> місце"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Елемент переміщено"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Додати в папку \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додати в папку з додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Елемент додано в папку"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Створити папку з: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Папку створено"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Перемістити на головний екран"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Перемістити екран ліворуч"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Перемістити екран праворуч"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Екран переміщено"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Змінити розміри"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Збільшити ширину"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Збільшити висоту"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Зменшити ширину"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Зменшити висоту"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Розміри віджета змінено на <xliff:g id="NUMBER_0">%1$s</xliff:g> завширшки та <xliff:g id="NUMBER_1">%2$s</xliff:g> заввишки"</string>
 </resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index ba1d3fa..ba189c8 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"ہوم"</string>
-    <string name="uid_name" msgid="7820867637514617527">"‏Android کور ایپس"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"دفتری"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"ایپ انسٹال نہیں ہے۔"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"ایپ دستیاب نہیں ہے"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"ڈاؤن لوڈ کردہ ایپ کو محفوظ وضع میں غیر فعال کر دیا گیا"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"ویجیٹس کو محفوظ وضع میں غیر فعال کر دیا گیا"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"ویجیٹس"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"ویجیٹس"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"‏Mem دکھائیں"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"کوئی ویجیٹ منتخب کرنے کیلئے ٹچ کریں اور پکڑے رہیں۔"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"آئٹم کو اس ہوم اسکرین پر ڈراپ نہیں کیا جا سکا۔"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"بنانے کیلئے ویجیٹ منتخب کریں"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"فولڈر کا نام"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"فولڈر کا نام تبدیل کریں"</string>
-    <string name="rename_action" msgid="5559600076028658757">"ٹھیک ہے"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"منسوخ کریں"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"ہوم اسکرین میں شامل کریں"</string>
-    <string name="group_applications" msgid="3797214114206693605">"ایپس"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"شارٹ کٹس"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"ویجیٹس"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"آپ کی ہوم اسکرینوں پر مزید کوئی گنجائش نہیں ہے۔"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"ایپس تلاش کریں"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"ایپس لوڈ ہو رہی ہیں…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" سے مماثل کوئی ایپس نہیں ملیں"</string>
     <string name="out_of_space" msgid="4691004494942118364">"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"یہ ویجیٹ پسندیدہ ٹرے کیلئے کافی بڑا ہے"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" بنایا گیا۔"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" ہٹا دیا گیا۔"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"شارٹ کٹ \"<xliff:g id="NAME">%s</xliff:g>\" پہلے سے موجود ہے۔"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"شارٹ کٹ منتخب کریں"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"ایپ منتخب کریں"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"ایپس"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"ہوم"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"ہٹائیں"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"اَن انسٹال کریں"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"ہٹائیں"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"اَن انسٹال کریں"</string>
     <string name="info_target_label" msgid="8053346143994679532">"ایپ کی معلومات"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"ایپس"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"ہٹائیں"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"اپ ڈیٹ اَن انسٹال کریں"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"ایپ کو اَن انسٹال کریں"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"ایپ کی تفصیلات"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ایپ منتخب کی گئی"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ویجیٹ منتخب کیا گیا"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 فولڈر منتخب کیا گیا"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 شارٹ کٹ منتخب کیا گیا"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"شارٹ کٹس انسٹال کریں"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"کسی ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس شامل کرنے کی اجازت دیتا ہے۔"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"شارٹ کٹس کو اَن انسٹال کریں"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"ایپ کو صارف کی مداخلت کے بغیر شارٹ کٹس ہٹانے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"ہوم ترتیبات اور شارٹ کٹس کو پڑھیں"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"ایپ کو ہوم میں ترتیبات اور شارٹ کٹس کو پڑھنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ہوم ترتیبات اور شارٹ کٹس کو لکھیں"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"ویجیٹ کو لوڈ کرنے میں مسئلہ"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"ترتیب دیں"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"یہ ایک سسٹم ایپ ہے اور اسے اَن انسٹال نہیں کیا جا سکتا ہے۔"</string>
-    <string name="dream_name" msgid="1530253749244328964">"راکٹ لانچر"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"بلا نام فولڈر"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"‏ہوم اسکرین ‎%1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"‏ایپس کا صفحہ ‎%1$d از ‎%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"‏ویجیٹس کا صفحہ ‎%1$d از ‎%2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"خوش آمدید"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"ہوم سکرین مرضی کے مطابق بنائیں۔"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"ایپس اور فولڈرز کیلئے مزید اسکرینیں بنائیں"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"اپنے ایپ آئیکنز کو کاپی کریں"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"اپنی پرانی ہوم اسکرینوں سے آئیکنز اور فولڈرز درآمد کریں؟"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"آئیکنز کاپی کریں"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"نئے سرے سے شروع کریں"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"اپنی جگہ کو منظم کریں"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"وال پیپر، ویجیٹس اور ترتیبات کا نظم کرنے کیلئے پس منظر کو ٹچ کریں اور پکڑ کر رکھیں۔"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"وال پیپرز، ویجیٹس اور ترتیبات"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"حسب ضرورت بنانے کیلئے پس منظر کو ٹچ کریں اور دبائے رکھیں"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"سمجھ آ گئی"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"یہ ہے ایک فولڈر"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"اس طرح کا ایک بنانے کیلئے، کسی ایپ کو ٹچ کریں اور پکڑ کر رکھیں، پھر اسے کسی دوسرے میں منتقل کریں۔"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"ٹھیک ہے"</string>
     <string name="folder_opened" msgid="94695026776264709">"فولڈر کھولا گیا، <xliff:g id="WIDTH">%1$d</xliff:g> × <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"فولڈر بند کرنے کیلئے ٹچ کریں"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"نام کی تبدیلی محفوظ کرنے کیلئے ٹچ کریں"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"ویجیٹس"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"وال پیپرز"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"ترتیبات"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"منتظر"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"ڈاؤن لوڈ کیا جا رہا ہے"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"انسٹال کیا جا رہا ہے"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"گردش کی اجازت دیں"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"نامعلوم"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"بحال نہیں ہوا"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"سبھی کو ہٹا دیں"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"ہٹائیں"</string>
     <string name="abandoned_search" msgid="891119232568284442">"تلاش کریں"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"یہ ایپ انسٹال کردہ نہیں ہے"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"اس آئیکن کیلئے ایپ انسٹال کردہ نہیں ہے۔ آپ اسے ہٹا سکتے ہیں یا ایپ کو تلاش کر سکتے اور دستی طور پر اسے انسٹال کر سکتے ہیں۔"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"ہوم اسکرین میں شامل کریں"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"آئٹم یہاں منتقل کریں"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"آئٹم کو ہوم اسکرین میں شامل کر دیا گیا"</string>
+    <string name="item_removed" msgid="851119963877842327">"آئٹم ہٹا دیا گیا"</string>
+    <string name="action_move" msgid="4339390619886385032">"آئٹم منتقل کریں"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"قطار <xliff:g id="NUMBER_0">%1$s</xliff:g> کالم <xliff:g id="NUMBER_1">%2$s</xliff:g> میں منتقل کریں"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"پوزیشن <xliff:g id="NUMBER">%1$s</xliff:g> میں منتقل کریں"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"پسندیدہ پوزیشن <xliff:g id="NUMBER">%1$s</xliff:g> میں منتقل کریں"</string>
+    <string name="item_moved" msgid="4606538322571412879">"آئٹم منتقل کر دیا گیا"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"فولڈر میں شامل کریں: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> کے فولڈر میں شامل کریں"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"آئٹم فولڈر میں شامل کر دیا گیا"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"اس کے ساتھ فولڈر بنائیں: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"فولڈر بنا دیا گیا"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"ہوم اسکرین میں منتقل کریں"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"اسکرین کو بائیں منتقل کریں"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"اسکرین کو دائیں منتقل کریں"</string>
+    <string name="screen_moved" msgid="266230079505650577">"اسکرین منتقل کر دی گئی"</string>
+    <string name="action_resize" msgid="1802976324781771067">"سائز تبدیل کریں"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"چوڑائی بڑھائیں"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"اونچائی بڑھائیں"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"چوڑائی کم کریں"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"اونچائی کم کریں"</string>
+    <string name="widget_resized" msgid="9130327887929620">"ویجیٹ کے سائز کو چوڑائی <xliff:g id="NUMBER_0">%1$s</xliff:g> اونچائی <xliff:g id="NUMBER_1">%2$s</xliff:g> میں تبدیل کر دیا گیا"</string>
 </resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index 60d3ac0..c3bffeb 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Ishga tushirgich3"</string>
-    <string name="home" msgid="7658288663002113681">"Uy"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Androidga asoslangan dasturlar"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Ishga oid"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Ilova o‘rnatilmadi."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Ilova mavjud emas"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Yuklab olingan ilova xavfsiz rejimda o‘chirib qo‘yildi"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Xavfsiz rejimda vidjetlar o‘chirib qo‘yilgan"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Vidjetlar"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Vidjetlar"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Xotirani ko‘rsatish"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Vidjetni tanlash uchun bosib turing."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Elementni ushbu \"Uy\" ekraniga tashlab bo‘lmadi."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Yaratish uchun vidjet tanlang"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Jild nomi"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Jild nomini o‘zgartirish"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Bekor qilish"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Uy ekraniga qo‘shish"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Ilovalar"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Yorliqlar"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Vidjetlar"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Uy ekraningizda birorta ham xona yo‘q."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Ilovalarni qidirish"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilovalar yuklanmoqda…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"“<xliff:g id="QUERY">%1$s</xliff:g>” bilan mos hech qanday ilova topilmadi"</string>
     <string name="out_of_space" msgid="4691004494942118364">"Uy ekranida bitta ham xona yo‘q."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ajratilganlarda birorta ham xona yo‘q"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Ajratilganlar uchun ushbu vidjet juda katta"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i yaratildi."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i o‘chirildi."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"\"<xliff:g id="NAME">%s</xliff:g>\" yorlig‘i allaqachon mavjud."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Yorliqni tanlash"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Ilovani tanlash"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ilovalar"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Uy"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"O‘chirish"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"O‘chirish"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"O‘chirish"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"O‘chirish"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Ilova haqida"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Ilovalar"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"O‘chirish"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Yangilashni o‘chirish"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Ilovani o‘chirish"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Ilova ma’lumotlari"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 ta ilova tanlandi"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 ta vidjet tanlandi"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ta jild tanlandi"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 ta yorliq tanlandi"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"yorliqlar yaratish"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ilovalarga foydalanuvchidan so‘ramasdan yorliqlar qo‘shishga ruxsat beradi."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"yorliqlarni o‘chirish"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ilovaga foydalanuvchiga bildirmasdan yorliqlarni o‘chirish uchun ruxsat beradi."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"Uy sozlamalari va yorliqlarini o‘qish"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Ilovaga \"Uy\" ekranidagi yorliqlar va sozlamalarni o‘qish uchun ruxsat beradi."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"Uy sozlamalari va yorliqlarini yozish"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Vidjetni yuklashda muammo"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Sozlash"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Bu tizim ilovasi, shuning uchun o‘chirib bo‘lmaydi."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Nomsiz jild"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Uy ekrani %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Ilovalar sahifasi %2$ddan %1$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Vidjetlar sahifasi %2$ddan %1$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Xush kelibsiz"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"O‘zingizni uyingizdagidek his qiling."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Ilovalar va jildlar uchun ko‘proq ekranlar yaratish"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Ilovangiz nishonchalaridan nusxa olish"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Eski \"Uy\" ekranlaringizdan jildlar va nishonchalar import qilinsinmi?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"NISHONCHALARNI NUSXALASH"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"YANGIDAN BOSHLASH"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Joylaringizni boshqaring"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Fon rasmi, vidjet va sozlamalarni boshqarish uchun orqa fonga bosib turing"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Orqa fon rasmlari, vidjet va sozlamalar"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Orqa fonni moslashtirish uchun uni bosing va ushlab turing"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Mana sizga jild"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Bunga o‘xshaganini yaratish uchun bosib turing, keyin boshqasiga o‘ting."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Jild ochildi, <xliff:g id="WIDTH">%1$d</xliff:g> ga <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Jildni yopish uchun bosing"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"O‘zgartirilgan nomni saqlash uchun bosing"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Vidjetlar"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fon rasmlari"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Sozlamalar"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Kutilmoqda"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Yuklab olinmoqda"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"O‘rnatilmoqda"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Aylanishga ruxsat berish"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Noma’lum"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Qayta tiklanmadi"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Barchasini o‘chirish"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"O‘chirish"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Qidirish"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ushbu ilova o‘rnatilmagan"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ilova o‘rnatilmagan. Belgini o‘chirib tashlashingiz yoki ilovani topib, uni qo‘lda o‘rnatishingiz mumkin."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Bosh ekranga qo‘shish"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Obyektni bu yerga ko‘chirish"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Obyekt bosh ekranga qo‘shildi"</string>
+    <string name="item_removed" msgid="851119963877842327">"Obyekt o‘chirib tashlandi"</string>
+    <string name="action_move" msgid="4339390619886385032">"Obyektni ko‘chirib o‘tkazish"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"<xliff:g id="NUMBER_0">%1$s</xliff:g> <xliff:g id="NUMBER_1">%2$s</xliff:g> katakka ko‘chirib o‘tkazish"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g>-joyga ko‘chirib o‘tkazish"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Sevimlilarga (<xliff:g id="NUMBER">%1$s</xliff:g>) ko‘chirib o‘tkazish"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Element ko‘chirib o‘tkazildi"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"<xliff:g id="NAME">%1$s</xliff:g> jildiga qo‘shish"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi bor jildga qo‘shish"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Element jildga qo‘shildi"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"<xliff:g id="NAME">%1$s</xliff:g> bilan jild yaratish"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Jild yaratildi"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Bosh ekranga ko‘chirish"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Ekranni chapga siljitish"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Ekranni o‘ngga siljitish"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Ekran siljitildi"</string>
+    <string name="action_resize" msgid="1802976324781771067">"O‘lchamini o‘zgartirish"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Enini uzaytirish"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Bo‘yini uzaytirish"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Enini kichraytirish"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Bo‘yini kichraytirish"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Vidjetning eni <xliff:g id="NUMBER_0">%1$s</xliff:g>, bo‘yi <xliff:g id="NUMBER_1">%2$s</xliff:g> qilib o‘zgartirildi"</string>
 </resources>
diff --git a/res/values-v17/styles.xml b/res/values-v17/styles.xml
deleted file mode 100644
index 11d2a1f..0000000
--- a/res/values-v17/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="PagedViewWidgetImageView">
-        <item name="android:paddingStart">@dimen/app_widget_preview_padding_left</item>
-    </style>
-</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 5bc1627..f57f491 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"Màn hình chính"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Ứng dụng lõi Android"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Ứng dụng chưa được cài đặt."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Ứng dụng không có sẵn"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Ứng dụng đã tải xuống bị tắt ở chế độ An toàn"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Tiện ích con bị vô hiệu hóa ở chế độ an toàn"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Tiện ích con"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Tiện ích con"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Hiển thị bộ nhớ"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Chạm và giữ để chọn tiện ích con."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Không thể thả mục vào Màn hình chính này."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Chọn tiện ích con để tạo"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Tên thư mục"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Đổi tên thư mục"</string>
-    <string name="rename_action" msgid="5559600076028658757">"OK"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Hủy"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Thêm vào Màn hình chính"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Ứng dụng"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Lối tắt"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Tiện ích con"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Không còn chỗ trên Màn hình chính của bạn."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Tìm kiếm ứng dụng"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Đang tải ứng dụng..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Không tìm thấy ứng dụng nào phù hợp với \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Không còn chỗ trên Màn hình chính này."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Không còn chỗ trong khay Mục yêu thích"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Tiện ích con này có kích thước quá lớn để đặt vào khay Mục yêu thích"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Lối tắt \"<xliff:g id="NAME">%s</xliff:g>\" đã được tạo."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Lối tắt \"<xliff:g id="NAME">%s</xliff:g>\" đã bị xóa."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Lối tắt \"<xliff:g id="NAME">%s</xliff:g>\" đã tồn tại."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Chọn lối tắt"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Chọn ứng dụng"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Ứng dụng"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Màn hình chính"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Xóa"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Gỡ cài đặt"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Xóa"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Gỡ cài đặt"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Thông tin ứng dụng"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Ứng dụng"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Xóa"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Gỡ cài đặt cập nhật"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Gỡ cài đặt ứng dụng"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Thông tin chi tiết về ứng dụng"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"Đã chọn 1 ứng dụng"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"Đã chọn 1 tiện ích con"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"Đã chọn 1 thư mục"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"Đã chọn 1 lối tắt"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"cài đặt lối tắt"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Cho phép ứng dụng thêm lối tắt mà không cần sự can thiệp của người dùng."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"gỡ cài đặt lối tắt"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Cho phép ứng dụng xóa lối tắt mà không cần sự can thiệp của người dùng."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"đọc cài đặt và lối tắt trên Màn hình chính"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Cho phép ứng dụng đọc cài đặt và lối tắt trên Màn hình chính."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"ghi cài đặt và lối tắt trên Màn hình chính"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Sự cố khi tải tiện ích con"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Thiết lập"</string>
     <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="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Thư mục chưa đặt tên"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Màn hình chính %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Trang ứng dụng %1$d / %2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Trang tiện ích con %1$d / %2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Chào mừng"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Tự nhiên như ở nhà."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Tạo thêm màn hình cho ứng dụng và thư mục"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Sao chép biểu tượng ứng dụng của bạn"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Nhập biểu tượng và thư mục từ Màn hình chính cũ của bạn?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"BIỂU TƯỢNG SAO CHÉP"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"BẮT ĐẦU LÀM MỚI"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Sắp xếp không gian của bạn"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Chạm và giữ nền để quản lý hình nền, tiện ích con và cài đặt."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Hình nền, tiện ích và cài đặt"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Chạm và giữ nền để tùy chỉnh"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"OK"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Đây là một thư mục"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Để tạo thư mục như thế này, hãy chạm và giữ một ứng dụng, sau đó di chuyển ứng dụng đó lên trên một ứng dụng khác."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"OK"</string>
     <string name="folder_opened" msgid="94695026776264709">"Đã mở thư mục, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Chạm để đóng thư mục"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Chạm để lưu tên mới"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Tiện ích con"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Hình nền"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Cài đặt"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Đang đợi"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Đang tải xuống"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Đang cài đặt"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Cho phép xoay"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Không xác định"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Không được khôi phục"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Xóa tất cả"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Xóa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Tìm kiếm"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Ứng dụng này chưa được cài đặt"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Ứng dụng cho biểu tượng này chưa được cài đặt. Bạn có thể xóa ứng dụng hoặc tìm kiếm và cài đặt ứng dụng theo cách thủ công."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Thêm vào màn hình chính"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Di chuyển mục vào đây"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Đã thêm mục vào màn hình chính"</string>
+    <string name="item_removed" msgid="851119963877842327">"Đã xóa mục"</string>
+    <string name="action_move" msgid="4339390619886385032">"Di chuyển mục"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Di chuyển đến hàng <xliff:g id="NUMBER_0">%1$s</xliff:g> cột <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Di chuyển tới vị trí <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Di chuyển tới vị trí mục yêu thích <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Đã di chuyển mục"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Thêm vào thư mục: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Thêm vào thư mục có <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Đã thêm mục vào thư mục"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Tạo thư mục bằng: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Đã tạo thư mục"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Di chuyển đến màn hình chính"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Di chuyển màn hình sang trái"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Di chuyển màn hình sang phải"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Đã di chuyển màn hình"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Đổi kích thước"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Tăng chiều rộng"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Tăng chiều cao"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Giảm chiều rộng"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Giảm chiều cao"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Đã đổi kích thước tiện ích thành chiều rộng <xliff:g id="NUMBER_0">%1$s</xliff:g> chiều cao <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index b7c42fe..82274ba 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"主屏"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android 核心应用"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"未安装该应用。"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"应用不可用"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"安全模式下不允许使用下载的此应用"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"安全模式下不允许使用小部件"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"小部件"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"小部件"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"显示内存空间"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"触摸并按住小部件即可选择。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"无法将相关内容拖放到此主屏幕上。"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"选择要创建的小部件"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"文件夹名称"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"重命名文件夹"</string>
-    <string name="rename_action" msgid="5559600076028658757">"确定"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"取消"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"添加到主屏幕"</string>
-    <string name="group_applications" msgid="3797214114206693605">"应用"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"快捷方式"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"小部件"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"您的主屏幕上没有空间了。"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜索应用"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在加载应用…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"未找到与“<xliff:g id="QUERY">%1$s</xliff:g>”相符的应用"</string>
     <string name="out_of_space" msgid="4691004494942118364">"此主屏幕上已没有空间。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"收藏栏已满"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"该小部件太大,收藏栏中放不下"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"已创建“<xliff:g id="NAME">%s</xliff:g>”快捷方式。"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"已删除“<xliff:g id="NAME">%s</xliff:g>”快捷方式。"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"“<xliff:g id="NAME">%s</xliff:g>”快捷方式已存在。"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"选择快捷方式"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"选择应用"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"应用"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主屏幕"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"删除"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"卸载"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"删除"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"卸载"</string>
     <string name="info_target_label" msgid="8053346143994679532">"应用信息"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"应用"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"删除"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"卸载更新内容"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"卸载应用"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"应用详情"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"已选择1个应用"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"已选择1个小部件"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"已选择1个文件夹"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"已选择1个快捷方式"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安装快捷方式"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允许应用自行添加快捷方式。"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"卸载快捷方式"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"允许应用自行删除快捷方式。"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"读取主屏幕设置和快捷方式"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"允许应用读取主屏幕中的设置和快捷方式。"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"写入主屏幕设置和快捷方式"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"加载小部件时出现问题"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"设置"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"这是系统应用,无法卸载。"</string>
-    <string name="dream_name" msgid="1530253749244328964">"火箭发射器"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名文件夹"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"主屏幕%1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"应用:第%1$d页,共%2$d页"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"小部件:第%1$d页,共%2$d页"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"欢迎使用"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"您的主屏幕您做主。"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"添加更多屏幕来容纳应用和文件夹"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"复制应用图标"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"要导入旧的主屏幕中的图标和文件夹吗?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"复制图标"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"使用全新配置"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"整理您的空间"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"触摸并按住背景,即可管理壁纸、小部件和设置。"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"壁纸、小部件和设置"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"触摸并按住背景,即可进行个性化设置"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"这是一个文件夹"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"要创建一个类似的文件夹,请触摸并按住某个应用,然后将其移至另一个应用上。"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"确定"</string>
     <string name="folder_opened" msgid="94695026776264709">"文件夹已打开,大小为<xliff:g id="WIDTH">%1$d</xliff:g>×<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"触摸可关闭文件夹"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"触摸可保存新名称"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"小部件"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"壁纸"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"设置"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"正在等待"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"正在下载"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"正在安装"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"允许旋转"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"未知"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"无法还原"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜索"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"未安装此应用"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"未安装此图标对应的应用。您可以移除此图标,也可以尝试搜索相应的应用并手动安装。"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"添加到主屏幕"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"将项目移至此处"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"已将项目添加到主屏幕"</string>
+    <string name="item_removed" msgid="851119963877842327">"项目已移除"</string>
+    <string name="action_move" msgid="4339390619886385032">"移动项目"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"移至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 行第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 列"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"移至第 <xliff:g id="NUMBER">%1$s</xliff:g> 个位置"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"移至收藏夹第 <xliff:g id="NUMBER">%1$s</xliff:g> 个位置"</string>
+    <string name="item_moved" msgid="4606538322571412879">"已移动项目"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"添加到“<xliff:g id="NAME">%1$s</xliff:g>”文件夹"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"添加到“<xliff:g id="NAME">%1$s</xliff:g>”所在文件夹"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"项目已添加到文件夹"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"创建“<xliff:g id="NAME">%1$s</xliff:g>”文件夹"</string>
+    <string name="folder_created" msgid="6409794597405184510">"文件夹已创建"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"移至主屏幕"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"将屏幕向左移动"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"将屏幕向右移动"</string>
+    <string name="screen_moved" msgid="266230079505650577">"屏幕已移动"</string>
+    <string name="action_resize" msgid="1802976324781771067">"调整大小"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"增加宽度"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"减小宽度"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"减小高度"</string>
+    <string name="widget_resized" msgid="9130327887929620">"小部件尺寸已调整为:宽度 <xliff:g id="NUMBER_0">%1$s</xliff:g>,高度 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 2eb7008..f7d240e 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"主畫面"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android 核心應用程式"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"工作"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"尚未安裝應用程式。"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"目前無法使用這個應用程式"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"在安全模式中無法使用「已下載的應用程式」功能"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"在安全模式中無法使用小工具"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"小工具"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"小工具"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"顯示記憶體"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"輕觸並按住小工具即可選取。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"無法將項目拖放至主畫面。"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"選擇要建立的小工具"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"資料夾名稱"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"重新命名資料夾"</string>
-    <string name="rename_action" msgid="5559600076028658757">"確定"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"取消"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"新增至主畫面"</string>
-    <string name="group_applications" msgid="3797214114206693605">"應用程式"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"捷徑"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"小工具"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"主畫面已無空間。"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"無法找到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
     <string name="out_of_space" msgid="4691004494942118364">"主畫面已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"我的收藏寄存區沒有足夠空間"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"這個小工具過大,我的收藏寄存區沒有足夠空間"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"已建立「<xliff:g id="NAME">%s</xliff:g>」捷徑。"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"已移除「<xliff:g id="NAME">%s</xliff:g>」捷徑。"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"「<xliff:g id="NAME">%s</xliff:g>」捷徑已存在。"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"選擇捷徑"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"選擇應用程式"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"應用程式"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主畫面"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"移除"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"解除安裝"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"移除"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"解除安裝"</string>
     <string name="info_target_label" msgid="8053346143994679532">"應用程式資料"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"應用程式"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"移除"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"解除安裝更新"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"解除安裝應用程式"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"應用程式詳細資料"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"已選取 1 個應用程式"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"已選取 1 個小工具"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"已選取 1 個資料夾"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"已選取 1 個捷徑"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式無需使用者許可也可新增捷徑。"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"解除安裝捷徑"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"允許應用程式無需使用者許可也可移除捷徑。"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"讀取主畫面的設定和捷徑"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"允許應用程式讀取主畫面中的設定和捷徑。"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"寫入主畫面的設定和捷徑"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"載入小工具時發生問題"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,無法將其解除安裝。"</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"主畫面 %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"第 %1$d 個應用程式頁面,共 %2$d 頁"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"第 %1$d 個小工具頁面,共 %2$d 頁"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"歡迎"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"自訂主畫面。"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"建立更多應用程式和資料夾的畫面"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"複製您的應用程式圖示"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"要從舊主畫面匯入圖示和資料夾嗎?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"複製圖示"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"重新開始"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"管理您的空間"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"輕觸並按住背景,即可管理桌布、小工具和設定。"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"桌布、小工具和設定"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"輕觸並按住背景即可自訂"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"資料夾顯示如下"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"如要建立類似的資料夾,請輕觸並按住某個應用程式,然後疊到另一個應用程式之上。"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"確定"</string>
     <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"輕觸即可關閉資料夾"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"輕觸即可儲存新改的名稱"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"小工具"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"設定"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"等候中"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"下載中"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"安裝中"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"允許旋轉"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"無法還原"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"尚未安裝這個應用程式"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"您尚未安裝這個圖示代表的應用程式。您可以移除這個圖示,也可以搜尋該應用程式並手動安裝。"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"新增至主畫面"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"移動項目至這裡"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目加入至主畫面"</string>
+    <string name="item_removed" msgid="851119963877842327">"項目已移除"</string>
+    <string name="action_move" msgid="4339390619886385032">"移動項目"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"移動至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 行第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 列"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"移動至位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"移動至喜愛的位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"已移動項目"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"加入資料夾:<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"加入至資料夾:<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"項目已加入資料夾"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"使用以下項目建立資料夾:<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"已建立資料夾"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"移動至主畫面"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"向左移動螢幕"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"向右移動螢幕"</string>
+    <string name="screen_moved" msgid="266230079505650577">"已移動螢幕"</string>
+    <string name="action_resize" msgid="1802976324781771067">"重新調整大小"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"增加闊度"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"減少闊度"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
+    <string name="widget_resized" msgid="9130327887929620">"已調整小工具的大小至闊 <xliff:g id="NUMBER_0">%1$s</xliff:g> 高 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 52e7583..39a0ec7 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Launcher3"</string>
-    <string name="home" msgid="7658288663002113681">"主螢幕"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Android 核心應用程式"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"公司"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"應用程式未安裝。"</string>
     <string name="activity_not_available" msgid="7456344436509528827">"應用程式目前無法使用"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"在安全模式中無法使用「已下載的應用程式」功能"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"在安全模式下無法使用小工具"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"小工具"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"小工具"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"顯示記憶體"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"輕觸並按住小工具即可選取。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"無法將項目拖放至這個主螢幕上。"</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"選擇要建立的小工具"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"資料夾名稱"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"重新命名資料夾"</string>
-    <string name="rename_action" msgid="5559600076028658757">"確定"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"取消"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"新增至主螢幕"</string>
-    <string name="group_applications" msgid="3797214114206693605">"應用程式"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"捷徑"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"小工具"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"主螢幕已無空間。"</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"搜尋應用程式"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"正在載入應用程式…"</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"找不到符合「<xliff:g id="QUERY">%1$s</xliff:g>」的應用程式"</string>
     <string name="out_of_space" msgid="4691004494942118364">"這個主螢幕已無空間。"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"「我的最愛」匣已無可用空間"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"這個小工具過大,「我的最愛」匣無法容納"</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"已建立「<xliff:g id="NAME">%s</xliff:g>」捷徑。"</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"已移除「<xliff:g id="NAME">%s</xliff:g>」捷徑。"</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"「<xliff:g id="NAME">%s</xliff:g>」捷徑已存在。"</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"選擇捷徑"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"選擇應用程式"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"應用程式"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"主螢幕"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"移除"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"解除安裝"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"移除"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"解除安裝"</string>
     <string name="info_target_label" msgid="8053346143994679532">"應用程式資訊"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"應用程式"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"移除"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"解除安裝更新"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"解除安裝應用程式"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"應用程式詳細資料"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"已選取 1 個應用程式"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"已選取 1 個小工具"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"已選取 1 個資料夾"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"已選取 1 個捷徑"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"安裝捷徑"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"允許應用程式自動新增捷徑。"</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"解除安裝捷徑"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"允許應用程式自動移除捷徑。"</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"讀取主螢幕的設定和捷徑"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"允許應用程式讀取主螢幕中的設定和捷徑。"</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"寫入主螢幕設定和捷徑"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"載入小工具時發生問題"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"設定"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"這是系統應用程式,不可解除安裝。"</string>
-    <string name="dream_name" msgid="1530253749244328964">"Rocket Launcher"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"未命名的資料夾"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"主螢幕 %1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"應用程式:第 %1$d 頁,共 %2$d 頁"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"小工具:第 %1$d 頁,共 %2$d 頁"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"歡迎使用"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"主螢幕由您作主。"</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"建立更多畫面容納應用程式和資料夾"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"複製您的應用程式圖示"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"要從舊的主螢幕匯入圖示和資料夾嗎?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"複製圖示"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"重新開始"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"管理您的空間"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"輕觸並按住背景,即可管理桌布、小工具和設定。"</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"桌布、小工具和設定"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"輕觸並按住背景即可自訂"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"知道了"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"資料夾顯示如下"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"如要建立類似的資料夾,請輕觸並按住應用程式,然後將應用程式疊放在另一個應用程式上。"</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"確定"</string>
     <string name="folder_opened" msgid="94695026776264709">"資料夾已開啟 (<xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>)"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"輕觸即可關閉資料夾"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"輕觸即可儲存新名稱"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"小工具"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"桌布"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"設定"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"等待中"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"下載中…"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"安裝中"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"允許輪播"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"不明"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"無法還原"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"全部移除"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"移除"</string>
     <string name="abandoned_search" msgid="891119232568284442">"搜尋"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"尚未安裝這個應用程式"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"您尚未安裝這個圖示代表的應用程式。您可以移除這個圖示,也可以搜尋該應用程式並手動安裝。"</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"新增至主畫面"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"將項目移至這裡"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"已將項目新增到主畫面"</string>
+    <string name="item_removed" msgid="851119963877842327">"已移除項目"</string>
+    <string name="action_move" msgid="4339390619886385032">"移動項目"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"移至第 <xliff:g id="NUMBER_0">%1$s</xliff:g> 列第 <xliff:g id="NUMBER_1">%2$s</xliff:g> 欄"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"移至位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"移至收藏位置 <xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"已移動項目"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"新增到「<xliff:g id="NAME">%1$s</xliff:g>」資料夾"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"新增到「<xliff:g id="NAME">%1$s</xliff:g>」所在資料夾"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"已將項目新增到資料夾"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"建立「<xliff:g id="NAME">%1$s</xliff:g>」資料夾"</string>
+    <string name="folder_created" msgid="6409794597405184510">"已建立資料夾"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"移至主畫面"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"將畫面往左移"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"將畫面往右移"</string>
+    <string name="screen_moved" msgid="266230079505650577">"已移動畫面"</string>
+    <string name="action_resize" msgid="1802976324781771067">"調整大小"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"增加寬度"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"增加高度"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"減少寬度"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
+    <string name="widget_resized" msgid="9130327887929620">"已將小工具的寬度和高度分別調整為 <xliff:g id="NUMBER_0">%1$s</xliff:g> 和 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index aea09e8..83ba089 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -20,57 +20,27 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="application_name" msgid="5181331383435256801">"Isiqalisi3"</string>
-    <string name="home" msgid="7658288663002113681">"Ikhaya"</string>
-    <string name="uid_name" msgid="7820867637514617527">"Izinhlelo zokusebenza ze-Android Core"</string>
     <string name="folder_name" msgid="7371454440695724752"></string>
+    <string name="work_folder_name" msgid="3753320833950115786">"Umsebenzi"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"Uhlelo lokusebenza alufakiwe."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"Uhlelo lokusebenza alutholakali"</string>
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Uhlelo lokusebenza olulandiwe lukhutshaziwe kumodi ephephile"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Amawijethi akhutshaziwe kwimodi yokuphepha"</string>
-    <string name="widgets_tab_label" msgid="2921133187116603919">"Amawijethi"</string>
-    <string name="widget_adder" msgid="3201040140710381657">"Amawijethi"</string>
     <string name="toggle_weight_watcher" msgid="5645299835184636119">"Bonisa i-Mem"</string>
     <string name="long_press_widget_to_add" msgid="7699152356777458215">"Thinta uphinde ubambe ukuze uphakamise iwijethi."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
-    <string name="external_drop_widget_error" msgid="3165821058322217155">"Ayikwazanga ukwehlisela into kulesi sikrini se-Ikhaya."</string>
-    <string name="external_drop_widget_pick_title" msgid="3486317258037690630">"Khetha iwijethi ongayidala"</string>
-    <string name="rename_folder_label" msgid="3727762225964550653">"Igama lefolda"</string>
-    <string name="rename_folder_title" msgid="3771389277707820891">"Qamba kabusha ifolda"</string>
-    <string name="rename_action" msgid="5559600076028658757">"KULUNGILE"</string>
-    <string name="cancel_action" msgid="7009134900002915310">"Khansela"</string>
-    <string name="menu_item_add_item" msgid="1264911265836810421">"Faka kwisikrini saseKhaya"</string>
-    <string name="group_applications" msgid="3797214114206693605">"Izinhlelo zokusebenza"</string>
-    <string name="group_shortcuts" msgid="6012256992764410535">"Izinqamuleli"</string>
-    <string name="group_widgets" msgid="1569030723286851002">"Amawijethi"</string>
-    <string name="completely_out_of_space" msgid="6106288382070760318">"Akusenagumbi ezikrinini zakho Zekhaya."</string>
+    <string name="all_apps_search_bar_hint" msgid="7084713969757597256">"Sesha Izinhlelo Zokusebenza"</string>
+    <string name="all_apps_loading_message" msgid="7557140873644765180">"Ilayisha izinhlelo zokusebenza..."</string>
+    <string name="all_apps_no_search_results" msgid="6332185285860416787">"Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
     <string name="out_of_space" msgid="4691004494942118364">"Asisekho isikhala kulesi sikrini Sasekhaya."</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Asisekho isikhala kwitreyi lezintandokazi"</string>
-    <string name="invalid_hotseat_item" msgid="5779907847267573691">"Le wijethi inkulu kakhulu ukuba kwitreyi lezintandokazi."</string>
-    <string name="shortcut_installed" msgid="1701742129426969556">"Isinqamuleli esithi \"<xliff:g id="NAME">%s</xliff:g>\" sidaliwe."</string>
-    <string name="shortcut_uninstalled" msgid="8176767991305701821">"Isinqamuleli esithi \"<xliff:g id="NAME">%s</xliff:g>\" sisusiwe."</string>
-    <string name="shortcut_duplicate" msgid="9167217446062498127">"Isinqamuleli esithi \"<xliff:g id="NAME">%s</xliff:g>\" sesivele sikhona."</string>
-    <string name="title_select_shortcut" msgid="6680642571148153868">"Khetha isinqamulelo"</string>
-    <string name="title_select_application" msgid="3280812711670683644">"Khetha uhlelo lokusebenza"</string>
     <string name="all_apps_button_label" msgid="9110807029020582876">"Izinhlelo zokusebenza"</string>
     <string name="all_apps_home_button_label" msgid="252062713717058851">"Ikhaya"</string>
-    <string name="delete_zone_label_workspace" msgid="4009607676751398685">"Susa"</string>
-    <string name="delete_zone_label_all_apps" msgid="8083826390278958980">"Khipha"</string>
     <string name="delete_target_label" msgid="1822697352535677073">"Susa"</string>
     <string name="delete_target_uninstall_label" msgid="5100785476250872595">"Khipha"</string>
     <string name="info_target_label" msgid="8053346143994679532">"Ulwazi lohlelo lokusebenza"</string>
-    <string name="accessibility_all_apps_button" msgid="2603132375383800483">"Izinhlelo zokusebenza"</string>
-    <string name="accessibility_delete_button" msgid="6466114477993744621">"Susa"</string>
-    <string name="delete_zone_label_all_apps_system_app" msgid="449755632749610895">"Khipha isibuyekezo"</string>
-    <string name="cab_menu_delete_app" msgid="7435191475867183689">"Khipha uhlelo lokusebenza"</string>
-    <string name="cab_menu_app_info" msgid="8593722221450362342">"Imininingwane yohlelo lokusebenza"</string>
-    <string name="cab_app_selection_text" msgid="374688303047985416">"1 uhlelo lokusebenza olukhethiwe"</string>
-    <string name="cab_widget_selection_text" msgid="1833458597831541241">"1 iwijethi ekhethiwe"</string>
-    <string name="cab_folder_selection_text" msgid="7999992513806132118">"1 ifolda ekhethiwe"</string>
-    <string name="cab_shortcut_selection_text" msgid="2103811025667946450">"1 isinqamuleli esikhethiwe"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"faka izinqamuleli"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Ivumela uhlelo lokusebenza ukufaka izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
-    <string name="permlab_uninstall_shortcut" msgid="864595034498083837">"khipha izinqamuleli"</string>
-    <string name="permdesc_uninstall_shortcut" msgid="5134129545001836849">"Ivumela uhlelo lokusebenza ukuthi lisuse izinqamuleli ngaphandle kokungenelela komsebenzisi."</string>
     <string name="permlab_read_settings" msgid="1941457408239617576">"funda izilungiselelo zokuthi Ikhaya nezinqamuleli"</string>
     <string name="permdesc_read_settings" msgid="5833423719057558387">"Ivumela uhlelo lokusebenza ukuthi lifunde izilungiselelo nezinqamuleli ekhaya."</string>
     <string name="permlab_write_settings" msgid="3574213698004620587">"bhala izilungiselelo zokuthi Ikhaya nezinqamuleli"</string>
@@ -78,30 +48,17 @@
     <string name="gadget_error_text" msgid="6081085226050792095">"Inkinga yokulayisha iwijethi"</string>
     <string name="gadget_setup_text" msgid="8274003207686040488">"Ukumisa"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Lolu uhlelo lokusebenza lwesistimu futhi alikwazi ukukhishwa."</string>
-    <string name="dream_name" msgid="1530253749244328964">"Isiqalisi se-Rocket"</string>
     <string name="folder_hint_text" msgid="6617836969016293992">"Ifolda engenagama"</string>
-    <string name="workspace_description_format" msgid="2950174241104043327">"Isikrini sasekhaya esingu-%1$d"</string>
     <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="apps_customize_apps_scroll_format" msgid="370005296147130238">"Ikhasi lezinhlelo zokusebenza elingu-%1$d le-%2$d"</string>
-    <string name="apps_customize_widgets_scroll_format" msgid="3106209519974971521">"Ikhasi lamawijethi elingu-%1$d le-%2$d"</string>
     <string name="first_run_cling_title" msgid="2459738000155917941">"Siyakwamukela"</string>
-    <string name="first_run_cling_description" msgid="6447072552696253358">"Zizwe usekhaya."</string>
-    <string name="first_run_cling_custom_content_hint" msgid="6090628589029352439"></string>
-    <string name="first_run_cling_search_bar_hint" msgid="5909062802402452582"></string>
-    <string name="first_run_cling_create_screens_hint" msgid="6950729526680114157">"Dala izikrini eziningi zezinhlelo zokusebenza namafolda"</string>
     <string name="migration_cling_title" msgid="9181776667882933767">"Kopisha izithonjana zakho zohlelo lokusebenza"</string>
     <string name="migration_cling_description" msgid="2752413805582227644">"Ngenisa izithonjana namafolda kusukela kuzikrini zakho ezindala zasekhaya?"</string>
     <string name="migration_cling_copy_apps" msgid="946331230090919440">"KOPISHA IZITHONJANA"</string>
     <string name="migration_cling_use_default" msgid="2626475813981258626">"QALISA KABUSHA"</string>
-    <string name="workspace_cling_title" msgid="5626202359865825661">"Hlela isikhala sakho"</string>
-    <string name="workspace_cling_move_item" msgid="528201129978005352">"Thinta uphinde ubambe okungemuva ukuze uphathe isithombe sangemuva, amawijethi nezilungiselelo."</string>
     <string name="workspace_cling_longpress_title" msgid="9173998993909018310">"Izithombe zangemuva, amawijethi, nezilungiselelo"</string>
     <string name="workspace_cling_longpress_description" msgid="4119994475505235248">"Thinta uphinde ubambe ingemuva ukuze wenze ngokwezifiso"</string>
     <string name="workspace_cling_longpress_dismiss" msgid="368660286867640874">"NGIYITHOLILE"</string>
-    <string name="folder_cling_title" msgid="3894908818693254164">"Nayi ifolda"</string>
-    <string name="folder_cling_create_folder" msgid="6158215559475836131">"Ukuze udale eyodwa efana nale, thinta uphinde ubambe uhlelo lokusebenza, bese ulidlulisa ngaphezulu kwelinye."</string>
-    <string name="cling_dismiss" msgid="8962359497601507581">"KULUNGILE"</string>
     <string name="folder_opened" msgid="94695026776264709">"Ifolda ivuliwe, <xliff:g id="WIDTH">%1$d</xliff:g> nge-<xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
     <string name="folder_tap_to_close" msgid="1884479294466410023">"Thinta ukuze uvale ifolda"</string>
     <string name="folder_tap_to_rename" msgid="9191075570492871147">"Thinta ukuze ulondoloze ukuqamba kabusha"</string>
@@ -111,14 +68,34 @@
     <string name="widget_button_text" msgid="2880537293434387943">"Amawijethi"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Izithombe zangemuva"</string>
     <string name="settings_button_text" msgid="8119458837558863227">"Izilungiselelo"</string>
-    <string name="package_state_enqueued" msgid="6227252464303085641">"Ilindile"</string>
-    <string name="package_state_downloading" msgid="4088770468458724721">"Iyalanda"</string>
-    <string name="package_state_installing" msgid="7588193972189849870">"Iyafaka"</string>
+    <string name="allow_rotation_title" msgid="2118706734511831751">"Vumela ukuphenduka"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Akwaziwa"</string>
-    <string name="package_state_error" msgid="7672093962724223588">"Ayibuyiselwe"</string>
-    <string name="abandoned_clean_all" msgid="5256770727689657618">"Susa konke"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Susa"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Sesha"</string>
     <string name="abandoned_promises_title" msgid="7096178467971716750">"Lolu hlelo lokusebenza alifakiwe"</string>
     <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Uhlelo lokusebenza lalesi sithonjana alufakiwe. Ungalisusa, noma sesha uhlelo lokusebenza bese uzifakela lona ngokuzenzela."</string>
+    <string name="action_add_to_workspace" msgid="8902165848117513641">"Faka kusikrini sasekhaya"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Hambisa into lapha"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Into ingezwe kusikrini sasekhaya"</string>
+    <string name="item_removed" msgid="851119963877842327">"Into isusiwe"</string>
+    <string name="action_move" msgid="4339390619886385032">"Hambisa into"</string>
+    <string name="move_to_empty_cell" msgid="2833711483015685619">"Hambisa kurowu engu-<xliff:g id="NUMBER_0">%1$s</xliff:g> ikholomu engu-<xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Hambisa kusimo esingu-<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Hambisa kusimo sezintandokazi esingu-<xliff:g id="NUMBER">%1$s</xliff:g>"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Into ihanjisiwe"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Engeza kufolda: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Engeza kufolda nge-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Into ingeziwe kufolda"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Dala ifolda nge-: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Ifolda idaliwe"</string>
+    <string name="action_move_to_workspace" msgid="1603837886334246317">"Hambisa kusikrini sasekhaya"</string>
+    <string name="action_move_screen_left" msgid="8854216831569401665">"Hambisa isikrini kwesokunxele"</string>
+    <string name="action_move_screen_right" msgid="329334910274311123">"Hambisa isikrini kwesokudla"</string>
+    <string name="screen_moved" msgid="266230079505650577">"Isikrini sihanjisiwe"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Shintsha usayizi"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Khuphula ububanzi"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Khuphula ubude"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Nciphisa ububanzi"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Nciphisa ubude"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Iwijethi inikezwe usayizi omusha ngobubanzi obungu-<xliff:g id="NUMBER_0">%1$s</xliff:g> ubude obungu-<xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 3331cde..827332a 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -18,6 +18,19 @@
 
 <resources>
 
+    <!-- BubbleTextView specific attributes. -->
+    <declare-styleable name="BubbleTextView">
+        <attr name="layoutHorizontal" format="boolean" />
+        <attr name="iconSizeOverride" format="dimension" />
+        <attr name="iconDisplay" format="integer">
+            <enum name="workspace" value="0" />
+            <enum name="all_apps" value="1" />
+            <enum name="widget_section" value="2" />
+        </attr>
+        <attr name="deferShadowGeneration" format="boolean" />
+        <attr name="customShadows" format="boolean" />
+    </declare-styleable>
+
     <!-- Page Indicator specific attributes. -->
     <declare-styleable name="PageIndicator">
         <attr name="windowSize" format="integer"  />
@@ -59,16 +72,6 @@
         <attr name="maxGap" format="dimension" />
     </declare-styleable>
 
-    <!-- StrokedTextView specific attributes. -->
-    <declare-styleable name="StrokedTextView">
-        <!-- The color of the stroke outline -->
-        <attr name="strokeColor" format="color" />
-        <!-- The color of the text -->
-        <attr name="strokeTextColor" format="color" />
-        <!-- The width of the stroke -->
-        <attr name="strokeWidth" format="float" />
-    </declare-styleable>
-
     <!-- PagedView specific attributes. These attributes are used to customize
          a PagedView view in XML files. -->
     <declare-styleable name="PagedView">
@@ -80,28 +83,6 @@
         <attr name="pageIndicator" format="reference" />
     </declare-styleable>
 
-    <declare-styleable name="BubbleTextView">
-        <!-- A spacing override for the icons within a page -->
-        <attr name="customShadows" format="boolean" />
-    </declare-styleable>
-
-    <!-- AppsCustomizePagedView specific attributes.  These attributes are used to
-         customize an AppsCustomizePagedView in xml files. -->
-    <declare-styleable name="AppsCustomizePagedView">
-        <!-- Max number of cells of applications horizontally -->
-        <attr name="maxAppCellCountX" format="integer" />
-        <!-- Max number of cells of applications vertically -->
-        <attr name="maxAppCellCountY" format="integer" />
-        <!-- Horizontal spacing between widgets and wallpapers -->
-        <attr name="widgetCellWidthGap" format="dimension" />
-        <!-- Vertical spacing between widgets -->
-        <attr name="widgetCellHeightGap" format="dimension" />
-        <!-- Number of widgets horizontally -->
-        <attr name="widgetCountX" format="integer" />
-        <!-- Number of widgets vertically -->
-        <attr name="widgetCountY" format="integer" />
-    </declare-styleable>
-
     <!-- XML attributes used by default_workspace.xml -->
     <declare-styleable name="Favorite">
         <attr name="className" format="string" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2daf9fe..51e4d40 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,20 +20,34 @@
 <resources>
     <!-- The color tints to apply to the text and drag view when hovering
          over the delete target or the info target -->
-    <color name="delete_target_hover_tint">#DAFF0000</color>
-    <color name="info_target_hover_tint">#DA0099CC</color>
+    <color name="delete_target_hover_tint">#FFC1C1C1</color>
+    <color name="uninstall_target_hover_tint">#FFF0592B</color>
+    <color name="info_target_hover_tint">#FF009688</color>
     <color name="cling_scrim_background">#80000000</color>
 
-    <color name="bubble_dark_background">#20000000</color>
     <color name="focused_background">#80c6c5c5</color>
 
-    <color name="appwidget_error_color">#FCCC</color>
-
     <color name="workspace_icon_text_color">#FFF</color>
 
-    <color name="quantum_panel_text_color">#FF666666</color>
-    <color name="quantum_panel_text_shadow_color">#FFC4C4C4</color>
-    <color name="outline_color">#FFFFFFFF</color>
-    <color name="widget_text_panel">#FF374248</color>
+    <color name="workspace_edge_effect_color">#FFFFFFFF</color>
+    <color name="folder_edge_effect_color">#FF757575</color>
 
+    <color name="quantum_panel_text_color">#FF666666</color>
+    <color name="quantum_panel_bg_color">#FFF5F5F5</color>
+    <color name="quantum_panel_bg_color_dark">#FF374248</color>
+
+    <color name="outline_color">#FFFFFFFF</color>
+
+    <!-- Containers -->
+    <color name="container_fastscroll_thumb_inactive_color">#42000000</color>
+    <color name="container_fastscroll_thumb_active_color">#009688</color>
+
+    <!-- All Apps -->
+    <color name="all_apps_grid_section_text_color">#009688</color>
+
+    <!-- Widgets view -->
+    <color name="widgets_view_fastscroll_thumb_inactive_color">#42FFFFFF</color>
+    <color name="widgets_view_section_text_color">#FFFFFF</color>
+    <color name="widgets_view_item_text_color">#C4C4C4</color>
+    <color name="widgets_cell_color">#263238</color>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 96bd13b..73de794 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,8 +1,5 @@
 <resources>
 <!-- Dynamic Grid -->
-    <integer name="config_dynamic_grid_max_long_edge_cell_count">6</integer>
-    <integer name="config_dynamic_grid_max_short_edge_cell_count">5</integer>
-    <integer name="config_dynamic_grid_min_edge_cell_count">3</integer>
     <!-- Out of 100, the percent of space the overview bar should try and take vertically. -->
     <integer name="config_dynamic_grid_overview_icon_zone_percentage">20</integer>
     <!-- Out of 100, the percent to shrink the workspace during overview mode. -->
@@ -23,28 +20,22 @@
 
 <!-- DragController -->
     <integer name="config_flingToDeleteMinVelocity">-1500</integer>
+    <item type="id" name="drag_event_parity" />
 
-<!-- AllApps/Customize/AppsCustomize -->
+<!-- AllApps & Launcher transitions -->
     <!-- The alpha of the AppsCustomize bg in spring loaded mode -->
     <integer name="config_workspaceScrimAlpha">55</integer>
-    <integer name="config_workspaceUnshrinkTime">300</integer>
+    <integer name="config_allAppsTransitionTime">100</integer>
     <integer name="config_overviewTransitionTime">250</integer>
 
     <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
     <integer name="config_workspaceSpringLoadShrinkPercentage">80</integer>
 
-    <!-- Fade/zoom in/out duration & scale in the AllApps transition.
-         Note: This should be less than the workspaceShrinkTime as they happen together. -->
-    <integer name="config_appsCustomizeRevealTime">220</integer>
-    <integer name="config_appsCustomizeZoomInTime">350</integer>
-    <integer name="config_appsCustomizeZoomOutTime">600</integer>
-    <integer name="config_appsCustomizeZoomScaleFactor">7</integer>
-    <integer name="config_appsCustomizeFadeInTime">250</integer>
-    <integer name="config_appsCustomizeFadeOutTime">200</integer>
-    <integer name="config_appsCustomizeWorkspaceShrinkTime">300</integer>
-
-    <integer name="config_appsCustomizeConcealTime">250</integer>
-    <integer name="config_appsCustomizeItemsAlphaStagger">60</integer>
+    <!-- Fade/zoom in/out duration & scale in a Launcher overlay transition.
+         Note: This should be less than the config_overlayTransitionTime as they happen together. -->
+    <integer name="config_overlayRevealTime">220</integer>
+    <integer name="config_overlayTransitionTime">300</integer>
+    <integer name="config_overlayItemsAlphaStagger">60</integer>
 
     <!-- This constant stores the ratio of the all apps button drawable which
          is used for internal (baked-in) padding -->
@@ -52,20 +43,7 @@
 
     <integer name="config_workspaceDefaultScreen">0</integer>
 
-    <!-- Tab transition animation duration -->
-    <integer name="config_tabTransitionDuration">250</integer>
-
-    <!-- The slope, in percent, of the drag movement needed to drag an item out of
-         AppsCustomize (y / x * 100%)  -->
-    <integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
-
 <!-- Workspace -->
-    <!-- Whether or not the drop targets drop down as opposed to fade in -->
-    <bool name="config_useDropTargetDownTransition">false</bool>
-
-    <!-- The transition duration for the background of the drop targets -->
-    <integer name="config_dropTargetBgTransitionDuration">0</integer>
-
     <!-- The duration (in ms) of the fade animation on the object outlines, used when
          we are dragging objects around on the home screen. -->
     <integer name="config_dragOutlineFadeTime">900</integer>
@@ -86,13 +64,6 @@
     <!-- The distance at which the animation should take the max duration -->
     <integer name="config_dropAnimMaxDist">800</integer>
 
-    <!-- Properties controlling the workspace fade-out during dragging -->
-    <integer name="config_dragFadeOutAlpha">80</integer>
-    <integer name="config_dragFadeOutDuration">250</integer>
-
-    <!-- Camera distance for the overscroll effect -->
-    <integer name="config_cameraDistance">8000</integer>
-
 <!-- Hotseat -->
     <bool name="hotseat_transpose_layout_with_orientation">true</bool>
 
@@ -106,4 +77,15 @@
     <!-- Name of a subclass of com.android.launcher3.BuildInfo used to
          get build information. Can be empty. -->
     <string name="build_info_class" translatable="false"></string>
+
+<!-- Accessibility actions -->
+    <item type="id" name="action_remove" />
+    <item type="id" name="action_uninstall" />
+    <item type="id" name="action_info" />
+    <item type="id" name="action_add_to_workspace" />
+    <item type="id" name="action_move" />
+    <item type="id" name="action_move_to_workspace" />
+    <item type="id" name="action_move_screen_backwards" />
+    <item type="id" name="action_move_screen_forwards" />
+    <item type="id" name="action_resize" />
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f12cb57..589d696 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,19 +15,25 @@
 -->
 
 <resources>
+    <dimen name="app_icon_size">64dp</dimen>
+
 <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">6dp</dimen>
     <dimen name="dynamic_grid_search_bar_max_width">500dp</dimen>
     <dimen name="dynamic_grid_search_bar_height">56dp</dimen>
     <dimen name="dynamic_grid_page_indicator_height">20dp</dimen>
     <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
-    <dimen name="dynamic_grid_all_apps_cell_padding">18dp</dimen>
     <dimen name="dynamic_grid_workspace_page_spacing">8dp</dimen>
     <dimen name="dynamic_grid_overview_min_icon_zone_height">80dp</dimen>
     <dimen name="dynamic_grid_overview_max_icon_zone_height">120dp</dimen>
     <dimen name="dynamic_grid_overview_bar_item_width">80dp</dimen>
     <dimen name="dynamic_grid_overview_bar_spacer_width">20dp</dimen>
 
+<!-- App Widget resize frame -->
+    <dimen name="default_widget_padding">8dp</dimen>
+    <dimen name="widget_handle_margin">13dp</dimen>
+    <dimen name="resize_frame_background_padding">24dp</dimen>
+
 <!-- Cling -->
     <dimen name="cling_migration_logo_height">240dp</dimen>
     <dimen name="cling_migration_logo_width">165dp</dimen>
@@ -38,60 +44,89 @@
 
 <!-- Workspace -->
     <dimen name="workspace_max_gap">16dp</dimen>
-    <dimen name="workspace_overscroll_drawable_padding">0dp</dimen>
 
 <!-- QSB -->
     <dimen name="toolbar_button_vertical_padding">4dip</dimen>
     <dimen name="toolbar_button_horizontal_padding">12dip</dimen>
 
-<!-- AllApps/Customize/AppsCustomize -->
-    <!-- The height of the tab bar - if this changes, we should update the
-         external icon width/height above to compensate -->
-    <dimen name="apps_customize_tab_bar_height">52dp</dimen>
-    <dimen name="apps_customize_tab_bar_margin_top">0dp</dimen>
-    <dimen name="app_icon_size">48dp</dimen>
-    <dimen name="apps_customize_horizontal_padding">0dp</dimen>
+<!-- Container -->
+    <!-- Note: This needs to match the fixed insets for the search box. -->
+    <dimen name="container_bounds_inset">8dp</dimen>
+    <!-- Notes: container_bounds_inset - quantum_panel_outer_padding -->
+    <dimen name="container_bounds_minus_quantum_panel_padding_inset">4dp</dimen>
 
-    <!-- The AppsCustomize page indicator -->
-    <dimen name="apps_customize_page_indicator_height">12dp</dimen>
-    <dimen name="apps_customize_page_indicator_margin">4dp</dimen>
-    <dimen name="apps_customize_page_indicator_offset">16dp</dimen>
+    <dimen name="container_fastscroll_thumb_min_width">4dp</dimen>
+    <dimen name="container_fastscroll_thumb_max_width">8dp</dimen>
+    <dimen name="container_fastscroll_thumb_height">64dp</dimen>
+    <dimen name="container_fastscroll_thumb_touch_inset">-24dp</dimen>
+    <dimen name="container_fastscroll_popup_size">72dp</dimen>
+    <dimen name="container_fastscroll_popup_text_size">48dp</dimen>
 
-    <!-- Drag padding to add to the bottom of drop targets -->
-    <dimen name="drop_target_drag_padding">14dp</dimen>
-    <dimen name="drop_target_text_size">14sp</dimen>
+<!-- All Apps -->
+    <dimen name="all_apps_grid_view_start_margin">0dp</dimen>
+    <dimen name="all_apps_grid_section_y_offset">8dp</dimen>
+    <dimen name="all_apps_grid_section_text_size">24sp</dimen>
+    <dimen name="all_apps_search_bar_height">48dp</dimen>
+    <dimen name="all_apps_search_bar_prediction_bar_padding">8dp</dimen>
+    <dimen name="all_apps_icon_top_bottom_padding">8dp</dimen>
+    <dimen name="all_apps_icon_width_gap">24dp</dimen>
+    <!-- The top padding should account for the existing all_apps_list_top_bottom_padding -->
+    <dimen name="all_apps_prediction_icon_top_padding">8dp</dimen>
+    <dimen name="all_apps_prediction_icon_bottom_padding">18dp</dimen>
+    <dimen name="all_apps_list_top_bottom_padding">8dp</dimen>
 
-<!-- Dragging -->
-    <!-- the area at the edge of the screen that makes the workspace go left
-         or right while you're dragging. -->
-    <dimen name="scroll_zone">20dp</dimen>
+<!-- Widget tray -->
+    <dimen name="widget_container_inset">8dp</dimen>
+    <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
+    <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
+    <dimen name="widget_preview_horizontal_padding">8dp</dimen>
 
-    <!-- When dragging items on the workspace, the number of dps by which the position of
-     the drag view should be offset from the position of the original view. -->
-    <dimen name="dragViewOffsetX">0dp</dimen>
-    <dimen name="dragViewOffsetY">0dp</dimen>
-    <!--  When dragging an item, how much bigger (fixed dps) the dragged view
-          should be. If 0, it will not be scaled at all. -->
-    <dimen name="dragViewScale">12dp</dimen>
+    <dimen name="widget_section_height">56dp</dimen>
+    <dimen name="widget_section_icon_size">40dp</dimen>
+    <dimen name="widget_section_vertical_padding">8dp</dimen>
+    <dimen name="widget_section_horizontal_padding">16dp</dimen>
 
-    <!-- Padding applied to AppWidget previews -->
-    <dimen name="app_widget_preview_padding_left">16dp</dimen>
-    <dimen name="app_widget_preview_padding_right">16dp</dimen>
-    <dimen name="app_widget_preview_padding_top">32dp</dimen>
-    <dimen name="app_widget_preview_label_vertical_padding">8dp</dimen>
-    <dimen name="app_widget_preview_label_horizontal_padding">8dp</dimen>
+    <dimen name="widget_row_padding">8dp</dimen>
+    <dimen name="widget_row_divider">2dp</dimen>
 
     <!-- Padding applied to shortcut previews -->
     <dimen name="shortcut_preview_padding_left">0dp</dimen>
     <dimen name="shortcut_preview_padding_right">0dp</dimen>
     <dimen name="shortcut_preview_padding_top">0dp</dimen>
 
+<!-- Dragging -->
+    <!-- Drag padding to add to the bottom of drop targets -->
+    <dimen name="drop_target_drag_padding">14dp</dimen>
+    <dimen name="drop_target_text_size">14sp</dimen>
+
+    <!-- the area at the edge of the screen that makes the workspace go left
+         or right while you're dragging. -->
+    <dimen name="scroll_zone">20dp</dimen>
+
+    <!-- When dragging an item, how much bigger (fixed dps) the dragged view
+         should be. If 0, it will not be scaled at all. -->
+    <dimen name="dragViewScale">12dp</dimen>
+
+    <!-- Elevation for the drag view. It should be larger than elevation of all other drag sources
+         and drop targets like all-apps and folders -->
+    <dimen name="drag_elevation">30dp</dimen>
+
+<!-- Theme -->
+    <dimen name="quantum_panel_outer_padding">4dp</dimen>
+
 <!-- Folders -->
     <!-- The amount that the preview contents are inset from the preview background -->
     <dimen name="folder_preview_padding">4dp</dimen>
-    <dimen name="folder_name_padding">10dp</dimen>
 
 <!-- Sizes for managed profile badges -->
     <dimen name="profile_badge_size">24dp</dimen>
-    <dimen name="profile_badge_margin">4dp</dimen>
+    <dimen name="profile_badge_margin">5dp</dimen>
+    <dimen name="profile_badge_minimum_top">2dp</dimen>
+
+<!-- Shadows and outlines -->
+    <dimen name="blur_size_thin_outline">1dp</dimen>
+    <dimen name="blur_size_medium_outline">2dp</dimen>
+    <dimen name="blur_size_click_shadow">4dp</dimen>
+    <dimen name="click_shadow_high_shift">2dp</dimen>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b6f4237..88f149b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -32,12 +32,10 @@
 
     <!-- Application name -->
     <string name="application_name">Launcher3</string>
-    <!-- Accessibility-facing application name -->
-    <string name="home">Home</string>
-    <!-- Name for all applications running as this uid. -->
-    <string name="uid_name">Android Core Apps</string>
     <!-- Default folder name -->
     <string name="folder_name"></string>
+    <!-- Work folder name -->
+    <string name="work_folder_name">Work</string>
     <!-- Displayed when user selects a shortcut for an app that was uninstalled [CHAR_LIMIT=none]-->
     <string name="activity_not_found">App isn\'t installed.</string>
     <!-- Displayed when user selects a shortcut for an app that is current not available [CHAR_LIMIT=none]-->
@@ -46,84 +44,36 @@
     <string name="safemode_shortcut_error">Downloaded app disabled in Safe mode</string>
     <!-- SafeMode widget error string -->
     <string name="safemode_widget_error">Widgets disabled in Safe mode</string>
-    <!--  Labels for the tabs in the customize drawer -->
-    <string name="widgets_tab_label">Widgets</string>
-
-    <string name="widget_adder">Widgets</string>
 
     <string name="toggle_weight_watcher">Show Mem</string>
 
-    <!-- AppsCustomize pane -->
+    <!-- Widgets -->
     <!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
     <string name="long_press_widget_to_add">Touch &amp; hold to pick up a widget.</string>
     <!-- The format string for the dimensions of a widget in the drawer -->
     <!-- There is a special version of this format string for Farsi -->
     <string name="widget_dims_format">%1$d \u00d7 %2$d</string>
 
-    <!-- External-drop widget pick label format string [CHAR_LIMIT=25] -->
-    <string name="external_drop_widget_pick_format" translatable="false">%1$s (%2$d \u00d7 %3$d)</string>
-    <!-- External-drop widget error string.  This is the error that is shown
-         when you drag and item into the homescreen and it is unable to fit,
-         or an error is encountered. [CHAR_LIMIT=50] -->
-    <string name="external_drop_widget_error">Couldn\'t drop item on this Home screen.</string>
-    <!-- External-drop widget pick title.  This is shown as the title of the
-         dialog which allows you to pick which widgets to handle a particular
-         drop if there are multiple choices. [CHAR_LIMIT=35] -->
-    <string name="external_drop_widget_pick_title">Choose widget to create</string>
+    <!-- All Apps -->
+    <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
+    <string name="all_apps_search_bar_hint">Search Apps</string>
+    <!-- Loading apps text. [CHAR_LIMIT=50] -->
+    <string name="all_apps_loading_message">Loading Apps&#8230;</string>
+    <!-- No-search-results text. [CHAR_LIMIT=50] -->
+    <string name="all_apps_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
 
-    <!-- Folders -->
+    <!-- Drag and drop -->
     <skip />
-    <!-- Label of Folder name field in Rename folder dialog box -->
-    <string name="rename_folder_label">Folder name</string>
-    <!-- Title of dialog box -->
-    <string name="rename_folder_title">Rename folder</string>
-    <!-- Buttons in Rename folder dialog box -->
-    <string name="rename_action">OK</string>
-    <!-- Buttons in Rename folder dialog box -->
-    <string name="cancel_action">Cancel</string>
-
-    <!-- Shortcuts -->
-    <skip />
-    <!-- Title of dialog box -->
-    <string name="menu_item_add_item">Add to Home screen</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps -->
-    <string name="group_applications">Apps</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcut
-s -->
-    <string name="group_shortcuts">Shortcuts</string>
-    <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
-    <string name="group_widgets">Widgets</string>
-    <!-- Error message when user has filled all their home screens -->
-    <string name="completely_out_of_space">No more room on your Home screens.</string>
     <!-- Error message when user has filled a home screen -->
     <string name="out_of_space">No more room on this Home screen.</string>
     <!-- Error message when user has filled the hotseat -->
     <string name="hotseat_out_of_space">No more room in the Favorites tray</string>
-    <!-- Error message when user tries to drop an invalid item on the hotseat -->
-    <string name="invalid_hotseat_item">This widget is too large for the Favorites tray</string>
-    <!-- Message displayed when a shortcut is created by an external application -->
-    <string name="shortcut_installed">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" created.</string>
-    <!-- Message displayed when a shortcut is uninstalled by an external application -->
-    <string name="shortcut_uninstalled">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" was removed.</string>
-    <!-- Message displayed when an external application attemps to create a shortcut that already exists -->
-    <string name="shortcut_duplicate">Shortcut \"<xliff:g id="name" example="Browser">%s</xliff:g>\" already exists.</string>
-
-    <!-- Title of dialog when user is selecting shortcut to add to homescreen -->
-    <string name="title_select_shortcut">Choose shortcut</string>
-    <!-- Title of dialog when user is selecting an application to add to homescreen -->
-    <string name="title_select_application">Choose app</string>
 
     <!-- All applications label -->
     <string name="all_apps_button_label">Apps</string>
     <!-- Label for button in all applications label to go back home (to the workspace / desktop)
          for accessibilty (spoken when the button gets focus). -->
     <string name="all_apps_home_button_label">Home</string>
-    <!-- Label for trash icon on workspace. Meant to communicate the idea of removing the
-         icon/widget from the home screen, but not permanently. [CHAR_LIMIT=30] -->
-    <string name="delete_zone_label_workspace">Remove</string>
-    <!-- Label for trash icon in All Apps. The icon/widget will become completely unavailable on the
-         device. [CHAR_LIMIT=30]-->
-    <string name="delete_zone_label_all_apps">Uninstall</string>
 
     <!-- Label for delete drop target. [CHAR_LIMIT=20] -->
     <string name="delete_target_label">Remove</string>
@@ -132,35 +82,6 @@
     <!-- Label for the info icon. [CHAR_LIMIT=20] -->
     <string name="info_target_label">App info</string>
 
-    <!-- Accessibility: AllApps button -->
-    <string name="accessibility_all_apps_button">Apps</string>
-    <!-- Accessibility: Delete button -->
-    <string name="accessibility_delete_button">Remove</string>
-
-    <!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
-         be uninstalled. [CHAR_LIMIT=30] -->
-    <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
-
-    <!-- URL pointing to help text. If empty, no link to help will be created [DO NOT TRANSLATE] -->
-    <string name="help_url" translatable="false"></string>
-
-    <!--  Strings for the contextual action bar (CAB) in All Apps -->
-    <skip />
-    <!-- Describes the button for uninstalling the currently selected application.
-         Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
-    <string name="cab_menu_delete_app">Uninstall app</string>
-    <!-- Describes the button for getting details/info about currently selected application.
-         Text is not displayed, but provided for accessibility. [CHAR_LIMIT=none] -->
-    <string name="cab_menu_app_info">App details</string>
-    <!-- Appears in the CAB when an app is selected in All Apps or Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_app_selection_text">1 app selected</string>
-    <!-- Appears in the CAB when a widget is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_widget_selection_text">1 widget selected</string>
-    <!-- Appears in the CAB when a folder is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_folder_selection_text">1 folder selected</string>
-    <!-- Appears in the CAB when a shortcut is selected in Customize mode. [CHAR_LIMIT=50] -->
-    <string name="cab_shortcut_selection_text">1 shortcut selected</string>
-
     <!-- Permissions: -->
     <skip />
     <!-- Permission short label -->
@@ -169,11 +90,6 @@
     <string name="permdesc_install_shortcut">Allows an app to add
         shortcuts without user intervention.</string>
     <!-- Permission short label -->
-    <string name="permlab_uninstall_shortcut">uninstall shortcuts</string>
-    <!-- Permission description -->
-    <string name="permdesc_uninstall_shortcut">Allows the app to remove
-        shortcuts without user intervention.</string>
-    <!-- Permission short label -->
     <string name="permlab_read_settings">read Home settings and shortcuts</string>
     <!-- Permission description -->
     <string name="permdesc_read_settings">Allows the app to read the settings and
@@ -196,38 +112,20 @@
     <!-- Text to inform the user that they can't uninstall a system application -->
     <string name="uninstall_system_app_text">This is a system app and can\'t be uninstalled.</string>
 
-    <!-- Title of the Android Dreams (screensaver) module -->
-    <string name="dream_name">Rocket Launcher</string>
-
     <!-- Default folder title -->
     <string name="folder_hint_text">Unnamed Folder</string>
 
     <!-- Accessibility -->
     <skip />
 
-    <!-- The format string for Workspace descriptions [CHAR_LIMIT=none] -->
-    <string name="workspace_description_format">Home screen %1$d</string>
-
     <!-- The format string for default page scroll text [CHAR_LIMIT=none] -->
     <string name="default_scroll_format">Page %1$d of %2$d</string>
     <!-- The format string for Workspace page scroll text [CHAR_LIMIT=none] -->
     <string name="workspace_scroll_format">Home screen %1$d of %2$d</string>
-    <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
-    <string name="apps_customize_apps_scroll_format">Apps page %1$d of %2$d</string>
-    <!-- The format string for AppsCustomize Apps page scroll text [CHAR_LIMIT=none] -->
-    <string name="apps_customize_widgets_scroll_format">Widgets page %1$d of %2$d</string>
 
     <!-- Clings -->
     <!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
     <string name="first_run_cling_title">Welcome</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_description">Make yourself at home.</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_custom_content_hint"></string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_search_bar_hint"></string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=60] -->
-    <string name="first_run_cling_create_screens_hint">Create more screens for apps and folders</string>
     <!-- The title text for the migration cling [CHAR_LIMIT=30] -->
     <string name="migration_cling_title">Copy your app icons</string>
     <!-- The description of what migration does [CHAR_LIMIT=70] -->
@@ -236,25 +134,12 @@
     <string name="migration_cling_copy_apps">COPY ICONS</string>
     <!-- The description of the button to use the default launcher layout [CHAR_LIMIT=30] -->
     <string name="migration_cling_use_default">START FRESH</string>
-    <!-- The title text for the workspace cling [CHAR_LIMIT=30] -->
-    <string name="workspace_cling_title">Organize your space</string>
-    <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
-    <string name="workspace_cling_move_item">Touch &amp; hold background to manage wallpaper, widgets and settings.</string>
     <!-- The title text for workspace longpress action [CHAR_LIMIT=40] -->
     <string name="workspace_cling_longpress_title">Wallpapers, widgets, &amp; settings</string>
     <!-- The description of how to use the workspace [CHAR_LIMIT=70] -->
     <string name="workspace_cling_longpress_description">Touch &amp; hold background to customize</string>
     <!-- The description of the button to dismiss the cling [CHAR_LIMIT=30] -->
     <string name="workspace_cling_longpress_dismiss">GOT IT</string>
-    <!-- The title text for the Folder cling [CHAR_LIMIT=30] -->
-    <string name="folder_cling_title">Here\'s a folder</string>
-    <!-- The description of how to create a folder [CHAR_LIMIT=70] -->
-    <string name="folder_cling_create_folder">To create one like this, touch &amp; hold an app, then move it over another.</string>
-    <!-- The text on the button to dismiss a cling [CHAR_LIMIT=30] -->
-    <string name="cling_dismiss">OK</string>
-    <!-- Error message on dummy custom cling layout [DO NOT TRANSLATE] -->
-    <string name="dummy_custom_cling_error_message">Error: custom workspace layout passed in but custom cling was not overwritten</string>
-    <add-resource type="string" name="default_folder_name" />
 
     <!-- Folder accessibility -->
     <!-- The format string for when a folder is opened, speaks the dimensions -->
@@ -281,19 +166,13 @@
     <!-- Text for settings button -->
     <string name="settings_button_text">Settings</string>
 
-    <!-- Label on an icon that references an uninstalled package, that is going to be installed at some point. [CHAR_LIMIT=15] -->
-    <string name="package_state_enqueued">Waiting</string>
-    <!-- Label on an icon that references an uninstalled package, that is currently being downloaded. [CHAR_LIMIT=15] -->
-    <string name="package_state_downloading">Downloading</string>
-    <!-- Label on an icon that references an uninstalled package, that is currently being installed. [CHAR_LIMIT=15] -->
-    <string name="package_state_installing">Installing</string>
+    <!-- Strings for settings -->
+    <!-- Title for Allow Rotation setting. [CHAR LIMIT=50] -->
+    <string name="allow_rotation_title">Allow rotation</string>
+
     <!-- Label on an icon that references an uninstalled package, for which we have no information about when it might be installed. [CHAR_LIMIT=15] -->
     <string name="package_state_unknown">Unknown</string>
-    <!-- Label on an icon that references an uninstalled package, for which restore from market has failed. [CHAR_LIMIT=15] -->
-    <string name="package_state_error">Not restored</string>
 
-    <!-- Button for abandoned promises dialog, that removes all abandoned promise icons. -->
-    <string name="abandoned_clean_all">Remove All</string>
     <!-- Button for abandoned promises dialog, to removes this abandoned promise icon. -->
     <string name="abandoned_clean_this">Remove</string>
     <!-- Button for abandoned promise dialog, to search in the market for the missing package. -->
@@ -305,4 +184,78 @@
     <string name="abandoned_promise_explanation">The app for this icon isn\'t installed.
         You can remove it, or search for the app and install it manually.
     </string>
+
+<!-- Strings for accessibility actions -->
+    <!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] -->
+    <string name="action_add_to_workspace">Add to Home screen</string>
+
+    <!-- Accessibility action to move item to the current location. [CHAR_LIMIT=30] -->
+    <string name="action_move_here">Move item here</string>
+
+    <!-- Accessibility confirmation for item added to workspace. -->
+    <string name="item_added_to_workspace">Item added to home screen</string>
+
+    <!-- Accessibility confirmation for item removed. -->
+    <string name="item_removed">Item removed</string>
+
+    <!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] -->
+    <string name="action_move">Move item</string>
+
+    <!-- Accessibility description to move item to empty cell. -->
+    <string name="move_to_empty_cell">Move to row <xliff:g id="number" example="1">%1$s</xliff:g> column <xliff:g id="number" example="1">%2$s</xliff:g></string>
+
+    <!-- Accessibility description to move item inside a folder. -->
+    <string name="move_to_position">Move to position <xliff:g id="number" example="1">%1$s</xliff:g></string>
+
+    <!-- Accessibility description to move item to the hotseat. -->
+    <string name="move_to_hotseat_position">Move to favorites position <xliff:g id="number" example="1">%1$s</xliff:g></string>
+
+    <!-- Accessibility confirmation for item move. -->
+    <string name="item_moved">Item moved</string>
+
+    <!-- Accessibility description to move item into an existing folder. -->
+    <string name="add_to_folder">Add to folder: <xliff:g id="name" example="Games">%1$s</xliff:g></string>
+
+    <!-- Accessibility description to move item into an existing folder containing an app. -->
+    <string name="add_to_folder_with_app">Add to folder with <xliff:g id="name" example="Messenger">%1$s</xliff:g></string>
+
+    <!-- Accessibility confirmation for item added to folder. -->
+    <string name="added_to_folder">Item added to folder</string>
+
+    <!-- Accessibility description to create folder with another item. -->
+    <string name="create_folder_with">Create folder with: <xliff:g id="name" example="Game">%1$s</xliff:g></string>
+
+    <!-- Accessibility confirmation for folder created. -->
+    <string name="folder_created">Folder created</string>
+
+    <!-- Accessibility action to move an item from folder to workspace. [CHAR_LIMIT=30] -->
+    <string name="action_move_to_workspace">Move to Home screen</string>
+
+    <!-- Accessibility action to move an homescreen to the left. [CHAR_LIMIT=30] -->
+    <string name="action_move_screen_left">Move screen to left</string>
+
+    <!-- Accessibility action to move an homescreen to the right. [CHAR_LIMIT=30] -->
+    <string name="action_move_screen_right">Move screen to right</string>
+
+    <!-- Accessibility confirmation when a screen was moved. -->
+    <string name="screen_moved">Screen moved</string>
+
+    <!-- Accessibility action to resize a widget. [CHAR_LIMIT=30] -->
+    <string name="action_resize">Resize</string>
+
+    <!-- Accessibility action to increase width of a widget. [CHAR_LIMIT=30] -->
+    <string name="action_increase_width">Increase width</string>
+
+    <!-- Accessibility action to increase height of a widget. [CHAR_LIMIT=30] -->
+    <string name="action_increase_height">Increase height</string>
+
+    <!-- Accessibility action to decrease width of a widget. [CHAR_LIMIT=30] -->
+    <string name="action_decrease_width">Decrease width</string>
+
+    <!-- Accessibility action to decrease height of a widget. [CHAR_LIMIT=30] -->
+    <string name="action_decrease_height">Decrease height</string>
+
+    <!-- Accessibility confirmation for widget resize. -->
+    <string name="widget_resized">Widget resized to width <xliff:g id="number" example="2">%1$s</xliff:g> height <xliff:g id="number" example="1">%2$s</xliff:g></string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 77798f1..7d60cbe 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -18,8 +18,15 @@
 -->
 
 <resources>
+    <style name="Theme.Light.CustomOverscroll" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorEdgeEffect">@color/folder_edge_effect_color</item>
+    </style>
 
-    <style name="WorkspaceIcon">
+    <style name="Theme.Dark.CustomOverscroll" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:colorEdgeEffect">@color/workspace_edge_effect_color</item>
+    </style>
+
+    <style name="Icon">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_gravity">center</item>
@@ -32,11 +39,7 @@
         <item name="android:fontFamily">sans-serif-condensed</item>
     </style>
 
-    <style name="WorkspaceIcon.Portrait"></style>
-
-    <style name="WorkspaceIcon.Landscape"></style>
-
-    <style name="WorkspaceIcon.AppsCustomize">
+    <style name="Icon.AllApps">
         <item name="android:background">@null</item>
         <item name="android:textColor">@color/quantum_panel_text_color</item>
         <item name="android:drawablePadding">@dimen/dynamic_grid_icon_drawable_padding</item>
@@ -44,7 +47,7 @@
         <item name="customShadows">false</item>
     </style>
 
-    <style name="WorkspaceIcon.Folder">
+    <style name="Icon.Folder">
         <item name="android:background">@null</item>
         <item name="android:textColor">@color/quantum_panel_text_color</item>
         <item name="android:shadowRadius">0</item>
@@ -58,7 +61,7 @@
         <item name="android:layout_height">match_parent</item>
     </style>
 
-    <style name="DropTargetButton.Base">
+    <style name="DropTargetButtonBase">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:layout_gravity">center</item>
@@ -76,7 +79,7 @@
         <item name="android:shadowRadius">4.0</item>
     </style>
 
-    <style name="DropTargetButton" parent="DropTargetButton.Base"></style>
+    <style name="DropTargetButton" parent="DropTargetButtonBase" />
 
     <style name="PreloadIcon">
         <item name="background">@drawable/virtual_preload</item>
@@ -90,9 +93,4 @@
         <item name="ringOutset">4dp</item>
     </style>
 
-    <!-- Overridden in device overlays -->
-    <style name="PagedViewWidgetImageView">
-        <item name="android:paddingLeft">@dimen/app_widget_preview_padding_left</item>
-    </style>
-
 </resources>
diff --git a/res/anim/fade_out_fast.xml b/res/xml/app_target_browser.xml
similarity index 64%
copy from res/anim/fade_out_fast.xml
copy to res/xml/app_target_browser.xml
index a061a6c..d7c3ed5 100644
--- a/res/anim/fade_out_fast.xml
+++ b/res/xml/app_target_browser.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,10 +15,9 @@
      limitations under the License.
 -->
 
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
 
-    android:fromAlpha="1.0"
-    android:toAlpha="0.0"
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
+    <favorite launcher:uri="http://www.example.com/" />
 
-    android:duration="@android:integer/config_mediumAnimTime" />
+</resolve>
\ No newline at end of file
diff --git a/res/anim/fade_out_fast.xml b/res/xml/app_target_camera.xml
similarity index 64%
rename from res/anim/fade_out_fast.xml
rename to res/xml/app_target_camera.xml
index a061a6c..f65a2b1 100644
--- a/res/anim/fade_out_fast.xml
+++ b/res/xml/app_target_camera.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,10 +15,9 @@
      limitations under the License.
 -->
 
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-    android:interpolator="@android:anim/accelerate_interpolator"
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
 
-    android:fromAlpha="1.0"
-    android:toAlpha="0.0"
+    <favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
+    <favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
 
-    android:duration="@android:integer/config_mediumAnimTime" />
+</resolve>
\ No newline at end of file
diff --git a/res/layout/application.xml b/res/xml/app_target_email.xml
similarity index 65%
copy from res/layout/application.xml
copy to res/xml/app_target_email.xml
index c21dea0..44f0a40 100644
--- a/res/layout/application.xml
+++ b/res/xml/app_target_email.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,6 +15,9 @@
      limitations under the License.
 -->
 
-<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon"
-   android:focusable="true" />
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
+    <favorite launcher:uri="mailto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/values-sw340dp-port/config.xml b/res/xml/app_target_gallery.xml
similarity index 63%
copy from res/values-sw340dp-port/config.xml
copy to res/xml/app_target_gallery.xml
index 5f71077..c9d3492 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/xml/app_target_gallery.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,5 +15,9 @@
      limitations under the License.
 -->
 
-<resources>
-</resources>
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
+    <favorite launcher:uri="#Intent;type=images/*;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_messenger.xml b/res/xml/app_target_messenger.xml
new file mode 100644
index 0000000..278eb5c
--- /dev/null
+++ b/res/xml/app_target_messenger.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
+    <favorite launcher:uri="sms:" />
+    <favorite launcher:uri="smsto:" />
+    <favorite launcher:uri="mms:" />
+    <favorite launcher:uri="mmsto:" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/values-sw340dp-port/config.xml b/res/xml/app_target_phone.xml
similarity index 62%
copy from res/values-sw340dp-port/config.xml
copy to res/xml/app_target_phone.xml
index 5f71077..5d6ca31 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/xml/app_target_phone.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,5 +15,10 @@
      limitations under the License.
 -->
 
-<resources>
-</resources>
+<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
+
+    <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
+    <favorite launcher:uri="tel:123" />
+    <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
+
+</resolve>
\ No newline at end of file
diff --git a/res/values-sw340dp-port/config.xml b/res/xml/launcher_preferences.xml
similarity index 62%
copy from res/values-sw340dp-port/config.xml
copy to res/xml/launcher_preferences.xml
index 5f71077..624d9eb 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/res/xml/launcher_preferences.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2015 Google Inc.
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,5 +14,13 @@
      limitations under the License.
 -->
 
-<resources>
-</resources>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <SwitchPreference
+            android:key="pref_allowRotation"
+            android:title="@string/allow_rotation_title"
+            android:defaultValue="@bool/allow_rotation"
+            android:persistent="true"
+    />
+
+</PreferenceScreen>
diff --git a/res/xml/update_workspace.xml b/res/xml/update_workspace.xml
deleted file mode 100644
index 38442b9..0000000
--- a/res/xml/update_workspace.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
-    <!-- Update the db with new hotseat items.  Note that we reference the browser's original
-         package name. -->
-    <!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
-    <favorite
-        launcher:packageName="com.android.dialer"
-        launcher:className="com.android.dialer.DialtactsActivity"
-        launcher:container="-101"
-        launcher:screen="0"
-        launcher:x="0"
-        launcher:y="0" />
-    <favorite
-        launcher:packageName="com.android.contacts"
-        launcher:className="com.android.contacts.activities.PeopleActivity"
-        launcher:container="-101"
-        launcher:screen="1"
-        launcher:x="1"
-        launcher:y="0" />
-    <favorite
-        launcher:packageName="com.android.mms"
-        launcher:className="com.android.mms.ui.ConversationList"
-        launcher:container="-101"
-        launcher:screen="3"
-        launcher:x="3"
-        launcher:y="0" />
-    <favorite
-        launcher:packageName="com.android.browser"
-        launcher:className="com.android.browser.BrowserActivity"
-        launcher:container="-101"
-        launcher:screen="4"
-        launcher:x="4"
-        launcher:y="0" />
-</favorites>
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 72c6693..3b25dca 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -24,6 +24,7 @@
 import com.android.launcher3.compat.UserHandleCompat;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 
 
@@ -98,14 +99,14 @@
                 user);
 
         for (LauncherActivityInfoCompat info : matches) {
-            add(new AppInfo(context, info, user, mIconCache, null));
+            add(new AppInfo(context, info, user, mIconCache));
         }
     }
 
     /**
      * Remove the apps for the given apk identified by packageName.
      */
-    public void removePackage(String packageName, UserHandleCompat user, boolean clearCache) {
+    public void removePackage(String packageName, UserHandleCompat user) {
         final List<AppInfo> data = this.data;
         for (int i = data.size() - 1; i >= 0; i--) {
             AppInfo info = data.get(i);
@@ -115,8 +116,15 @@
                 data.remove(i);
             }
         }
-        if (clearCache) {
-            mIconCache.remove(packageName, user);
+    }
+
+    public void updateIconsAndLabels(HashSet<String> packages, UserHandleCompat user,
+            ArrayList<AppInfo> outUpdates) {
+        for (AppInfo info : data) {
+            if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) {
+                mIconCache.updateTitleAndIcon(info);
+                outUpdates.add(info);
+            }
         }
     }
 
@@ -137,7 +145,6 @@
                         && packageName.equals(component.getPackageName())) {
                     if (!findActivity(matches, component)) {
                         removed.add(applicationInfo);
-                        mIconCache.remove(component, user);
                         data.remove(i);
                     }
                 }
@@ -150,10 +157,9 @@
                         info.getComponentName().getPackageName(), user,
                         info.getComponentName().getClassName());
                 if (applicationInfo == null) {
-                    add(new AppInfo(context, info, user, mIconCache, null));
+                    add(new AppInfo(context, info, user, mIconCache));
                 } else {
-                    mIconCache.remove(applicationInfo.componentName, user);
-                    mIconCache.getTitleAndIcon(applicationInfo, info, null);
+                    mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */);
                     modified.add(applicationInfo);
                 }
             }
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index a66bac0..c95d558 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -19,19 +19,16 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.util.Log;
 
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
-import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 
 /**
  * Represents an app in AllAppsView.
@@ -42,19 +39,24 @@
     /**
      * The intent used to start the application.
      */
-    Intent intent;
+    public Intent intent;
 
     /**
      * A bitmap version of the application icon.
      */
-    Bitmap iconBitmap;
+    public Bitmap iconBitmap;
+
+    /**
+     * Indicates whether we're using a low res icon
+     */
+    boolean usingLowResIcon;
 
     /**
      * The time at which the app was first installed.
      */
     long firstInstallTime;
 
-    ComponentName componentName;
+    public ComponentName componentName;
 
     static final int DOWNLOADED_FLAG = 1;
     static final int UPDATED_SYSTEM_APP_FLAG = 2;
@@ -77,13 +79,13 @@
      * Must not hold the Context.
      */
     public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandleCompat user,
-            IconCache iconCache, HashMap<Object, CharSequence> labelCache) {
+            IconCache iconCache) {
         this.componentName = info.getComponentName();
         this.container = ItemInfo.NO_ID;
 
         flags = initFlags(info);
         firstInstallTime = info.getFirstInstallTime();
-        iconCache.getTitleAndIcon(this, info, labelCache);
+        iconCache.getTitleAndIcon(this, info, true /* useLowResIcon */);
         intent = makeLaunchIntent(context, info, user);
         this.user = user;
     }
@@ -104,7 +106,7 @@
     public AppInfo(AppInfo info) {
         super(info);
         componentName = info.componentName;
-        title = info.title.toString();
+        title = Utilities.trim(info.title);
         intent = new Intent(info.intent);
         flags = info.flags;
         firstInstallTime = info.firstInstallTime;
@@ -113,19 +115,22 @@
 
     @Override
     public String toString() {
-        return "ApplicationInfo(title=" + title.toString() + " id=" + this.id
+        return "ApplicationInfo(title=" + title + " id=" + this.id
                 + " type=" + this.itemType + " container=" + this.container
                 + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
                 + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
                 + " user=" + user + ")";
     }
 
+    /**
+     * Helper method used for debugging.
+     */
     public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) {
         Log.d(tag, label + " size=" + list.size());
         for (AppInfo info: list) {
-            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap="
-                    + info.iconBitmap + " firstInstallTime="
-                    + info.firstInstallTime);
+            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap=" + info.iconBitmap 
+                    + " firstInstallTime=" + info.firstInstallTime
+                    + " componentName=" + info.componentName.getPackageName());
         }
     }
 
@@ -133,6 +138,10 @@
         return new ShortcutInfo(this);
     }
 
+    public ComponentKey toComponentKey() {
+        return new ComponentKey(componentName, user);
+    }
+
     public static Intent makeLaunchIntent(Context context, LauncherActivityInfoCompat info,
             UserHandleCompat user) {
         long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index f57f4d0..ea7c221 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -8,30 +8,43 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.view.Gravity;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 public class AppWidgetResizeFrame extends FrameLayout {
-    private LauncherAppWidgetHostView mWidgetView;
-    private CellLayout mCellLayout;
-    private DragLayer mDragLayer;
-    private ImageView mLeftHandle;
-    private ImageView mRightHandle;
-    private ImageView mTopHandle;
-    private ImageView mBottomHandle;
+    private static final int SNAP_DURATION = 150;
+    private static final float DIMMED_HANDLE_ALPHA = 0f;
+    private static final float RESIZE_THRESHOLD = 0.66f;
+
+    private static Rect sTmpRect = new Rect();
+
+    private final Launcher mLauncher;
+    private final LauncherAppWidgetHostView mWidgetView;
+    private final CellLayout mCellLayout;
+    private final DragLayer mDragLayer;
+
+    private final ImageView mLeftHandle;
+    private final ImageView mRightHandle;
+    private final ImageView mTopHandle;
+    private final ImageView mBottomHandle;
+
+    private final Rect mWidgetPadding;
+
+    private final int mBackgroundPadding;
+    private final int mTouchTargetWidth;
+
+    private final int[] mDirectionVector = new int[2];
+    private final int[] mLastDirectionVector = new int[2];
+    private final int[] mTmpPt = new int[2];
 
     private boolean mLeftBorderActive;
     private boolean mRightBorderActive;
     private boolean mTopBorderActive;
     private boolean mBottomBorderActive;
 
-    private int mWidgetPaddingLeft;
-    private int mWidgetPaddingRight;
-    private int mWidgetPaddingTop;
-    private int mWidgetPaddingBottom;
-
     private int mBaselineWidth;
     private int mBaselineHeight;
     private int mBaselineX;
@@ -47,30 +60,9 @@
     private int mDeltaXAddOn;
     private int mDeltaYAddOn;
 
-    private int mBackgroundPadding;
-    private int mTouchTargetWidth;
-
     private int mTopTouchRegionAdjustment = 0;
     private int mBottomTouchRegionAdjustment = 0;
 
-    int[] mDirectionVector = new int[2];
-    int[] mLastDirectionVector = new int[2];
-    int[] mTmpPt = new int[2];
-
-    final int SNAP_DURATION = 150;
-    final int BACKGROUND_PADDING = 24;
-    final float DIMMED_HANDLE_ALPHA = 0f;
-    final float RESIZE_THRESHOLD = 0.66f;
-
-    private static Rect mTmpRect = new Rect();
-
-    public static final int LEFT = 0;
-    public static final int TOP = 1;
-    public static final int RIGHT = 2;
-    public static final int BOTTOM = 3;
-
-    private Launcher mLauncher;
-
     public AppWidgetResizeFrame(Context context,
             LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
 
@@ -78,48 +70,56 @@
         mLauncher = (Launcher) context;
         mCellLayout = cellLayout;
         mWidgetView = widgetView;
-        mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+        LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo)
+                widgetView.getAppWidgetInfo();
+        mResizeMode = info.resizeMode;
         mDragLayer = dragLayer;
 
-        final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
-        int[] result = Launcher.getMinSpanForWidget(mLauncher, info);
-        mMinHSpan = result[0];
-        mMinVSpan = result[1];
+        mMinHSpan = info.getMinSpanX(mLauncher);
+        mMinVSpan = info.getMinSpanY(mLauncher);
 
-        setBackgroundResource(R.drawable.widget_resize_frame_holo);
+        setBackgroundResource(R.drawable.widget_resize_shadow);
+        setForeground(getResources().getDrawable(R.drawable.widget_resize_frame));
         setPadding(0, 0, 0, 0);
 
+        final int handleMargin = getResources().getDimensionPixelSize(R.dimen.widget_handle_margin);
         LayoutParams lp;
         mLeftHandle = new ImageView(context);
-        mLeftHandle.setImageResource(R.drawable.widget_resize_handle_left);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mLeftHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.LEFT | Gravity.CENTER_VERTICAL);
+        lp.leftMargin = handleMargin;
         addView(mLeftHandle, lp);
 
         mRightHandle = new ImageView(context);
-        mRightHandle.setImageResource(R.drawable.widget_resize_handle_right);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mRightHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+        lp.rightMargin = handleMargin;
         addView(mRightHandle, lp);
 
         mTopHandle = new ImageView(context);
-        mTopHandle.setImageResource(R.drawable.widget_resize_handle_top);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mTopHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.CENTER_HORIZONTAL | Gravity.TOP);
+        lp.topMargin = handleMargin;
         addView(mTopHandle, lp);
 
         mBottomHandle = new ImageView(context);
-        mBottomHandle.setImageResource(R.drawable.widget_resize_handle_bottom);
-        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 
+        mBottomHandle.setImageResource(R.drawable.ic_widget_resize_handle);
+        lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
                 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
+        lp.bottomMargin = handleMargin;
         addView(mBottomHandle, lp);
 
-        Rect p = AppWidgetHostView.getDefaultPaddingForWidget(context,
-                widgetView.getAppWidgetInfo().provider, null);
-        mWidgetPaddingLeft = p.left;
-        mWidgetPaddingTop = p.top;
-        mWidgetPaddingRight = p.right;
-        mWidgetPaddingBottom = p.bottom;
+        if (!info.isCustomWidget) {
+            mWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context,
+                    widgetView.getAppWidgetInfo().provider, null);
+        } else {
+            Resources r = context.getResources();
+            int padding = r.getDimensionPixelSize(R.dimen.default_widget_padding);
+            mWidgetPadding = new Rect(padding, padding, padding, padding);
+        }
 
         if (mResizeMode == AppWidgetProviderInfo.RESIZE_HORIZONTAL) {
             mTopHandle.setVisibility(GONE);
@@ -129,8 +129,8 @@
             mRightHandle.setVisibility(GONE);
         }
 
-        final float density = mLauncher.getResources().getDisplayMetrics().density;
-        mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING);
+        mBackgroundPadding = getResources()
+                .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
         mTouchTargetWidth = 2 * mBackgroundPadding;
 
         // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
@@ -335,13 +335,12 @@
 
     static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher,
             int spanX, int spanY) {
-
-        getWidgetSizeRanges(launcher, spanX, spanY, mTmpRect);
-        widgetView.updateAppWidgetSize(null, mTmpRect.left, mTmpRect.top,
-                mTmpRect.right, mTmpRect.bottom);
+        getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect);
+        widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top,
+                sTmpRect.right, sTmpRect.bottom);
     }
 
-    static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
+    public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
         if (rect == null) {
             rect = new Rect();
         }
@@ -396,19 +395,19 @@
 
     public void snapToWidget(boolean animate) {
         final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding - mWidgetPaddingLeft -
-                mWidgetPaddingRight;
-        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding - mWidgetPaddingTop -
-                mWidgetPaddingBottom;
+        int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding
+                - mWidgetPadding.left - mWidgetPadding.right;
+        int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding
+                - mWidgetPadding.top - mWidgetPadding.bottom;
 
         mTmpPt[0] = mWidgetView.getLeft();
         mTmpPt[1] = mWidgetView.getTop();
         mDragLayer.getDescendantCoordRelativeToSelf(mCellLayout.getShortcutsAndWidgets(), mTmpPt);
 
-        int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPaddingLeft;
-        int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPaddingTop;
+        int newX = mTmpPt[0] - mBackgroundPadding + mWidgetPadding.left;
+        int newY = mTmpPt[1] - mBackgroundPadding + mWidgetPadding.top;
 
-        // We need to make sure the frame's touchable regions lie fully within the bounds of the 
+        // We need to make sure the frame's touchable regions lie fully within the bounds of the
         // DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
         // down accordingly to provide a proper touch target.
         if (newY < 0) {
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 880aaf1..5e7a012 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -90,5 +90,10 @@
                 }
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
         }
+
+        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+        if (app != null) {
+            app.reloadWorkspace();
+        }
     }
 }
diff --git a/src/com/android/launcher3/AppsCustomizeCellLayout.java b/src/com/android/launcher3/AppsCustomizeCellLayout.java
deleted file mode 100644
index a50fb68..0000000
--- a/src/com/android/launcher3/AppsCustomizeCellLayout.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.view.View;
-
-public class AppsCustomizeCellLayout extends CellLayout implements Page {
-
-    final FocusIndicatorView mFocusHandlerView;
-
-    public AppsCustomizeCellLayout(Context context) {
-        super(context);
-
-        mFocusHandlerView = new FocusIndicatorView(context);
-        addView(mFocusHandlerView, 0);
-        mFocusHandlerView.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
-        mFocusHandlerView.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
-    }
-
-    @Override
-    public void removeAllViewsOnPage() {
-        removeAllViews();
-        setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    @Override
-    public void removeViewOnPageAt(int index) {
-        removeViewAt(index);
-    }
-
-    @Override
-    public int getPageChildCount() {
-        return getChildCount();
-    }
-
-    @Override
-    public View getChildOnPageAt(int i) {
-        return getChildAt(i);
-    }
-
-    @Override
-    public int indexOfChildOnPage(View v) {
-        return indexOfChild(v);
-    }
-
-    /**
-     * Clears all the key listeners for the individual icons.
-     */
-    public void resetChildrenOnKeyListeners() {
-        ShortcutAndWidgetContainer children = getShortcutsAndWidgets();
-        int childCount = children.getChildCount();
-        for (int j = 0; j < childCount; ++j) {
-            children.getChildAt(j).setOnKeyListener(null);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
deleted file mode 100644
index c8187f0..0000000
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ /dev/null
@@ -1,1567 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.GridLayout;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A simple callback interface which also provides the results of the task.
- */
-interface AsyncTaskCallback {
-    void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data);
-}
-
-/**
- * The data needed to perform either of the custom AsyncTasks.
- */
-class AsyncTaskPageData {
-    enum Type {
-        LoadWidgetPreviewData
-    }
-
-    AsyncTaskPageData(int p, ArrayList<Object> l, int cw, int ch, AsyncTaskCallback bgR,
-            AsyncTaskCallback postR, WidgetPreviewLoader w) {
-        page = p;
-        items = l;
-        generatedImages = new ArrayList<Bitmap>();
-        maxImageWidth = cw;
-        maxImageHeight = ch;
-        doInBackgroundCallback = bgR;
-        postExecuteCallback = postR;
-        widgetPreviewLoader = w;
-    }
-    void cleanup(boolean cancelled) {
-        // Clean up any references to source/generated bitmaps
-        if (generatedImages != null) {
-            if (cancelled) {
-                for (int i = 0; i < generatedImages.size(); i++) {
-                    widgetPreviewLoader.recycleBitmap(items.get(i), generatedImages.get(i));
-                }
-            }
-            generatedImages.clear();
-        }
-    }
-    int page;
-    ArrayList<Object> items;
-    ArrayList<Bitmap> sourceImages;
-    ArrayList<Bitmap> generatedImages;
-    int maxImageWidth;
-    int maxImageHeight;
-    AsyncTaskCallback doInBackgroundCallback;
-    AsyncTaskCallback postExecuteCallback;
-    WidgetPreviewLoader widgetPreviewLoader;
-}
-
-/**
- * A generic template for an async task used in AppsCustomize.
- */
-class AppsCustomizeAsyncTask extends AsyncTask<AsyncTaskPageData, Void, AsyncTaskPageData> {
-    AppsCustomizeAsyncTask(int p, AsyncTaskPageData.Type ty) {
-        page = p;
-        threadPriority = Process.THREAD_PRIORITY_DEFAULT;
-        dataType = ty;
-    }
-    @Override
-    protected AsyncTaskPageData doInBackground(AsyncTaskPageData... params) {
-        if (params.length != 1) return null;
-        // Load each of the widget previews in the background
-        params[0].doInBackgroundCallback.run(this, params[0]);
-        return params[0];
-    }
-    @Override
-    protected void onPostExecute(AsyncTaskPageData result) {
-        // All the widget previews are loaded, so we can just callback to inflate the page
-        result.postExecuteCallback.run(this, result);
-    }
-
-    void setThreadPriority(int p) {
-        threadPriority = p;
-    }
-    void syncThreadPriority() {
-        Process.setThreadPriority(threadPriority);
-    }
-
-    // The page that this async task is associated with
-    AsyncTaskPageData.Type dataType;
-    int page;
-    int threadPriority;
-}
-
-/**
- * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
- */
-public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
-        View.OnClickListener, View.OnKeyListener, DragSource,
-        PagedViewWidget.ShortPressListener, LauncherTransitionable {
-    static final String TAG = "AppsCustomizePagedView";
-
-    private static Rect sTmpRect = new Rect();
-
-    /**
-     * The different content types that this paged view can show.
-     */
-    public enum ContentType {
-        Applications,
-        Widgets
-    }
-    private ContentType mContentType = ContentType.Applications;
-
-    // Refs
-    private Launcher mLauncher;
-    private DragController mDragController;
-    private final LayoutInflater mLayoutInflater;
-    private final PackageManager mPackageManager;
-
-    // Save and Restore
-    private int mSaveInstanceStateItemIndex = -1;
-
-    // Content
-    private ArrayList<AppInfo> mApps;
-    private ArrayList<Object> mWidgets;
-
-    // Caching
-    private IconCache mIconCache;
-
-    // Dimens
-    private int mContentWidth, mContentHeight;
-    private int mWidgetCountX, mWidgetCountY;
-    private PagedViewCellLayout mWidgetSpacingLayout;
-    private int mNumAppsPages;
-    private int mNumWidgetPages;
-    private Rect mAllAppsPadding = new Rect();
-
-    // Previews & outlines
-    ArrayList<AppsCustomizeAsyncTask> mRunningTasks;
-    private static final int sPageSleepDelay = 200;
-
-    private Runnable mInflateWidgetRunnable = null;
-    private Runnable mBindWidgetRunnable = null;
-    static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
-    static final int WIDGET_PRELOAD_PENDING = 0;
-    static final int WIDGET_BOUND = 1;
-    static final int WIDGET_INFLATED = 2;
-    int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
-    int mWidgetLoadingId = -1;
-    PendingAddWidgetInfo mCreateWidgetInfo = null;
-    private boolean mDraggingWidget = false;
-    boolean mPageBackgroundsVisible = true;
-
-    private Toast mWidgetInstructionToast;
-
-    // Deferral of loading widget previews during launcher transitions
-    private boolean mInTransition;
-    private ArrayList<AsyncTaskPageData> mDeferredSyncWidgetPageItems =
-        new ArrayList<AsyncTaskPageData>();
-    private ArrayList<Runnable> mDeferredPrepareLoadWidgetPreviewsTasks =
-        new ArrayList<Runnable>();
-
-    WidgetPreviewLoader mWidgetPreviewLoader;
-
-    private boolean mInBulkBind;
-    private boolean mNeedToUpdatePageCountsAndInvalidateData;
-
-    public AppsCustomizePagedView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mLayoutInflater = LayoutInflater.from(context);
-        mPackageManager = context.getPackageManager();
-        mApps = new ArrayList<AppInfo>();
-        mWidgets = new ArrayList<Object>();
-        mIconCache = (LauncherAppState.getInstance()).getIconCache();
-        mRunningTasks = new ArrayList<AppsCustomizeAsyncTask>();
-
-        // Save the default widget preview background
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
-        mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
-        mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
-        a.recycle();
-        mWidgetSpacingLayout = new PagedViewCellLayout(getContext());
-
-        // The padding on the non-matched dimension for the default widget preview icons
-        // (top + bottom)
-        mFadeInAdjacentScreens = false;
-
-        // Unless otherwise specified this view is important for accessibility.
-        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-        setSinglePageInViewport();
-    }
-
-    @Override
-    protected void init() {
-        super.init();
-        mCenterPagesVertically = false;
-
-        Context context = getContext();
-        Resources r = context.getResources();
-        setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
-    }
-
-    public void onFinishInflate() {
-        super.onFinishInflate();
-
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        setPadding(grid.edgeMarginPx, 2 * grid.edgeMarginPx,
-                grid.edgeMarginPx, 2 * grid.edgeMarginPx);
-    }
-
-    void setAllAppsPadding(Rect r) {
-        mAllAppsPadding.set(r);
-    }
-
-    void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
-        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
-    }
-
-    WidgetPreviewLoader getWidgetPreviewLoader() {
-        if (mWidgetPreviewLoader == null) {
-            mWidgetPreviewLoader = new WidgetPreviewLoader(mLauncher);
-        }
-        return mWidgetPreviewLoader;
-    }
-
-    /** Returns the item index of the center item on this page so that we can restore to this
-     *  item index when we rotate. */
-    private int getMiddleComponentIndexOnCurrentPage() {
-        int i = -1;
-        if (getPageCount() > 0) {
-            int currentPage = getCurrentPage();
-            if (mContentType == ContentType.Applications) {
-                AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(currentPage);
-                ShortcutAndWidgetContainer childrenLayout = layout.getShortcutsAndWidgets();
-                int numItemsPerPage = mCellCountX * mCellCountY;
-                int childCount = childrenLayout.getChildCount();
-                if (childCount > 0) {
-                    i = (currentPage * numItemsPerPage) + (childCount / 2);
-                }
-            } else if (mContentType == ContentType.Widgets) {
-                int numApps = mApps.size();
-                PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
-                int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-                int childCount = layout.getChildCount();
-                if (childCount > 0) {
-                    i = numApps +
-                        (currentPage * numItemsPerPage) + (childCount / 2);
-                }
-            } else {
-                throw new RuntimeException("Invalid ContentType");
-            }
-        }
-        return i;
-    }
-
-    /** Get the index of the item to restore to if we need to restore the current page. */
-    int getSaveInstanceStateIndex() {
-        if (mSaveInstanceStateItemIndex == -1) {
-            mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
-        }
-        return mSaveInstanceStateItemIndex;
-    }
-
-    /** Returns the page in the current orientation which is expected to contain the specified
-     *  item index. */
-    int getPageForComponent(int index) {
-        if (index < 0) return 0;
-
-        if (index < mApps.size()) {
-            int numItemsPerPage = mCellCountX * mCellCountY;
-            return (index / numItemsPerPage);
-        } else {
-            int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-            return (index - mApps.size()) / numItemsPerPage;
-        }
-    }
-
-    /** Restores the page for an item at the specified index */
-    void restorePageForIndex(int index) {
-        if (index < 0) return;
-        mSaveInstanceStateItemIndex = index;
-    }
-
-    private void updatePageCounts() {
-        mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
-                (float) (mWidgetCountX * mWidgetCountY));
-        mNumAppsPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
-    }
-
-    protected void onDataReady(int width, int height) {
-        // Now that the data is ready, we can calculate the content width, the number of cells to
-        // use for each page
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        mCellCountX = (int) grid.allAppsNumCols;
-        mCellCountY = (int) grid.allAppsNumRows;
-        updatePageCounts();
-
-        // Force a measure to update recalculate the gaps
-        mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-        mContentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-        int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
-        int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-        mWidgetSpacingLayout.measure(widthSpec, heightSpec);
-
-        final boolean hostIsTransitioning = getTabHost().isInTransition();
-        int page = getPageForComponent(mSaveInstanceStateItemIndex);
-        invalidatePageData(Math.max(0, page), hostIsTransitioning);
-    }
-
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        if (!isDataReady()) {
-            if ((LauncherAppState.isDisableAllApps() || !mApps.isEmpty()) && !mWidgets.isEmpty()) {
-                post(new Runnable() {
-                    // This code triggers requestLayout so must be posted outside of the
-                    // layout pass.
-                    public void run() {
-                        if (Utilities.isViewAttachedToWindow(AppsCustomizePagedView.this)) {
-                            setDataIsReady();
-                            onDataReady(getMeasuredWidth(), getMeasuredHeight());
-                        }
-                    }
-                });
-            }
-        }
-    }
-
-    public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
-        // Get the list of widgets and shortcuts
-        mWidgets.clear();
-        for (Object o : widgetsAndShortcuts) {
-            if (o instanceof AppWidgetProviderInfo) {
-                AppWidgetProviderInfo widget = (AppWidgetProviderInfo) o;
-                if (!app.shouldShowAppOrWidgetProvider(widget.provider)) {
-                    continue;
-                }
-                if (widget.minWidth > 0 && widget.minHeight > 0) {
-                    // Ensure that all widgets we show can be added on a workspace of this size
-                    int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
-                    int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
-                    int minSpanX = Math.min(spanXY[0], minSpanXY[0]);
-                    int minSpanY = Math.min(spanXY[1], minSpanXY[1]);
-                    if (minSpanX <= (int) grid.numColumns &&
-                        minSpanY <= (int) grid.numRows) {
-                        mWidgets.add(widget);
-                    } else {
-                        Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" +
-                              widget.minWidth + ", " + widget.minHeight + ")");
-                    }
-                } else {
-                    Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
-                          widget.minWidth + ", " + widget.minHeight + ")");
-                }
-            } else {
-                // just add shortcuts
-                mWidgets.add(o);
-            }
-        }
-        updatePageCountsAndInvalidateData();
-    }
-
-    public void setBulkBind(boolean bulkBind) {
-        if (bulkBind) {
-            mInBulkBind = true;
-        } else {
-            mInBulkBind = false;
-            if (mNeedToUpdatePageCountsAndInvalidateData) {
-                updatePageCountsAndInvalidateData();
-            }
-        }
-    }
-
-    private void updatePageCountsAndInvalidateData() {
-        if (mInBulkBind) {
-            mNeedToUpdatePageCountsAndInvalidateData = true;
-        } else {
-            updatePageCounts();
-            invalidateOnDataChange();
-            mNeedToUpdatePageCountsAndInvalidateData = false;
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        // When we have exited all apps or are in transition, disregard clicks
-        if (!mLauncher.isAllAppsVisible()
-                || mLauncher.getWorkspace().isSwitchingState()
-                || !(v instanceof PagedViewWidget)) return;
-
-        // Let the user know that they have to long press to add a widget
-        if (mWidgetInstructionToast != null) {
-            mWidgetInstructionToast.cancel();
-        }
-        mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
-            Toast.LENGTH_SHORT);
-        mWidgetInstructionToast.show();
-
-        // Create a little animation to show that the widget can move
-        float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
-        final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
-        AnimatorSet bounce = LauncherAnimUtils.createAnimatorSet();
-        ValueAnimator tyuAnim = LauncherAnimUtils.ofFloat(p, "translationY", offsetY);
-        tyuAnim.setDuration(125);
-        ValueAnimator tydAnim = LauncherAnimUtils.ofFloat(p, "translationY", 0f);
-        tydAnim.setDuration(100);
-        bounce.play(tyuAnim).before(tydAnim);
-        bounce.setInterpolator(new AccelerateInterpolator());
-        bounce.start();
-    }
-
-    public boolean onKey(View v, int keyCode, KeyEvent event) {
-        return FocusHelper.handleAppsCustomizeKeyEvent(v,  keyCode, event);
-    }
-
-    /*
-     * PagedViewWithDraggableItems implementation
-     */
-    @Override
-    protected void determineDraggingStart(android.view.MotionEvent ev) {
-        // Disable dragging by pulling an app down for now.
-    }
-
-    private void beginDraggingApplication(View v) {
-        mLauncher.getWorkspace().beginDragShared(v, this);
-    }
-
-    static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
-        Bundle options = null;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect);
-            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
-                    info.componentName, null);
-
-            float density = launcher.getResources().getDisplayMetrics().density;
-            int xPaddingDips = (int) ((padding.left + padding.right) / density);
-            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
-
-            options = new Bundle();
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                    sTmpRect.left - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                    sTmpRect.top - yPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                    sTmpRect.right - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                    sTmpRect.bottom - yPaddingDips);
-        }
-        return options;
-    }
-
-    private void preloadWidget(final PendingAddWidgetInfo info) {
-        final AppWidgetProviderInfo pInfo = info.info;
-        final Bundle options = getDefaultOptionsForWidget(mLauncher, info);
-
-        if (pInfo.configure != null) {
-            info.bindOptions = options;
-            return;
-        }
-
-        mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
-        mBindWidgetRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
-                if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
-                        mWidgetLoadingId, pInfo, options)) {
-                    mWidgetCleanupState = WIDGET_BOUND;
-                }
-            }
-        };
-        post(mBindWidgetRunnable);
-
-        mInflateWidgetRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if (mWidgetCleanupState != WIDGET_BOUND) {
-                    return;
-                }
-                AppWidgetHostView hostView = mLauncher.
-                        getAppWidgetHost().createView(getContext(), mWidgetLoadingId, pInfo);
-                info.boundWidget = hostView;
-                mWidgetCleanupState = WIDGET_INFLATED;
-                hostView.setVisibility(INVISIBLE);
-                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info.spanX,
-                        info.spanY, info, false);
-
-                // We want the first widget layout to be the correct size. This will be important
-                // for width size reporting to the AppWidgetManager.
-                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
-                        unScaledSize[1]);
-                lp.x = lp.y = 0;
-                lp.customPosition = true;
-                hostView.setLayoutParams(lp);
-                mLauncher.getDragLayer().addView(hostView);
-            }
-        };
-        post(mInflateWidgetRunnable);
-    }
-
-    @Override
-    public void onShortPress(View v) {
-        // We are anticipating a long press, and we use this time to load bind and instantiate
-        // the widget. This will need to be cleaned up if it turns out no long press occurs.
-        if (mCreateWidgetInfo != null) {
-            // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
-            cleanupWidgetPreloading(false);
-        }
-        mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
-        preloadWidget(mCreateWidgetInfo);
-    }
-
-    private void cleanupWidgetPreloading(boolean widgetWasAdded) {
-        if (!widgetWasAdded) {
-            // If the widget was not added, we may need to do further cleanup.
-            PendingAddWidgetInfo info = mCreateWidgetInfo;
-            mCreateWidgetInfo = null;
-
-            if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
-                // We never did any preloading, so just remove pending callbacks to do so
-                removeCallbacks(mBindWidgetRunnable);
-                removeCallbacks(mInflateWidgetRunnable);
-            } else if (mWidgetCleanupState == WIDGET_BOUND) {
-                 // Delete the widget id which was allocated
-                if (mWidgetLoadingId != -1) {
-                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-                }
-
-                // We never got around to inflating the widget, so remove the callback to do so.
-                removeCallbacks(mInflateWidgetRunnable);
-            } else if (mWidgetCleanupState == WIDGET_INFLATED) {
-                // Delete the widget id which was allocated
-                if (mWidgetLoadingId != -1) {
-                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-                }
-
-                // The widget was inflated and added to the DragLayer -- remove it.
-                AppWidgetHostView widget = info.boundWidget;
-                mLauncher.getDragLayer().removeView(widget);
-            }
-        }
-        mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
-        mWidgetLoadingId = -1;
-        mCreateWidgetInfo = null;
-        PagedViewWidget.resetShortPressTarget();
-    }
-
-    @Override
-    public void cleanUpShortPress(View v) {
-        if (!mDraggingWidget) {
-            cleanupWidgetPreloading(false);
-        }
-    }
-
-    private boolean beginDraggingWidget(View v) {
-        mDraggingWidget = true;
-        // Get the widget preview as the drag representation
-        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
-        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
-
-        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
-        // we abort the drag.
-        if (image.getDrawable() == null) {
-            mDraggingWidget = false;
-            return false;
-        }
-
-        // Compose the drag image
-        Bitmap preview;
-        Bitmap outline;
-        float scale = 1f;
-        Point previewPadding = null;
-
-        if (createItemInfo instanceof PendingAddWidgetInfo) {
-            // This can happen in some weird cases involving multi-touch. We can't start dragging
-            // the widget if this is null, so we break out.
-            if (mCreateWidgetInfo == null) {
-                return false;
-            }
-
-            PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo;
-            createItemInfo = createWidgetInfo;
-            int spanX = createItemInfo.spanX;
-            int spanY = createItemInfo.spanY;
-            int[] size = mLauncher.getWorkspace().estimateItemSize(spanX, spanY,
-                    createWidgetInfo, true);
-
-            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
-            float minScale = 1.25f;
-            int maxWidth, maxHeight;
-            maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
-            maxHeight = Math.min((int) (previewDrawable.getIntrinsicHeight() * minScale), size[1]);
-
-            int[] previewSizeBeforeScale = new int[1];
-
-            preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
-                    spanX, spanY, maxWidth, maxHeight, null, previewSizeBeforeScale);
-
-            // Compare the size of the drag preview to the preview in the AppsCustomize tray
-            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
-                    getWidgetPreviewLoader().maxWidthForWidgetPreview(spanX));
-            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
-
-            // The bitmap in the AppsCustomize tray is always the the same size, so there
-            // might be extra pixels around the preview itself - this accounts for that
-            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
-                int padding =
-                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
-                previewPadding = new Point(padding, 0);
-            }
-        } else {
-            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
-            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo);
-            preview = Utilities.createIconBitmap(icon, mLauncher);
-            createItemInfo.spanX = createItemInfo.spanY = 1;
-        }
-
-        // Don't clip alpha values for the drag outline if we're using the default widget preview
-        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
-                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
-
-        // Save the preview for the outline generation, then dim the preview
-        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
-                false);
-
-        // Start the drag
-        mLauncher.lockScreenOrientation();
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
-        mDragController.startDrag(image, preview, this, createItemInfo,
-                DragController.DRAG_ACTION_COPY, previewPadding, scale);
-        outline.recycle();
-        preview.recycle();
-        return true;
-    }
-
-    @Override
-    protected boolean beginDragging(final View v) {
-        if (!super.beginDragging(v)) return false;
-
-        if (v instanceof BubbleTextView) {
-            beginDraggingApplication(v);
-        } else if (v instanceof PagedViewWidget) {
-            if (!beginDraggingWidget(v)) {
-                return false;
-            }
-        }
-
-        // We delay entering spring-loaded mode slightly to make sure the UI
-        // thready is free of any work.
-        postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                // We don't enter spring-loaded mode if the drag has been cancelled
-                if (mLauncher.getDragController().isDragging()) {
-                    // Go into spring loaded mode (must happen before we startDrag())
-                    mLauncher.enterSpringLoadedDragMode();
-                }
-            }
-        }, 150);
-
-        return true;
-    }
-
-    /**
-     * Clean up after dragging.
-     *
-     * @param target where the item was dragged to (can be null if the item was flung)
-     */
-    private void endDragging(View target, boolean isFlingToDelete, boolean success) {
-        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
-                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
-            // Exit spring loaded mode if we have not successfully dropped or have not handled the
-            // drop in Workspace
-            mLauncher.exitSpringLoadedDragModeDelayed(true,
-                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
-            mLauncher.unlockScreenOrientation(false);
-        } else {
-            mLauncher.unlockScreenOrientation(false);
-        }
-    }
-
-    @Override
-    public View getContent() {
-        if (getChildCount() > 0) {
-            return getChildAt(0);
-        }
-        return null;
-    }
-
-    @Override
-    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
-        mInTransition = true;
-        if (toWorkspace) {
-            cancelAllTasks();
-        }
-    }
-
-    @Override
-    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
-    }
-
-    @Override
-    public void onLauncherTransitionStep(Launcher l, float t) {
-    }
-
-    @Override
-    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        mInTransition = false;
-        for (AsyncTaskPageData d : mDeferredSyncWidgetPageItems) {
-            onSyncWidgetPageItems(d, false);
-        }
-        mDeferredSyncWidgetPageItems.clear();
-        for (Runnable r : mDeferredPrepareLoadWidgetPreviewsTasks) {
-            r.run();
-        }
-        mDeferredPrepareLoadWidgetPreviewsTasks.clear();
-        mForceDrawAllChildrenNextFrame = !toWorkspace;
-    }
-
-    @Override
-    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
-            boolean success) {
-        // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
-        if (isFlingToDelete) return;
-
-        endDragging(target, false, success);
-
-        // Display an error message if the drag failed due to there not being enough space on the
-        // target layout we were dropping on.
-        if (!success) {
-            boolean showOutOfSpaceMessage = false;
-            if (target instanceof Workspace) {
-                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
-                Workspace workspace = (Workspace) target;
-                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
-                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
-                if (layout != null) {
-                    layout.calculateSpans(itemInfo);
-                    showOutOfSpaceMessage =
-                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
-                }
-            }
-            if (showOutOfSpaceMessage) {
-                mLauncher.showOutOfSpaceMessage(false);
-            }
-
-            d.deferDragViewCleanupPostAnimation = false;
-        }
-        cleanupWidgetPreloading(success);
-        mDraggingWidget = false;
-    }
-
-    @Override
-    public void onFlingToDeleteCompleted() {
-        // We just dismiss the drag when we fling, so cleanup here
-        endDragging(null, true, true);
-        cleanupWidgetPreloading(false);
-        mDraggingWidget = false;
-    }
-
-    @Override
-    public boolean supportsFlingToDelete() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        return (float) grid.allAppsIconSizePx / grid.iconSizePx;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        cancelAllTasks();
-    }
-
-    @Override
-    public void trimMemory() {
-        super.trimMemory();
-        clearAllWidgetPages();
-    }
-
-    public void clearAllWidgetPages() {
-        cancelAllTasks();
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View v = getPageAt(i);
-            if (v instanceof PagedViewGridLayout) {
-                ((PagedViewGridLayout) v).removeAllViewsOnPage();
-                mDirtyPageContent.set(i, true);
-            }
-        }
-    }
-
-    private void cancelAllTasks() {
-        // Clean up all the async tasks
-        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
-        while (iter.hasNext()) {
-            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
-            task.cancel(false);
-            iter.remove();
-            mDirtyPageContent.set(task.page, true);
-
-            // We've already preallocated the views for the data to load into, so clear them as well
-            View v = getPageAt(task.page);
-            if (v instanceof PagedViewGridLayout) {
-                ((PagedViewGridLayout) v).removeAllViewsOnPage();
-            }
-        }
-        mDeferredSyncWidgetPageItems.clear();
-        mDeferredPrepareLoadWidgetPreviewsTasks.clear();
-    }
-
-    public void setContentType(ContentType type) {
-        // Widgets appear to be cleared every time you leave, always force invalidate for them
-        if (mContentType != type || type == ContentType.Widgets) {
-            int page = (mContentType != type) ? 0 : getCurrentPage();
-            mContentType = type;
-            invalidatePageData(page, true);
-        }
-    }
-
-    public ContentType getContentType() {
-        return mContentType;
-    }
-
-    protected void snapToPage(int whichPage, int delta, int duration) {
-        super.snapToPage(whichPage, delta, duration);
-
-        // Update the thread priorities given the direction lookahead
-        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
-        while (iter.hasNext()) {
-            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
-            int pageIndex = task.page;
-            if ((mNextPage > mCurrentPage && pageIndex >= mCurrentPage) ||
-                (mNextPage < mCurrentPage && pageIndex <= mCurrentPage)) {
-                task.setThreadPriority(getThreadPriorityForPage(pageIndex));
-            } else {
-                task.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
-            }
-        }
-    }
-
-    /*
-     * Apps PagedView implementation
-     */
-    private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
-        int childCount = layout.getChildCount();
-        for (int i = 0; i < childCount; ++i) {
-            layout.getChildAt(i).setVisibility(visibility);
-        }
-    }
-    private void setupPage(AppsCustomizeCellLayout layout) {
-        layout.setGridSize(mCellCountX, mCellCountY);
-
-        // Note: We force a measure here to get around the fact that when we do layout calculations
-        // immediately after syncing, we don't have a proper width.  That said, we already know the
-        // expected page width, so we can actually optimize by hiding all the TextView-based
-        // children that are expensive to measure, and let that happen naturally later.
-        setVisibilityOnChildren(layout, View.GONE);
-        int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
-        int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-        layout.measure(widthSpec, heightSpec);
-
-        Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel);
-        if (bg != null) {
-            bg.setAlpha(mPageBackgroundsVisible ? 255: 0);
-            layout.setBackground(bg);
-        }
-
-        setVisibilityOnChildren(layout, View.VISIBLE);
-    }
-
-    public void setPageBackgroundsVisible(boolean visible) {
-        mPageBackgroundsVisible = visible;
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; ++i) {
-            Drawable bg = getChildAt(i).getBackground();
-            if (bg != null) {
-                bg.setAlpha(visible ? 255 : 0);
-            }
-        }
-    }
-
-    public void syncAppsPageItems(int page, boolean immediate) {
-        // ensure that we have the right number of items on the pages
-        final boolean isRtl = isLayoutRtl();
-        int numCells = mCellCountX * mCellCountY;
-        int startIndex = page * numCells;
-        int endIndex = Math.min(startIndex + numCells, mApps.size());
-        AppsCustomizeCellLayout layout = (AppsCustomizeCellLayout) getPageAt(page);
-
-        layout.removeAllViewsOnPage();
-        ArrayList<Object> items = new ArrayList<Object>();
-        ArrayList<Bitmap> images = new ArrayList<Bitmap>();
-        for (int i = startIndex; i < endIndex; ++i) {
-            AppInfo info = mApps.get(i);
-            BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
-                    R.layout.apps_customize_application, layout, false);
-            icon.applyFromApplicationInfo(info);
-            icon.setOnClickListener(mLauncher);
-            icon.setOnLongClickListener(this);
-            icon.setOnTouchListener(this);
-            icon.setOnKeyListener(this);
-            icon.setOnFocusChangeListener(layout.mFocusHandlerView);
-
-            int index = i - startIndex;
-            int x = index % mCellCountX;
-            int y = index / mCellCountX;
-            if (isRtl) {
-                x = mCellCountX - x - 1;
-            }
-            layout.addViewToCellLayout(icon, -1, i, new CellLayout.LayoutParams(x,y, 1,1), false);
-
-            items.add(info);
-            images.add(info.iconBitmap);
-        }
-
-        enableHwLayersOnVisiblePages();
-    }
-
-    /**
-     * A helper to return the priority for loading of the specified widget page.
-     */
-    private int getWidgetPageLoadPriority(int page) {
-        // If we are snapping to another page, use that index as the target page index
-        int toPage = mCurrentPage;
-        if (mNextPage > -1) {
-            toPage = mNextPage;
-        }
-
-        // We use the distance from the target page as an initial guess of priority, but if there
-        // are no pages of higher priority than the page specified, then bump up the priority of
-        // the specified page.
-        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
-        int minPageDiff = Integer.MAX_VALUE;
-        while (iter.hasNext()) {
-            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
-            minPageDiff = Math.abs(task.page - toPage);
-        }
-
-        int rawPageDiff = Math.abs(page - toPage);
-        return rawPageDiff - Math.min(rawPageDiff, minPageDiff);
-    }
-    /**
-     * Return the appropriate thread priority for loading for a given page (we give the current
-     * page much higher priority)
-     */
-    private int getThreadPriorityForPage(int page) {
-        // TODO-APPS_CUSTOMIZE: detect number of cores and set thread priorities accordingly below
-        int pageDiff = getWidgetPageLoadPriority(page);
-        if (pageDiff <= 0) {
-            return Process.THREAD_PRIORITY_LESS_FAVORABLE;
-        } else if (pageDiff <= 1) {
-            return Process.THREAD_PRIORITY_LOWEST;
-        } else {
-            return Process.THREAD_PRIORITY_LOWEST;
-        }
-    }
-    private int getSleepForPage(int page) {
-        int pageDiff = getWidgetPageLoadPriority(page);
-        return Math.max(0, pageDiff * sPageSleepDelay);
-    }
-    /**
-     * Creates and executes a new AsyncTask to load a page of widget previews.
-     */
-    private void prepareLoadWidgetPreviewsTask(int page, ArrayList<Object> widgets,
-            int cellWidth, int cellHeight, int cellCountX) {
-
-        // Prune all tasks that are no longer needed
-        Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
-        while (iter.hasNext()) {
-            AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
-            int taskPage = task.page;
-            if (taskPage < getAssociatedLowerPageBound(mCurrentPage) ||
-                    taskPage > getAssociatedUpperPageBound(mCurrentPage)) {
-                task.cancel(false);
-                iter.remove();
-            } else {
-                task.setThreadPriority(getThreadPriorityForPage(taskPage));
-            }
-        }
-
-        // We introduce a slight delay to order the loading of side pages so that we don't thrash
-        final int sleepMs = getSleepForPage(page);
-        AsyncTaskPageData pageData = new AsyncTaskPageData(page, widgets, cellWidth, cellHeight,
-            new AsyncTaskCallback() {
-                @Override
-                public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
-                    try {
-                        try {
-                            Thread.sleep(sleepMs);
-                        } catch (Exception e) {}
-                        loadWidgetPreviewsInBackground(task, data);
-                    } finally {
-                        if (task.isCancelled()) {
-                            data.cleanup(true);
-                        }
-                    }
-                }
-            },
-            new AsyncTaskCallback() {
-                @Override
-                public void run(AppsCustomizeAsyncTask task, AsyncTaskPageData data) {
-                    mRunningTasks.remove(task);
-                    if (task.isCancelled()) return;
-                    // do cleanup inside onSyncWidgetPageItems
-                    onSyncWidgetPageItems(data, false);
-                }
-            }, getWidgetPreviewLoader());
-
-        // Ensure that the task is appropriately prioritized and runs in parallel
-        AppsCustomizeAsyncTask t = new AppsCustomizeAsyncTask(page,
-                AsyncTaskPageData.Type.LoadWidgetPreviewData);
-        t.setThreadPriority(getThreadPriorityForPage(page));
-        t.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, pageData);
-        mRunningTasks.add(t);
-    }
-
-    /*
-     * Widgets PagedView implementation
-     */
-    private void setupPage(PagedViewGridLayout layout) {
-        // Note: We force a measure here to get around the fact that when we do layout calculations
-        // immediately after syncing, we don't have a proper width.
-        int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
-        int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-
-        Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel_dark);
-        if (bg != null) {
-            bg.setAlpha(mPageBackgroundsVisible ? 255 : 0);
-            layout.setBackground(bg);
-        }
-        layout.measure(widthSpec, heightSpec);
-    }
-
-    public void syncWidgetPageItems(final int page, final boolean immediate) {
-        int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-
-        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
-        // Calculate the dimensions of each cell we are giving to each widget
-        final ArrayList<Object> items = new ArrayList<Object>();
-        int contentWidth = mContentWidth - layout.getPaddingLeft() - layout.getPaddingRight();
-        final int cellWidth = contentWidth / mWidgetCountX;
-        int contentHeight = mContentHeight - layout.getPaddingTop() - layout.getPaddingBottom();
-
-        final int cellHeight = contentHeight / mWidgetCountY;
-
-        // Prepare the set of widgets to load previews for in the background
-        int offset = page * numItemsPerPage;
-        for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) {
-            items.add(mWidgets.get(i));
-        }
-
-        // Prepopulate the pages with the other widget info, and fill in the previews later
-        layout.setColumnCount(layout.getCellCountX());
-        for (int i = 0; i < items.size(); ++i) {
-            Object rawInfo = items.get(i);
-            PendingAddItemInfo createItemInfo = null;
-            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
-                    R.layout.apps_customize_widget, layout, false);
-            if (rawInfo instanceof AppWidgetProviderInfo) {
-                // Fill in the widget information
-                AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
-                createItemInfo = new PendingAddWidgetInfo(info, null, null);
-
-                // Determine the widget spans and min resize spans.
-                int[] spanXY = Launcher.getSpanForWidget(mLauncher, info);
-                createItemInfo.spanX = spanXY[0];
-                createItemInfo.spanY = spanXY[1];
-                int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, info);
-                createItemInfo.minSpanX = minSpanXY[0];
-                createItemInfo.minSpanY = minSpanXY[1];
-
-                widget.applyFromAppWidgetProviderInfo(info, -1, spanXY, getWidgetPreviewLoader());
-                widget.setTag(createItemInfo);
-                widget.setShortPressListener(this);
-            } else if (rawInfo instanceof ResolveInfo) {
-                // Fill in the shortcuts information
-                ResolveInfo info = (ResolveInfo) rawInfo;
-                createItemInfo = new PendingAddShortcutInfo(info.activityInfo);
-                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-                createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
-                        info.activityInfo.name);
-                widget.applyFromResolveInfo(mPackageManager, info, getWidgetPreviewLoader());
-                widget.setTag(createItemInfo);
-            }
-            widget.setOnClickListener(this);
-            widget.setOnLongClickListener(this);
-            widget.setOnTouchListener(this);
-            widget.setOnKeyListener(this);
-
-            // Layout each widget
-            int ix = i % mWidgetCountX;
-            int iy = i / mWidgetCountX;
-
-            if (ix > 0) {
-                View border = widget.findViewById(R.id.left_border);
-                border.setVisibility(View.VISIBLE);
-            }
-            if (ix < mWidgetCountX - 1) {
-                View border = widget.findViewById(R.id.right_border);
-                border.setVisibility(View.VISIBLE);
-            }
-
-            GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
-                    GridLayout.spec(iy, GridLayout.START),
-                    GridLayout.spec(ix, GridLayout.TOP));
-            lp.width = cellWidth;
-            lp.height = cellHeight;
-            lp.setGravity(Gravity.TOP | Gravity.START);
-            layout.addView(widget, lp);
-        }
-
-        // wait until a call on onLayout to start loading, because
-        // PagedViewWidget.getPreviewSize() will return 0 if it hasn't been laid out
-        // TODO: can we do a measure/layout immediately?
-        layout.setOnLayoutListener(new Runnable() {
-            public void run() {
-                // Load the widget previews
-                int maxPreviewWidth = cellWidth;
-                int maxPreviewHeight = cellHeight;
-                if (layout.getChildCount() > 0) {
-                    PagedViewWidget w = (PagedViewWidget) layout.getChildAt(0);
-                    int[] maxSize = w.getPreviewSize();
-                    maxPreviewWidth = maxSize[0];
-                    maxPreviewHeight = maxSize[1];
-                }
-
-                getWidgetPreviewLoader().setPreviewSize(
-                        maxPreviewWidth, maxPreviewHeight, mWidgetSpacingLayout);
-                if (immediate) {
-                    AsyncTaskPageData data = new AsyncTaskPageData(page, items,
-                            maxPreviewWidth, maxPreviewHeight, null, null, getWidgetPreviewLoader());
-                    loadWidgetPreviewsInBackground(null, data);
-                    onSyncWidgetPageItems(data, immediate);
-                } else {
-                    if (mInTransition) {
-                        mDeferredPrepareLoadWidgetPreviewsTasks.add(this);
-                    } else {
-                        prepareLoadWidgetPreviewsTask(page, items,
-                                maxPreviewWidth, maxPreviewHeight, mWidgetCountX);
-                    }
-                }
-                layout.setOnLayoutListener(null);
-            }
-        });
-    }
-    private void loadWidgetPreviewsInBackground(AppsCustomizeAsyncTask task,
-            AsyncTaskPageData data) {
-        // loadWidgetPreviewsInBackground can be called without a task to load a set of widget
-        // previews synchronously
-        if (task != null) {
-            // Ensure that this task starts running at the correct priority
-            task.syncThreadPriority();
-        }
-
-        // Load each of the widget/shortcut previews
-        ArrayList<Object> items = data.items;
-        ArrayList<Bitmap> images = data.generatedImages;
-        int count = items.size();
-        for (int i = 0; i < count; ++i) {
-            if (task != null) {
-                // Ensure we haven't been cancelled yet
-                if (task.isCancelled()) break;
-                // Before work on each item, ensure that this task is running at the correct
-                // priority
-                task.syncThreadPriority();
-            }
-
-            images.add(getWidgetPreviewLoader().getPreview(items.get(i)));
-        }
-    }
-
-    private void onSyncWidgetPageItems(AsyncTaskPageData data, boolean immediatelySyncItems) {
-        if (!immediatelySyncItems && mInTransition) {
-            mDeferredSyncWidgetPageItems.add(data);
-            return;
-        }
-        try {
-            int page = data.page;
-            PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
-            ArrayList<Object> items = data.items;
-            int count = items.size();
-            for (int i = 0; i < count; ++i) {
-                PagedViewWidget widget = (PagedViewWidget) layout.getChildAt(i);
-                if (widget != null) {
-                    Bitmap preview = data.generatedImages.get(i);
-                    widget.applyPreview(new FastBitmapDrawable(preview), i);
-                }
-            }
-
-            enableHwLayersOnVisiblePages();
-
-            // Update all thread priorities
-            Iterator<AppsCustomizeAsyncTask> iter = mRunningTasks.iterator();
-            while (iter.hasNext()) {
-                AppsCustomizeAsyncTask task = (AppsCustomizeAsyncTask) iter.next();
-                int pageIndex = task.page;
-                task.setThreadPriority(getThreadPriorityForPage(pageIndex));
-            }
-        } finally {
-            data.cleanup(false);
-        }
-    }
-
-    @Override
-    public void syncPages() {
-        disablePagedViewAnimations();
-
-        removeAllViews();
-        cancelAllTasks();
-
-        Context context = getContext();
-        if (mContentType == ContentType.Applications) {
-            for (int i = 0; i < mNumAppsPages; ++i) {
-                AppsCustomizeCellLayout layout = new AppsCustomizeCellLayout(context);
-                setupPage(layout);
-                addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
-                        LayoutParams.MATCH_PARENT));
-            }
-        } else if (mContentType == ContentType.Widgets) {
-            for (int j = 0; j < mNumWidgetPages; ++j) {
-                PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
-                        mWidgetCountY);
-                setupPage(layout);
-                addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
-                        LayoutParams.MATCH_PARENT));
-            }
-        } else {
-            throw new RuntimeException("Invalid ContentType");
-        }
-
-        enablePagedViewAnimations();
-    }
-
-    @Override
-    public void syncPageItems(int page, boolean immediate) {
-        if (mContentType == ContentType.Widgets) {
-            syncWidgetPageItems(page, immediate);
-        } else {
-            syncAppsPageItems(page, immediate);
-        }
-    }
-
-    // We want our pages to be z-ordered such that the further a page is to the left, the higher
-    // it is in the z-order. This is important to insure touch events are handled correctly.
-    View getPageAt(int index) {
-        return getChildAt(indexToPage(index));
-    }
-
-    @Override
-    protected int indexToPage(int index) {
-        return getChildCount() - index - 1;
-    }
-
-    // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        super.screenScrolled(screenCenter);
-        enableHwLayersOnVisiblePages();
-    }
-
-    private void enableHwLayersOnVisiblePages() {
-        final int screenCount = getChildCount();
-
-        getVisiblePages(mTempVisiblePagesRange);
-        int leftScreen = mTempVisiblePagesRange[0];
-        int rightScreen = mTempVisiblePagesRange[1];
-        int forceDrawScreen = -1;
-        if (leftScreen == rightScreen) {
-            // make sure we're caching at least two pages always
-            if (rightScreen < screenCount - 1) {
-                rightScreen++;
-                forceDrawScreen = rightScreen;
-            } else if (leftScreen > 0) {
-                leftScreen--;
-                forceDrawScreen = leftScreen;
-            }
-        } else {
-            forceDrawScreen = leftScreen + 1;
-        }
-
-        for (int i = 0; i < screenCount; i++) {
-            final View layout = (View) getPageAt(i);
-            if (!(leftScreen <= i && i <= rightScreen &&
-                    (i == forceDrawScreen || shouldDrawChild(layout)))) {
-                layout.setLayerType(LAYER_TYPE_NONE, null);
-            }
-        }
-
-        for (int i = 0; i < screenCount; i++) {
-            final View layout = (View) getPageAt(i);
-
-            if (leftScreen <= i && i <= rightScreen &&
-                    (i == forceDrawScreen || shouldDrawChild(layout))) {
-                if (layout.getLayerType() != LAYER_TYPE_HARDWARE) {
-                    layout.setLayerType(LAYER_TYPE_HARDWARE, null);
-                }
-            }
-        }
-    }
-
-    protected void overScroll(float amount) {
-        dampedOverScroll(amount);
-    }
-
-    /**
-     * Used by the parent to get the content width to set the tab bar to
-     * @return
-     */
-    public int getPageContentWidth() {
-        return mContentWidth;
-    }
-
-    @Override
-    protected void onPageEndMoving() {
-        super.onPageEndMoving();
-        mForceDrawAllChildrenNextFrame = true;
-        // We reset the save index when we change pages so that it will be recalculated on next
-        // rotation
-        mSaveInstanceStateItemIndex = -1;
-    }
-
-    /*
-     * AllAppsView implementation
-     */
-    public void setup(Launcher launcher, DragController dragController) {
-        mLauncher = launcher;
-        mDragController = dragController;
-    }
-
-    /**
-     * We should call thise method whenever the core data changes (mApps, mWidgets) so that we can
-     * appropriately determine when to invalidate the PagedView page data.  In cases where the data
-     * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
-     * next onMeasure() pass, which will trigger an invalidatePageData() itself.
-     */
-    private void invalidateOnDataChange() {
-        if (!isDataReady()) {
-            // The next layout pass will trigger data-ready if both widgets and apps are set, so
-            // request a layout to trigger the page data when ready.
-            requestLayout();
-        } else {
-            cancelAllTasks();
-            invalidatePageData();
-        }
-    }
-
-    public void setApps(ArrayList<AppInfo> list) {
-        if (!LauncherAppState.isDisableAllApps()) {
-            mApps = list;
-            Collections.sort(mApps, LauncherModel.getAppNameComparator());
-            updatePageCountsAndInvalidateData();
-        }
-    }
-    private void addAppsWithoutInvalidate(ArrayList<AppInfo> list) {
-        // We add it in place, in alphabetical order
-        int count = list.size();
-        for (int i = 0; i < count; ++i) {
-            AppInfo info = list.get(i);
-            int index = Collections.binarySearch(mApps, info, LauncherModel.getAppNameComparator());
-            if (index < 0) {
-                mApps.add(-(index + 1), info);
-            }
-        }
-    }
-    public void addApps(ArrayList<AppInfo> list) {
-        if (!LauncherAppState.isDisableAllApps()) {
-            addAppsWithoutInvalidate(list);
-            updatePageCountsAndInvalidateData();
-        }
-    }
-    private int findAppByComponent(List<AppInfo> list, AppInfo item) {
-        ComponentName removeComponent = item.intent.getComponent();
-        int length = list.size();
-        for (int i = 0; i < length; ++i) {
-            AppInfo info = list.get(i);
-            if (info.user.equals(item.user)
-                    && info.intent.getComponent().equals(removeComponent)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-    private void removeAppsWithoutInvalidate(ArrayList<AppInfo> list) {
-        // loop through all the apps and remove apps that have the same component
-        int length = list.size();
-        for (int i = 0; i < length; ++i) {
-            AppInfo info = list.get(i);
-            int removeIndex = findAppByComponent(mApps, info);
-            if (removeIndex > -1) {
-                mApps.remove(removeIndex);
-            }
-        }
-    }
-    public void removeApps(ArrayList<AppInfo> appInfos) {
-        if (!LauncherAppState.isDisableAllApps()) {
-            removeAppsWithoutInvalidate(appInfos);
-            updatePageCountsAndInvalidateData();
-        }
-    }
-    public void updateApps(ArrayList<AppInfo> list) {
-        // We remove and re-add the updated applications list because it's properties may have
-        // changed (ie. the title), and this will ensure that the items will be in their proper
-        // place in the list.
-        if (!LauncherAppState.isDisableAllApps()) {
-            removeAppsWithoutInvalidate(list);
-            addAppsWithoutInvalidate(list);
-            updatePageCountsAndInvalidateData();
-        }
-    }
-
-    public void reset() {
-        // If we have reset, then we should not continue to restore the previous state
-        mSaveInstanceStateItemIndex = -1;
-
-        if (mContentType != ContentType.Applications) {
-            setContentType(ContentType.Applications);
-        }
-
-        if (mCurrentPage != 0) {
-            invalidatePageData(0);
-        }
-    }
-
-    private AppsCustomizeTabHost getTabHost() {
-        return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
-    }
-
-    public void dumpState() {
-        // TODO: Dump information related to current list of Applications, Widgets, etc.
-        AppInfo.dumpApplicationInfoList(TAG, "mApps", mApps);
-        dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
-    }
-
-    private void dumpAppWidgetProviderInfoList(String tag, String label,
-            ArrayList<Object> list) {
-        Log.d(tag, label + " size=" + list.size());
-        for (Object i: list) {
-            if (i instanceof AppWidgetProviderInfo) {
-                AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
-                Log.d(tag, "   label=\"" + info.label + "\" previewImage=" + info.previewImage
-                        + " resizeMode=" + info.resizeMode + " configure=" + info.configure
-                        + " initialLayout=" + info.initialLayout
-                        + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
-            } else if (i instanceof ResolveInfo) {
-                ResolveInfo info = (ResolveInfo) i;
-                Log.d(tag, "   label=\"" + info.loadLabel(mPackageManager) + "\" icon="
-                        + info.icon);
-            }
-        }
-    }
-
-    public void surrender() {
-        // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
-        // should stop this now.
-
-        // Stop all background tasks
-        cancelAllTasks();
-    }
-
-    /*
-     * We load an extra page on each side to prevent flashes from scrolling and loading of the
-     * widget previews in the background with the AsyncTasks.
-     */
-    final static int sLookBehindPageCount = 2;
-    final static int sLookAheadPageCount = 2;
-    protected int getAssociatedLowerPageBound(int page) {
-        final int count = getChildCount();
-        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
-        int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0);
-        return windowMinIndex;
-    }
-    protected int getAssociatedUpperPageBound(int page) {
-        final int count = getChildCount();
-        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
-        int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1),
-                count - 1);
-        return windowMaxIndex;
-    }
-
-    protected String getCurrentPageDescription() {
-        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-        int stringId = R.string.default_scroll_format;
-        int count = 0;
-
-        if (mContentType == ContentType.Applications) {
-            stringId = R.string.apps_customize_apps_scroll_format;
-            count = mNumAppsPages;
-        } else if (mContentType == ContentType.Widgets) {
-            stringId = R.string.apps_customize_widgets_scroll_format;
-            count = mNumWidgetPages;
-        } else {
-            throw new RuntimeException("Invalid ContentType");
-        }
-
-        return String.format(getContext().getString(stringId), page + 1, count);
-    }
-}
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
deleted file mode 100644
index a271712..0000000
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.FrameLayout;
-
-public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable  {
-    static final String LOG_TAG = "AppsCustomizeTabHost";
-
-    private static final String APPS_TAB_TAG = "APPS";
-    private static final String WIDGETS_TAB_TAG = "WIDGETS";
-
-    private AppsCustomizePagedView mPagedView;
-    private View mContent;
-    private boolean mInTransition = false;
-
-    private final Rect mInsets = new Rect();
-
-    public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    /**
-     * Convenience methods to select specific tabs.  We want to set the content type immediately
-     * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
-     * reflects the new content (but doesn't do the animation and logic associated with changing
-     * tabs manually).
-     */
-    void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
-        mPagedView.setContentType(type);
-    }
-
-    public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
-        setContentTypeImmediate(type);
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
-        flp.topMargin = insets.top;
-        flp.bottomMargin = insets.bottom;
-        flp.leftMargin = insets.left;
-        flp.rightMargin = insets.right;
-        mContent.setLayoutParams(flp);
-    }
-
-    /**
-     * Setup the tab host and create all necessary tabs.
-     */
-    @Override
-    protected void onFinishInflate() {
-        mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
-        mContent = findViewById(R.id.content);
-    }
-
-    public String getContentTag() {
-        return getTabTagForContentType(mPagedView.getContentType());
-    }
-
-    /**
-     * Returns the content type for the specified tab tag.
-     */
-    public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
-        if (tag.equals(APPS_TAB_TAG)) {
-            return AppsCustomizePagedView.ContentType.Applications;
-        } else if (tag.equals(WIDGETS_TAB_TAG)) {
-            return AppsCustomizePagedView.ContentType.Widgets;
-        }
-        return AppsCustomizePagedView.ContentType.Applications;
-    }
-
-    /**
-     * Returns the tab tag for a given content type.
-     */
-    public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
-        if (type == AppsCustomizePagedView.ContentType.Applications) {
-            return APPS_TAB_TAG;
-        } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
-            return WIDGETS_TAB_TAG;
-        }
-        return APPS_TAB_TAG;
-    }
-
-    /**
-     * Disable focus on anything under this view in the hierarchy if we are not visible.
-     */
-    @Override
-    public int getDescendantFocusability() {
-        if (getVisibility() != View.VISIBLE) {
-            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
-        }
-        return super.getDescendantFocusability();
-    }
-
-    void reset() {
-        // Reset immediately
-        mPagedView.reset();
-    }
-
-    void trimMemory() {
-        mPagedView.trimMemory();
-    }
-
-    public void onWindowVisible() {
-        if (getVisibility() == VISIBLE) {
-            mContent.setVisibility(VISIBLE);
-            // We unload the widget previews when the UI is hidden, so need to reload pages
-            // Load the current page synchronously, and the neighboring pages asynchronously
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-        }
-    }
-    @Override
-    public ViewGroup getContent() {
-        return mPagedView;
-    }
-
-    public boolean isInTransition() {
-        return mInTransition;
-    }
-
-    /* LauncherTransitionable overrides */
-    @Override
-    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
-        mInTransition = true;
-
-        if (toWorkspace) {
-            // Going from All Apps -> Workspace
-            setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
-        } else {
-            // Going from Workspace -> All Apps
-            mContent.setVisibility(VISIBLE);
-
-            // Make sure the current page is loaded (we start loading the side pages after the
-            // transition to prevent slowing down the animation)
-            // TODO: revisit this
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-        }
-    }
-
-    @Override
-    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
-    }
-
-    @Override
-    public void onLauncherTransitionStep(Launcher l, float t) {
-        mPagedView.onLauncherTransitionStep(l, t);
-    }
-
-    @Override
-    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
-        mInTransition = false;
-
-        if (!toWorkspace) {
-            // Make sure adjacent pages are loaded (we wait until after the transition to
-            // prevent slowing down the animation)
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-
-            // Opening apps, need to announce what page we are on.
-            AccessibilityManager am = (AccessibilityManager)
-                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-            if (am.isEnabled()) {
-                // Notify the user when the page changes
-                announceForAccessibility(mPagedView.getCurrentPageDescription());
-            }
-
-            // Going from Workspace -> All Apps
-            // NOTE: We should do this at the end since we check visibility state in some of the
-            // cling initialization/dismiss code above.
-            setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
-        }
-    }
-
-    private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
-        ViewGroup parent = (ViewGroup) getParent();
-        if (parent == null) return;
-
-        View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
-        final int count = parent.getChildCount();
-        if (!isChildrenDrawingOrderEnabled()) {
-            for (int i = 0; i < count; i++) {
-                final View child = parent.getChildAt(i);
-                if (child == this) {
-                    break;
-                } else {
-                    if (child.getVisibility() == GONE || child == overviewPanel) {
-                        continue;
-                    }
-                    child.setVisibility(visibility);
-                }
-            }
-        } else {
-            throw new RuntimeException("Failed; can't get z-order of views");
-        }
-    }
-}
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index a5d2228..99a98dd 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -37,6 +37,7 @@
 
 import com.android.launcher3.LauncherProvider.SqlArguments;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -44,6 +45,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Layout parsing code for auto installs layout
@@ -56,6 +58,11 @@
     static final String ACTION_LAUNCHER_CUSTOMIZATION =
             "android.autoinstalls.config.action.PLAY_AUTO_INSTALL";
 
+    /**
+     * Layout resource which also includes grid size and hotseat count, e.g., default_layout_6x6_h5
+     */
+    private static final String FORMATTED_LAYOUT_RES_WITH_HOSTEAT = "default_layout_%dx%d_h%s";
+    private static final String FORMATTED_LAYOUT_RES = "default_layout_%dx%d";
     private static final String LAYOUT_RES = "default_layout";
 
     static AutoInstallsLayout get(Context context, AppWidgetHost appWidgetHost,
@@ -65,19 +72,44 @@
         if (customizationApkInfo == null) {
             return null;
         }
+        return get(context, customizationApkInfo.first, customizationApkInfo.second,
+                appWidgetHost, callback);
+    }
 
-        String pkg = customizationApkInfo.first;
-        Resources res = customizationApkInfo.second;
-        int layoutId = res.getIdentifier(LAYOUT_RES, "xml", pkg);
+    static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
+            AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
+        InvariantDeviceProfile grid = LauncherAppState.getInstance().getInvariantDeviceProfile();
+
+        // Try with grid size and hotseat count
+        String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
+                (int) grid.numColumns, (int) grid.numRows, (int) grid.numHotseatIcons);
+        int layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
+
+        // Try with only grid size
+        if (layoutId == 0) {
+            Log.d(TAG, "Formatted layout: " + layoutName
+                    + " not found. Trying layout without hosteat");
+            layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES,
+                    (int) grid.numColumns, (int) grid.numRows);
+            layoutId = targetRes.getIdentifier(layoutName, "xml", pkg);
+        }
+
+        // Try the default layout
+        if (layoutId == 0) {
+            Log.d(TAG, "Formatted layout: " + layoutName + " not found. Trying the default layout");
+            layoutId = targetRes.getIdentifier(LAYOUT_RES, "xml", pkg);
+        }
+
         if (layoutId == 0) {
             Log.e(TAG, "Layout definition not found in package: " + pkg);
             return null;
         }
-        return new AutoInstallsLayout(context, appWidgetHost, callback, res, layoutId,
+        return new AutoInstallsLayout(context, appWidgetHost, callback, targetRes, layoutId,
                 TAG_WORKSPACE);
     }
 
     // Object Tags
+    private static final String TAG_INCLUDE = "include";
     private static final String TAG_WORKSPACE = "workspace";
     private static final String TAG_APP_ICON = "appicon";
     private static final String TAG_AUTO_INSTALL = "autoinstall";
@@ -100,6 +132,9 @@
     private static final String ATTR_ICON = "icon";
     private static final String ATTR_URL = "url";
 
+    // Attrs for "Include"
+    private static final String ATTR_WORKSPACE = "workspace";
+
     // Style attrs -- "Extra"
     private static final String ATTR_KEY = "key";
     private static final String ATTR_VALUE = "value";
@@ -110,9 +145,9 @@
     private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
             "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
 
-    private final Context mContext;
-    private final AppWidgetHost mAppWidgetHost;
-    private final LayoutParserCallback mCallback;
+    @Thunk final Context mContext;
+    @Thunk final AppWidgetHost mAppWidgetHost;
+    protected final LayoutParserCallback mCallback;
 
     protected final PackageManager mPackageManager;
     protected final Resources mSourceRes;
@@ -121,14 +156,21 @@
     private final int mHotseatAllAppsRank;
 
     private final long[] mTemp = new long[2];
-    private final ContentValues mValues;
-    private final String mRootTag;
+    @Thunk final ContentValues mValues;
+    protected final String mRootTag;
 
     protected SQLiteDatabase mDb;
 
     public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources res,
             int layoutId, String rootTag) {
+        this(context, appWidgetHost, callback, res, layoutId, rootTag,
+                LauncherAppState.getInstance().getInvariantDeviceProfile().hotseatAllAppsRank);
+    }
+
+    public AutoInstallsLayout(Context context, AppWidgetHost appWidgetHost,
+            LayoutParserCallback callback, Resources res,
+            int layoutId, String rootTag, int hotseatAllAppsRank) {
         mContext = context;
         mAppWidgetHost = appWidgetHost;
         mCallback = callback;
@@ -139,8 +181,7 @@
 
         mSourceRes = res;
         mLayoutId = layoutId;
-        mHotseatAllAppsRank = LauncherAppState.getInstance()
-                .getDynamicGrid().getDeviceProfile().hotseatAllAppsRank;
+        mHotseatAllAppsRank = hotseatAllAppsRank;
     }
 
     /**
@@ -202,6 +243,17 @@
             HashMap<String, TagParser> tagParserMap,
             ArrayList<Long> screenIds)
                     throws XmlPullParserException, IOException {
+
+        if (TAG_INCLUDE.equals(parser.getName())) {
+            final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
+            if (resId != 0) {
+                // recursively load some more favorites, why not?
+                return parseLayout(resId, screenIds);
+            } else {
+                return 0;
+            }
+        }
+
         mValues.clear();
         parseContainerAndScreen(parser, mTemp);
         final long container = mTemp[0];
@@ -528,6 +580,7 @@
 
             int type;
             int folderDepth = parser.getDepth();
+            int rank = 0;
             while ((type = parser.next()) != XmlPullParser.END_TAG ||
                     parser.getDepth() > folderDepth) {
                 if (type != XmlPullParser.START_TAG) {
@@ -535,12 +588,14 @@
                 }
                 mValues.clear();
                 mValues.put(Favorites.CONTAINER, folderId);
+                mValues.put(Favorites.RANK, rank);
 
                 TagParser tagParser = mFolderElements.get(parser.getName());
                 if (tagParser != null) {
                     final long id = tagParser.parseAndAdd(parser);
                     if (id >= 0) {
                         folderItems.add(id);
+                        rank++;
                     }
                 } else {
                     throw new RuntimeException("Invalid folder item " + parser.getName());
@@ -554,7 +609,7 @@
             // failed to add, and less than 2 were actually added
             if (folderItems.size() < 2) {
                 // Delete the folder
-                Uri uri = Favorites.getContentUri(folderId, false);
+                Uri uri = Favorites.getContentUri(folderId);
                 SqlArguments args = new SqlArguments(uri, null, null);
                 mDb.delete(args.table, args.where, args.args);
                 addedId = -1;
@@ -627,7 +682,7 @@
         long insertAndCheck(SQLiteDatabase db, ContentValues values);
     }
 
-    private static void copyInteger(ContentValues from, ContentValues to, String key) {
+    @Thunk static void copyInteger(ContentValues from, ContentValues to, String key) {
         to.put(key, from.getAsInteger(key));
     }
 }
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
new file mode 100644
index 0000000..c8de9df
--- /dev/null
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.LinearLayout;
+
+/**
+ * A base container view, which supports resizing.
+ */
+public abstract class BaseContainerView extends LinearLayout implements Insettable {
+
+    private final static String TAG = "BaseContainerView";
+
+    // The window insets
+    private Rect mInsets = new Rect();
+    // The bounds of the search bar.  Only the left, top, right are used to inset the
+    // search bar and the height is determined by the measurement of the layout
+    private Rect mFixedSearchBarBounds = new Rect();
+    // The bounds of the container
+    protected Rect mContentBounds = new Rect();
+    // The padding to apply to the container to achieve the bounds
+    protected Rect mContentPadding = new Rect();
+    // The inset to apply to the edges and between the search bar and the container
+    private int mContainerBoundsInset;
+    private boolean mHasSearchBar;
+
+    public BaseContainerView(Context context) {
+        this(context, null);
+    }
+
+    public BaseContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContainerBoundsInset = getResources().getDimensionPixelSize(R.dimen.container_bounds_inset);
+    }
+
+    @Override
+    final public void setInsets(Rect insets) {
+        mInsets.set(insets);
+        updateBackgroundAndPaddings();
+    }
+
+    protected void setHasSearchBar() {
+        mHasSearchBar = true;
+    }
+
+    /**
+     * Sets the search bar bounds for this container view to match.
+     */
+    final public void setSearchBarBounds(Rect bounds) {
+        if (LauncherAppState.isDogfoodBuild() && !isValidSearchBarBounds(bounds)) {
+            Log.e(TAG, "Invalid search bar bounds: " + bounds);
+        }
+
+        mFixedSearchBarBounds.set(bounds);
+
+        // Post the updates since they can trigger a relayout, and this call can be triggered from
+        // a layout pass itself.
+        post(new Runnable() {
+            @Override
+            public void run() {
+                updateBackgroundAndPaddings();
+            }
+        });
+    }
+
+    /**
+     * Update the backgrounds and padding in response to a change in the bounds or insets.
+     */
+    protected void updateBackgroundAndPaddings() {
+        Rect padding;
+        Rect searchBarBounds = new Rect(mFixedSearchBarBounds);
+        if (!isValidSearchBarBounds(mFixedSearchBarBounds)) {
+            // Use the default bounds
+            padding = new Rect(mInsets.left + mContainerBoundsInset,
+                    (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
+                    mInsets.right + mContainerBoundsInset,
+                    mInsets.bottom + mContainerBoundsInset);
+
+            // Special case -- we have the search bar, but no specific bounds, so just give it
+            // the inset bounds without a height.
+            searchBarBounds.set(mInsets.left + mContainerBoundsInset,
+                    mInsets.top + mContainerBoundsInset,
+                    getMeasuredWidth() - (mInsets.right + mContainerBoundsInset), 0);
+        } else {
+            // Use the search bounds, if there is a search bar, the bounds will contain
+            // the offsets for the insets so we can ignore that
+            padding = new Rect(mFixedSearchBarBounds.left,
+                    (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)),
+                    getMeasuredWidth() - mFixedSearchBarBounds.right,
+                    mInsets.bottom + mContainerBoundsInset);
+        }
+        if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mFixedSearchBarBounds)) {
+            mContentPadding.set(padding);
+            mContentBounds.set(padding.left, padding.top,
+                    getMeasuredWidth() - padding.right,
+                    getMeasuredHeight() - padding.bottom);
+            mFixedSearchBarBounds.set(searchBarBounds);
+            onUpdateBackgroundAndPaddings(mFixedSearchBarBounds, padding);
+        }
+    }
+
+    /**
+     * To be implemented by container views to update themselves when the bounds changes.
+     */
+    protected abstract void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding);
+
+    /**
+     * Returns whether the search bar bounds we got are considered valid.
+     */
+    private boolean isValidSearchBarBounds(Rect searchBarBounds) {
+        return !searchBarBounds.isEmpty() &&
+                searchBarBounds.right <= getMeasuredWidth() &&
+                searchBarBounds.bottom <= getMeasuredHeight();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
new file mode 100644
index 0000000..0fae427
--- /dev/null
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import com.android.launcher3.util.Thunk;
+
+
+/**
+ * A base {@link RecyclerView}, which does the following:
+ * <ul>
+ *   <li> NOT intercept a touch unless the scrolling velocity is below a predefined threshold.
+ *   <li> Enable fast scroller.
+ * </ul>
+ */
+public abstract class BaseRecyclerView extends RecyclerView
+        implements RecyclerView.OnItemTouchListener {
+
+    private static final int SCROLL_DELTA_THRESHOLD_DP = 4;
+
+    /** Keeps the last known scrolling delta/velocity along y-axis. */
+    @Thunk int mDy = 0;
+    private float mDeltaThreshold;
+
+    /**
+     * The current scroll state of the recycler view.  We use this in onUpdateScrollbar()
+     * and scrollToPositionAtProgress() to determine the scroll position of the recycler view so
+     * that we can calculate what the scroll bar looks like, and where to jump to from the fast
+     * scroller.
+     */
+    public static class ScrollPositionState {
+        // The index of the first visible row
+        public int rowIndex;
+        // The offset of the first visible row
+        public int rowTopOffset;
+        // The height of a given row (they are currently all the same height)
+        public int rowHeight;
+    }
+
+    protected BaseRecyclerViewFastScrollBar mScrollbar;
+
+    private int mDownX;
+    private int mDownY;
+    private int mLastY;
+    protected Rect mBackgroundPadding = new Rect();
+
+    public BaseRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public BaseRecyclerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mDeltaThreshold = getResources().getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
+        mScrollbar = new BaseRecyclerViewFastScrollBar(this, getResources());
+
+        ScrollListener listener = new ScrollListener();
+        setOnScrollListener(listener);
+    }
+
+    private class ScrollListener extends OnScrollListener {
+        public ScrollListener() {
+            // Do nothing
+        }
+
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+            mDy = dy;
+
+            // TODO(winsonc): If we want to animate the section heads while scrolling, we can
+            //                initiate that here if the recycler view scroll state is not
+            //                RecyclerView.SCROLL_STATE_IDLE.
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        addOnItemTouchListener(this);
+    }
+
+    /**
+     * We intercept the touch handling only to support fast scrolling when initiated from the
+     * scroll bar.  Otherwise, we fall back to the default RecyclerView touch handling.
+     */
+    @Override
+    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
+        return handleTouchEvent(ev);
+    }
+
+    @Override
+    public void onTouchEvent(RecyclerView rv, MotionEvent ev) {
+        handleTouchEvent(ev);
+    }
+
+    /**
+     * Handles the touch event and determines whether to show the fast scroller (or updates it if
+     * it is already showing).
+     */
+    private boolean handleTouchEvent(MotionEvent ev) {
+        int action = ev.getAction();
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                // Keep track of the down positions
+                mDownX = x;
+                mDownY = mLastY = y;
+                if (shouldStopScroll(ev)) {
+                    stopScroll();
+                }
+                mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                mLastY = y;
+                mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                onFastScrollCompleted();
+                mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY);
+                break;
+        }
+        return mScrollbar.isDragging();
+    }
+
+    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        // DO NOT REMOVE, NEEDED IMPLEMENTATION FOR M BUILDS
+    }
+
+    /**
+     * Returns whether this {@link MotionEvent} should trigger the scroll to be stopped.
+     */
+    protected boolean shouldStopScroll(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if ((Math.abs(mDy) < mDeltaThreshold &&
+                    getScrollState() != RecyclerView.SCROLL_STATE_IDLE)) {
+                // now the touch events are being passed to the {@link WidgetCell} until the
+                // touch sequence goes over the touch slop.
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void updateBackgroundPadding(Rect padding) {
+        mBackgroundPadding.set(padding);
+    }
+
+    public Rect getBackgroundPadding() {
+        return mBackgroundPadding;
+    }
+
+    /**
+     * Returns the scroll bar width when the user is scrolling.
+     */
+    public int getMaxScrollbarWidth() {
+        return mScrollbar.getThumbMaxWidth();
+    }
+
+    /**
+     * Returns the available scroll height:
+     *   AvailableScrollHeight = Total height of the all items - last page height
+     *
+     * This assumes that all rows are the same height.
+     *
+     * @param yOffset the offset from the top of the recycler view to start tracking.
+     */
+    protected int getAvailableScrollHeight(int rowCount, int rowHeight, int yOffset) {
+        int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom;
+        int scrollHeight = getPaddingTop() + yOffset + rowCount * rowHeight + getPaddingBottom();
+        int availableScrollHeight = scrollHeight - visibleHeight;
+        return availableScrollHeight;
+    }
+
+    /**
+     * Returns the available scroll bar height:
+     *   AvailableScrollBarHeight = Total height of the visible view - thumb height
+     */
+    protected int getAvailableScrollBarHeight() {
+        int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom;
+        int availableScrollBarHeight = visibleHeight - mScrollbar.getThumbHeight();
+        return availableScrollBarHeight;
+    }
+
+    /**
+     * Returns the track color (ignoring alpha), can be overridden by each subclass.
+     */
+    public int getFastScrollerTrackColor(int defaultTrackColor) {
+        return defaultTrackColor;
+    }
+
+    /**
+     * Returns the inactive thumb color, can be overridden by each subclass.
+     */
+    public int getFastScrollerThumbInactiveColor(int defaultInactiveThumbColor) {
+        return defaultInactiveThumbColor;
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        onUpdateScrollbar();
+        mScrollbar.draw(canvas);
+    }
+
+    /**
+     * Updates the scrollbar thumb offset to match the visible scroll of the recycler view.  It does
+     * this by mapping the available scroll area of the recycler view to the available space for the
+     * scroll bar.
+     *
+     * @param scrollPosState the current scroll position
+     * @param rowCount the number of rows, used to calculate the total scroll height (assumes that
+     *                 all rows are the same height)
+     * @param yOffset the offset to start tracking in the recycler view (only used for all apps)
+     */
+    protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState,
+            int rowCount, int yOffset) {
+        int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight,
+                yOffset);
+        int availableScrollBarHeight = getAvailableScrollBarHeight();
+
+        // Only show the scrollbar if there is height to be scrolled
+        if (availableScrollHeight <= 0) {
+            mScrollbar.setScrollbarThumbOffset(-1, -1);
+            return;
+        }
+
+        // Calculate the current scroll position, the scrollY of the recycler view accounts for the
+        // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
+        // padding)
+        int scrollY = getPaddingTop() + yOffset +
+                (scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset;
+        int scrollBarY = mBackgroundPadding.top +
+                (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
+
+        // Calculate the position and size of the scroll bar
+        int scrollBarX;
+        if (Utilities.isRtl(getResources())) {
+            scrollBarX = mBackgroundPadding.left;
+        } else {
+            scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getWidth();
+        }
+        mScrollbar.setScrollbarThumbOffset(scrollBarX, scrollBarY);
+    }
+
+    /**
+     * Maps the touch (from 0..1) to the adapter position that should be visible.
+     * <p>Override in each subclass of this base class.
+     */
+    public abstract String scrollToPositionAtProgress(float touchFraction);
+
+    /**
+     * Updates the bounds for the scrollbar.
+     * <p>Override in each subclass of this base class.
+     */
+    public abstract void onUpdateScrollbar();
+
+    /**
+     * <p>Override in each subclass of this base class.
+     */
+    public void onFastScrollCompleted() {}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
new file mode 100644
index 0000000..2c4184d
--- /dev/null
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3;
+
+import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.util.Thunk;
+
+/**
+ * The track and scrollbar that shows when you scroll the list.
+ */
+public class BaseRecyclerViewFastScrollBar {
+
+    public interface FastScrollFocusableView {
+        void setFastScrollFocused(boolean focused, boolean animated);
+    }
+
+    private final static int MAX_TRACK_ALPHA = 30;
+    private final static int SCROLL_BAR_VIS_DURATION = 150;
+
+    @Thunk BaseRecyclerView mRv;
+    private BaseRecyclerViewFastScrollPopup mPopup;
+
+    private AnimatorSet mScrollbarAnimator;
+
+    private int mThumbInactiveColor;
+    private int mThumbActiveColor;
+    @Thunk Point mThumbOffset = new Point(-1, -1);
+    @Thunk Paint mThumbPaint;
+    private Paint mTrackPaint;
+    private int mThumbMinWidth;
+    private int mThumbMaxWidth;
+    @Thunk int mThumbWidth;
+    @Thunk int mThumbHeight;
+    // The inset is the buffer around which a point will still register as a click on the scrollbar
+    private int mTouchInset;
+    private boolean mIsDragging;
+
+    // This is the offset from the top of the scrollbar when the user first starts touching.  To
+    // prevent jumping, this offset is applied as the user scrolls.
+    private int mTouchOffset;
+
+    private Rect mInvalidateRect = new Rect();
+    private Rect mTmpRect = new Rect();
+
+    public BaseRecyclerViewFastScrollBar(BaseRecyclerView rv, Resources res) {
+        mRv = rv;
+        mPopup = new BaseRecyclerViewFastScrollPopup(rv, res);
+        mTrackPaint = new Paint();
+        mTrackPaint.setColor(rv.getFastScrollerTrackColor(Color.BLACK));
+        mTrackPaint.setAlpha(0);
+        mThumbInactiveColor = rv.getFastScrollerThumbInactiveColor(
+                res.getColor(R.color.container_fastscroll_thumb_inactive_color));
+        mThumbActiveColor = res.getColor(R.color.container_fastscroll_thumb_active_color);
+        mThumbPaint = new Paint();
+        mThumbPaint.setColor(mThumbInactiveColor);
+        mThumbWidth = mThumbMinWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_min_width);
+        mThumbMaxWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_max_width);
+        mThumbHeight = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_height);
+        mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset);
+    }
+
+    public void setScrollbarThumbOffset(int x, int y) {
+        if (mThumbOffset.x == x && mThumbOffset.y == y) {
+            return;
+        }
+        mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight());
+        mThumbOffset.set(x, y);
+        mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth,
+                mRv.getHeight()));
+        mRv.invalidate(mInvalidateRect);
+    }
+
+    // Setter/getter for the search bar width for animations
+    public void setWidth(int width) {
+        mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight());
+        mThumbWidth = width;
+        mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth,
+                mRv.getHeight()));
+        mRv.invalidate(mInvalidateRect);
+    }
+
+    public int getWidth() {
+        return mThumbWidth;
+    }
+
+    // Setter/getter for the track background alpha for animations
+    public void setTrackAlpha(int alpha) {
+        mTrackPaint.setAlpha(alpha);
+        mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight());
+        mRv.invalidate(mInvalidateRect);
+    }
+
+    public int getTrackAlpha() {
+        return mTrackPaint.getAlpha();
+    }
+
+    public int getThumbHeight() {
+        return mThumbHeight;
+    }
+
+    public int getThumbMaxWidth() {
+        return mThumbMaxWidth;
+    }
+
+    public boolean isDragging() {
+        return mIsDragging;
+    }
+
+    /**
+     * Handles the touch event and determines whether to show the fast scroller (or updates it if
+     * it is already showing).
+     */
+    public void handleTouchEvent(MotionEvent ev, int downX, int downY, int lastY) {
+        ViewConfiguration config = ViewConfiguration.get(mRv.getContext());
+
+        int action = ev.getAction();
+        int y = (int) ev.getY();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                if (isNearPoint(downX, downY)) {
+                    mTouchOffset = downY - mThumbOffset.y;
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                // Check if we should start scrolling
+                if (!mIsDragging && isNearPoint(downX, downY) &&
+                        Math.abs(y - downY) > config.getScaledTouchSlop()) {
+                    mRv.getParent().requestDisallowInterceptTouchEvent(true);
+                    mIsDragging = true;
+                    mTouchOffset += (lastY - downY);
+                    mPopup.animateVisibility(true);
+                    animateScrollbar(true);
+                }
+                if (mIsDragging) {
+                    // Update the fastscroller section name at this touch position
+                    int top = mRv.getBackgroundPadding().top;
+                    int bottom = mRv.getHeight() - mRv.getBackgroundPadding().bottom - mThumbHeight;
+                    float boundedY = (float) Math.max(top, Math.min(bottom, y - mTouchOffset));
+                    String sectionName = mRv.scrollToPositionAtProgress((boundedY - top) /
+                            (bottom - top));
+                    mPopup.setSectionName(sectionName);
+                    mPopup.animateVisibility(!sectionName.isEmpty());
+                    mRv.invalidate(mPopup.updateFastScrollerBounds(mRv, lastY));
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mTouchOffset = 0;
+                if (mIsDragging) {
+                    mIsDragging = false;
+                    mPopup.animateVisibility(false);
+                    animateScrollbar(false);
+                }
+                break;
+        }
+    }
+
+    public void draw(Canvas canvas) {
+        if (mThumbOffset.x < 0 || mThumbOffset.y < 0) {
+            return;
+        }
+
+        // Draw the scroll bar track and thumb
+        if (mTrackPaint.getAlpha() > 0) {
+            canvas.drawRect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight(), mTrackPaint);
+        }
+        canvas.drawRect(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth,
+                mThumbOffset.y + mThumbHeight, mThumbPaint);
+
+        // Draw the popup
+        mPopup.draw(canvas);
+    }
+
+    /**
+     * Animates the width and color of the scrollbar.
+     */
+    private void animateScrollbar(boolean isScrolling) {
+        if (mScrollbarAnimator != null) {
+            mScrollbarAnimator.cancel();
+        }
+        ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha",
+                isScrolling ? MAX_TRACK_ALPHA : 0);
+        ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "width",
+                isScrolling ? mThumbMaxWidth : mThumbMinWidth);
+        ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(),
+                mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor);
+        colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animator) {
+                mThumbPaint.setColor((Integer) animator.getAnimatedValue());
+                mRv.invalidate(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth,
+                        mThumbOffset.y + mThumbHeight);
+            }
+        });
+        mScrollbarAnimator = new AnimatorSet();
+        mScrollbarAnimator.playTogether(trackAlphaAnim, thumbWidthAnim, colorAnimation);
+        mScrollbarAnimator.setDuration(SCROLL_BAR_VIS_DURATION);
+        mScrollbarAnimator.start();
+    }
+
+    /**
+     * Returns whether the specified points are near the scroll bar bounds.
+     */
+    private boolean isNearPoint(int x, int y) {
+        mTmpRect.set(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth,
+                mThumbOffset.y + mThumbHeight);
+        mTmpRect.inset(mTouchInset, mTouchInset);
+        return mTmpRect.contains(x, y);
+    }
+}
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
new file mode 100644
index 0000000..aeeb515
--- /dev/null
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollPopup.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+/**
+ * The fast scroller popup that shows the section name the list will jump to.
+ */
+public class BaseRecyclerViewFastScrollPopup {
+
+    private static final float FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR = 1.5f;
+
+    private Resources mRes;
+    private BaseRecyclerView mRv;
+
+    private Drawable mBg;
+    // The absolute bounds of the fast scroller bg
+    private Rect mBgBounds = new Rect();
+    private int mBgOriginalSize;
+    private Rect mInvalidateRect = new Rect();
+    private Rect mTmpRect = new Rect();
+
+    private String mSectionName;
+    private Paint mTextPaint;
+    private Rect mTextBounds = new Rect();
+    private float mAlpha;
+
+    private Animator mAlphaAnimator;
+    private boolean mVisible;
+
+    public BaseRecyclerViewFastScrollPopup(BaseRecyclerView rv, Resources res) {
+        mRes = res;
+        mRv = rv;
+        mBgOriginalSize = res.getDimensionPixelSize(R.dimen.container_fastscroll_popup_size);
+        mBg = res.getDrawable(R.drawable.container_fastscroll_popup_bg);
+        mBg.setBounds(0, 0, mBgOriginalSize, mBgOriginalSize);
+        mTextPaint = new Paint();
+        mTextPaint.setColor(Color.WHITE);
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setTextSize(res.getDimensionPixelSize(R.dimen.container_fastscroll_popup_text_size));
+    }
+
+    /**
+     * Sets the section name.
+     */
+    public void setSectionName(String sectionName) {
+        if (!sectionName.equals(mSectionName)) {
+            mSectionName = sectionName;
+            mTextPaint.getTextBounds(sectionName, 0, sectionName.length(), mTextBounds);
+            // Update the width to use measureText since that is more accurate
+            mTextBounds.right = (int) (mTextBounds.left + mTextPaint.measureText(sectionName));
+        }
+    }
+
+    /**
+     * Updates the bounds for the fast scroller.
+     * @return the invalidation rect for this update.
+     */
+    public Rect updateFastScrollerBounds(BaseRecyclerView rv, int lastTouchY) {
+        mInvalidateRect.set(mBgBounds);
+
+        if (isVisible()) {
+            // Calculate the dimensions and position of the fast scroller popup
+            int edgePadding = rv.getMaxScrollbarWidth();
+            int bgPadding = (mBgOriginalSize - mTextBounds.height()) / 2;
+            int bgHeight = mBgOriginalSize;
+            int bgWidth = Math.max(mBgOriginalSize, mTextBounds.width() + (2 * bgPadding));
+            if (Utilities.isRtl(mRes)) {
+                mBgBounds.left = rv.getBackgroundPadding().left + (2 * rv.getMaxScrollbarWidth());
+                mBgBounds.right = mBgBounds.left + bgWidth;
+            } else {
+                mBgBounds.right = rv.getWidth() - rv.getBackgroundPadding().right -
+                        (2 * rv.getMaxScrollbarWidth());
+                mBgBounds.left = mBgBounds.right - bgWidth;
+            }
+            mBgBounds.top = lastTouchY - (int) (FAST_SCROLL_OVERLAY_Y_OFFSET_FACTOR * bgHeight);
+            mBgBounds.top = Math.max(edgePadding,
+                    Math.min(mBgBounds.top, rv.getHeight() - edgePadding - bgHeight));
+            mBgBounds.bottom = mBgBounds.top + bgHeight;
+        } else {
+            mBgBounds.setEmpty();
+        }
+
+        // Combine the old and new fast scroller bounds to create the full invalidate rect
+        mInvalidateRect.union(mBgBounds);
+        return mInvalidateRect;
+    }
+
+    /**
+     * Animates the visibility of the fast scroller popup.
+     */
+    public void animateVisibility(boolean visible) {
+        if (mVisible != visible) {
+            mVisible = visible;
+            if (mAlphaAnimator != null) {
+                mAlphaAnimator.cancel();
+            }
+            mAlphaAnimator = ObjectAnimator.ofFloat(this, "alpha", visible ? 1f : 0f);
+            mAlphaAnimator.setDuration(visible ? 200 : 150);
+            mAlphaAnimator.start();
+        }
+    }
+
+    // Setter/getter for the popup alpha for animations
+    public void setAlpha(float alpha) {
+        mAlpha = alpha;
+        mRv.invalidate(mBgBounds);
+    }
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    public int getHeight() {
+        return mBgOriginalSize;
+    }
+
+    public void draw(Canvas c) {
+        if (isVisible()) {
+            // Draw the fast scroller popup
+            int restoreCount = c.save(Canvas.MATRIX_SAVE_FLAG);
+            c.translate(mBgBounds.left, mBgBounds.top);
+            mTmpRect.set(mBgBounds);
+            mTmpRect.offsetTo(0, 0);
+            mBg.setBounds(mTmpRect);
+            mBg.setAlpha((int) (mAlpha * 255));
+            mBg.draw(c);
+            mTextPaint.setAlpha((int) (mAlpha * 255));
+            c.drawText(mSectionName, (mBgBounds.width() - mTextBounds.width()) / 2,
+                    mBgBounds.height() - (mBgBounds.height() - mTextBounds.height()) / 2,
+                    mTextPaint);
+            c.restoreToCount(restoreCount);
+        }
+    }
+
+    public boolean isVisible() {
+        return (mAlpha > 0f) && (mSectionName != null);
+    }
+}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 07f3045..a0be8ea 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3;
 
+import android.animation.ObjectAnimator;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -23,22 +25,30 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.view.ViewParent;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.TextView;
+import com.android.launcher3.IconCache.IconLoadRequest;
+import com.android.launcher3.model.PackageItemInfo;
 
 /**
  * TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
  * because we want to make the bubble taller than the text and TextView's clip is
  * too aggressive.
  */
-public class BubbleTextView extends TextView {
+public class BubbleTextView extends TextView
+        implements BaseRecyclerViewFastScrollBar.FastScrollFocusableView {
 
     private static SparseArray<Theme> sPreloaderThemes = new SparseArray<Theme>(2);
 
@@ -47,25 +57,47 @@
     private static final float SHADOW_Y_OFFSET = 2.0f;
     private static final int SHADOW_LARGE_COLOUR = 0xDD000000;
     private static final int SHADOW_SMALL_COLOUR = 0xCC000000;
-    static final float PADDING_V = 3.0f;
 
-    private HolographicOutlineHelper mOutlineHelper;
+    private static final int DISPLAY_WORKSPACE = 0;
+    private static final int DISPLAY_ALL_APPS = 1;
+
+    private static final float FAST_SCROLL_FOCUS_MAX_SCALE = 1.15f;
+    private static final int FAST_SCROLL_FOCUS_MODE_NONE = 0;
+    private static final int FAST_SCROLL_FOCUS_MODE_SCALE_ICON = 1;
+    private static final int FAST_SCROLL_FOCUS_MODE_DRAW_CIRCLE_BG = 2;
+    private static final int FAST_SCROLL_FOCUS_FADE_IN_DURATION = 175;
+    private static final int FAST_SCROLL_FOCUS_FADE_OUT_DURATION = 125;
+
+    private final Launcher mLauncher;
+    private Drawable mIcon;
+    private final Drawable mBackground;
+    private final CheckLongPressHelper mLongPressHelper;
+    private final HolographicOutlineHelper mOutlineHelper;
+    private final StylusEventHelper mStylusEventHelper;
+
+    private boolean mBackgroundSizeChanged;
+
     private Bitmap mPressedBackground;
 
     private float mSlop;
 
-    private int mTextColor;
+    private final boolean mDeferShadowGenerationOnTouch;
     private final boolean mCustomShadowsEnabled;
-    private boolean mIsTextVisible;
-
-    // TODO: Remove custom background handling code, as no instance of BubbleTextView use any
-    // background.
-    private boolean mBackgroundSizeChanged;
-    private final Drawable mBackground;
+    private final boolean mLayoutHorizontal;
+    private final int mIconSize;
+    private int mTextColor;
 
     private boolean mStayPressed;
     private boolean mIgnorePressedStateChange;
-    private CheckLongPressHelper mLongPressHelper;
+    private boolean mDisableRelayout = false;
+
+    private ObjectAnimator mFastScrollFocusAnimator;
+    private Paint mFastScrollFocusBgPaint;
+    private float mFastScrollFocusFraction;
+    private boolean mFastScrollFocused;
+    private final int mFastScrollMode = FAST_SCROLL_FOCUS_MODE_SCALE_ICON;
+
+    private IconLoadRequest mIconLoadRequest;
 
     public BubbleTextView(Context context) {
         this(context, null, 0);
@@ -77,10 +109,28 @@
 
     public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        mLauncher = (Launcher) context;
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.BubbleTextView, defStyle, 0);
         mCustomShadowsEnabled = a.getBoolean(R.styleable.BubbleTextView_customShadows, true);
+        mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+        mDeferShadowGenerationOnTouch =
+                a.getBoolean(R.styleable.BubbleTextView_deferShadowGeneration, false);
+
+        int display = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
+        int defaultIconSize = grid.iconSizePx;
+        if (display == DISPLAY_WORKSPACE) {
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
+        } else if (display == DISPLAY_ALL_APPS) {
+            setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
+            defaultIconSize = grid.allAppsIconSizePx;
+        }
+
+        mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
+                defaultIconSize);
+
         a.recycle();
 
         if (mCustomShadowsEnabled) {
@@ -90,45 +140,37 @@
         } else {
             mBackground = null;
         }
-        init();
-    }
 
-    public void onFinishInflate() {
-        super.onFinishInflate();
-
-        // Ensure we are using the right text size
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
-    }
-
-    private void init() {
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
 
         mOutlineHelper = HolographicOutlineHelper.obtain(getContext());
         if (mCustomShadowsEnabled) {
             setShadowLayer(SHADOW_LARGE_RADIUS, 0.0f, SHADOW_Y_OFFSET, SHADOW_LARGE_COLOUR);
         }
+
+        if (mFastScrollMode == FAST_SCROLL_FOCUS_MODE_DRAW_CIRCLE_BG) {
+            mFastScrollFocusBgPaint = new Paint();
+            mFastScrollFocusBgPaint.setAntiAlias(true);
+            mFastScrollFocusBgPaint.setColor(
+                    getResources().getColor(R.color.container_fastscroll_thumb_active_color));
+        }
+
+        setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+    }
+
+    public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
+        applyFromShortcutInfo(info, iconCache, false);
     }
 
     public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
-            boolean setDefaultPadding) {
-        applyFromShortcutInfo(info, iconCache, setDefaultPadding, false);
-    }
-
-    public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache,
-            boolean setDefaultPadding, boolean promiseStateChanged) {
+            boolean promiseStateChanged) {
         Bitmap b = info.getIcon(iconCache);
-        LauncherAppState app = LauncherAppState.getInstance();
 
-        FastBitmapDrawable iconDrawable = Utilities.createIconDrawable(b);
+        FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b);
         iconDrawable.setGhostModeEnabled(info.isDisabled != 0);
 
-        setCompoundDrawables(null, iconDrawable, null, null);
-        if (setDefaultPadding) {
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
-        }
+        setIcon(iconDrawable, mIconSize);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
         }
@@ -141,20 +183,37 @@
     }
 
     public void applyFromApplicationInfo(AppInfo info) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
-        Drawable topDrawable = Utilities.createIconDrawable(info.iconBitmap);
-        topDrawable.setBounds(0, 0, grid.allAppsIconSizePx, grid.allAppsIconSizePx);
-        setCompoundDrawables(null, topDrawable, null, null);
-        setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
         setText(info.title);
         if (info.contentDescription != null) {
             setContentDescription(info.contentDescription);
         }
-        setTag(info);
+        // We don't need to check the info since it's not a ShortcutInfo
+        super.setTag(info);
+
+        // Verify high res immediately
+        verifyHighRes();
     }
 
+    public void applyFromPackageItemInfo(PackageItemInfo info) {
+        setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
+        setText(info.title);
+        if (info.contentDescription != null) {
+            setContentDescription(info.contentDescription);
+        }
+        // We don't need to check the info since it's not a ShortcutInfo
+        super.setTag(info);
+
+        // Verify high res immediately
+        verifyHighRes();
+    }
+
+    /**
+     * Overrides the default long press timeout.
+     */
+    public void setLongPressTimeout(int longPressTimeout) {
+        mLongPressHelper.setLongPressTimeout(longPressTimeout);
+    }
 
     @Override
     protected boolean setFrame(int left, int top, int right, int bottom) {
@@ -186,10 +245,19 @@
         }
     }
 
+    /** Returns the icon for this view. */
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /** Returns whether the layout is horizontal. */
+    public boolean isLayoutHorizontal() {
+        return mLayoutHorizontal;
+    }
+
     private void updateIconState() {
-        Drawable top = getCompoundDrawables()[1];
-        if (top instanceof FastBitmapDrawable) {
-            ((FastBitmapDrawable) top).setPressed(isPressed() || mStayPressed);
+        if (mIcon instanceof FastBitmapDrawable) {
+            ((FastBitmapDrawable) mIcon).setPressed(isPressed() || mStayPressed);
         }
     }
 
@@ -199,16 +267,25 @@
         // isPressed() on an ACTION_UP
         boolean result = super.onTouchEvent(event);
 
+        // Check for a stylus button press, if it occurs cancel any long press checks.
+        if (mStylusEventHelper.checkAndPerformStylusEvent(event)) {
+            mLongPressHelper.cancelLongPress();
+            result = true;
+        }
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 // So that the pressed outline is visible immediately on setStayPressed(),
                 // we pre-create it on ACTION_DOWN (it takes a small but perceptible amount of time
                 // to create it)
-                if (mPressedBackground == null) {
+                if (!mDeferShadowGenerationOnTouch && mPressedBackground == null) {
                     mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
                 }
 
-                mLongPressHelper.postCheckForLongPress();
+                // If we're in a stylus button press, don't check for long press.
+                if (!mStylusEventHelper.inStylusButtonPressed()) {
+                    mLongPressHelper.postCheckForLongPress();
+                }
                 break;
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
@@ -233,12 +310,17 @@
         mStayPressed = stayPressed;
         if (!stayPressed) {
             mPressedBackground = null;
+        } else {
+            if (mPressedBackground == null) {
+                mPressedBackground = mOutlineHelper.createMediumDropShadow(this);
+            }
         }
 
         // Only show the shadow effect when persistent pressed state is set.
-        if (getParent() instanceof ShortcutAndWidgetContainer) {
-            CellLayout layout = (CellLayout) getParent().getParent();
-            layout.setPressedIcon(this, mPressedBackground, mOutlineHelper.shadowBitmapPadding);
+        ViewParent parent = getParent();
+        if (parent != null && parent.getParent() instanceof BubbleTextShadowHandler) {
+            ((BubbleTextShadowHandler) parent.getParent()).setPressedIcon(
+                    this, mPressedBackground);
         }
 
         updateIconState();
@@ -278,7 +360,18 @@
     @Override
     public void draw(Canvas canvas) {
         if (!mCustomShadowsEnabled) {
+            // Draw the fast scroll focus bg if we have one
+            if (mFastScrollMode == FAST_SCROLL_FOCUS_MODE_DRAW_CIRCLE_BG &&
+                    mFastScrollFocusFraction > 0f) {
+                DeviceProfile grid = mLauncher.getDeviceProfile();
+                int iconCenterX = getScrollX() + (getWidth() / 2);
+                int iconCenterY = getScrollY() + getPaddingTop() + (grid.iconSizePx / 2);
+                canvas.drawCircle(iconCenterX, iconCenterY,
+                        mFastScrollFocusFraction * (getWidth() / 2), mFastScrollFocusBgPaint);
+            }
+
             super.draw(canvas);
+
             return;
         }
 
@@ -325,10 +418,9 @@
         super.onAttachedToWindow();
 
         if (mBackground != null) mBackground.setCallback(this);
-        Drawable top = getCompoundDrawables()[1];
 
-        if (top instanceof PreloadIconDrawable) {
-            ((PreloadIconDrawable) top).applyTheme(getPreloaderTheme());
+        if (mIcon instanceof PreloadIconDrawable) {
+            ((PreloadIconDrawable) mIcon).applyPreloaderTheme(getPreloaderTheme());
         }
         mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
     }
@@ -358,16 +450,6 @@
         } else {
             super.setTextColor(res.getColor(android.R.color.transparent));
         }
-        mIsTextVisible = visible;
-    }
-
-    public boolean isTextVisible() {
-        return mIsTextVisible;
-    }
-
-    @Override
-    protected boolean onSetAlpha(int alpha) {
-        return true;
     }
 
     @Override
@@ -385,15 +467,13 @@
                     ((info.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
                             info.getInstallProgress() : 0)) : 100;
 
-            Drawable[] drawables = getCompoundDrawables();
-            Drawable top = drawables[1];
-            if (top != null) {
+            if (mIcon != null) {
                 final PreloadIconDrawable preloadDrawable;
-                if (top instanceof PreloadIconDrawable) {
-                    preloadDrawable = (PreloadIconDrawable) top;
+                if (mIcon instanceof PreloadIconDrawable) {
+                    preloadDrawable = (PreloadIconDrawable) mIcon;
                 } else {
-                    preloadDrawable = new PreloadIconDrawable(top, getPreloaderTheme());
-                    setCompoundDrawables(drawables[0], preloadDrawable, drawables[2], drawables[3]);
+                    preloadDrawable = new PreloadIconDrawable(mIcon, getPreloaderTheme());
+                    setIcon(preloadDrawable, mIconSize);
                 }
 
                 preloadDrawable.setLevel(progressLevel);
@@ -417,4 +497,132 @@
         }
         return theme;
     }
+
+    /**
+     * Sets the icon for this view based on the layout direction.
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    private Drawable setIcon(Drawable icon, int iconSize) {
+        mIcon = icon;
+        if (iconSize != -1) {
+            mIcon.setBounds(0, 0, iconSize, iconSize);
+        }
+        if (mLayoutHorizontal) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                setCompoundDrawablesRelative(mIcon, null, null, null);
+            } else {
+                setCompoundDrawables(mIcon, null, null, null);
+            }
+        } else {
+            setCompoundDrawables(null, mIcon, null, null);
+        }
+        return icon;
+    }
+
+    @Override
+    public void requestLayout() {
+        if (!mDisableRelayout) {
+            super.requestLayout();
+        }
+    }
+
+    /**
+     * Applies the item info if it is same as what the view is pointing to currently.
+     */
+    public void reapplyItemInfo(final ItemInfo info) {
+        if (getTag() == info) {
+            mIconLoadRequest = null;
+            mDisableRelayout = true;
+            if (info instanceof AppInfo) {
+                applyFromApplicationInfo((AppInfo) info);
+            } else if (info instanceof ShortcutInfo) {
+                applyFromShortcutInfo((ShortcutInfo) info,
+                        LauncherAppState.getInstance().getIconCache());
+            } else if (info instanceof PackageItemInfo) {
+                applyFromPackageItemInfo((PackageItemInfo) info);
+            }
+            mDisableRelayout = false;
+        }
+    }
+
+    /**
+     * Verifies that the current icon is high-res otherwise posts a request to load the icon.
+     */
+    public void verifyHighRes() {
+        if (mIconLoadRequest != null) {
+            mIconLoadRequest.cancel();
+            mIconLoadRequest = null;
+        }
+        if (getTag() instanceof AppInfo) {
+            AppInfo info = (AppInfo) getTag();
+            if (info.usingLowResIcon) {
+                mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
+                        .updateIconInBackground(BubbleTextView.this, info);
+            }
+        } else if (getTag() instanceof ShortcutInfo) {
+            ShortcutInfo info = (ShortcutInfo) getTag();
+            if (info.usingLowResIcon) {
+                mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
+                        .updateIconInBackground(BubbleTextView.this, info);
+            }
+        } else if (getTag() instanceof PackageItemInfo) {
+            PackageItemInfo info = (PackageItemInfo) getTag();
+            if (info.usingLowResIcon) {
+                mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
+                        .updateIconInBackground(BubbleTextView.this, info);
+            }
+        }
+    }
+
+    // Setters & getters for the animation
+    public void setFastScrollFocus(float fraction) {
+        mFastScrollFocusFraction = fraction;
+        if (mFastScrollMode == FAST_SCROLL_FOCUS_MODE_SCALE_ICON) {
+            setScaleX(1f + fraction * (FAST_SCROLL_FOCUS_MAX_SCALE - 1f));
+            setScaleY(1f + fraction * (FAST_SCROLL_FOCUS_MAX_SCALE - 1f));
+        } else {
+            invalidate();
+        }
+    }
+
+    public float getFastScrollFocus() {
+        return mFastScrollFocusFraction;
+    }
+
+    @Override
+    public void setFastScrollFocused(final boolean focused, boolean animated) {
+        if (mFastScrollMode == FAST_SCROLL_FOCUS_MODE_NONE) {
+            return;
+        }
+
+        if (mFastScrollFocused != focused) {
+            mFastScrollFocused = focused;
+
+            if (animated) {
+                // Clean up the previous focus animator
+                if (mFastScrollFocusAnimator != null) {
+                    mFastScrollFocusAnimator.cancel();
+                }
+                mFastScrollFocusAnimator = ObjectAnimator.ofFloat(this, "fastScrollFocus",
+                        focused ? 1f : 0f);
+                if (focused) {
+                    mFastScrollFocusAnimator.setInterpolator(new DecelerateInterpolator());
+                } else {
+                    mFastScrollFocusAnimator.setInterpolator(new AccelerateInterpolator());
+                }
+                mFastScrollFocusAnimator.setDuration(focused ?
+                        FAST_SCROLL_FOCUS_FADE_IN_DURATION : FAST_SCROLL_FOCUS_FADE_OUT_DURATION);
+                mFastScrollFocusAnimator.start();
+            } else {
+                mFastScrollFocusFraction = focused ? 1f : 0f;
+            }
+        }
+    }
+
+    /**
+     * Interface to be implemented by the grand parent to allow click shadow effect.
+     */
+    public static interface BubbleTextShadowHandler {
+        void setPressedIcon(BubbleTextView icon, Bitmap background);
+    }
 }
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 019f86c..b7f89d0 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -16,26 +16,41 @@
 
 package com.android.launcher3;
 
+import android.animation.AnimatorSet;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.Context;
-import android.content.res.Resources;
+import android.content.res.ColorStateList;
+import android.content.res.Configuration;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
 
 /**
  * Implements a DropTarget.
  */
-public class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
+public abstract class ButtonDropTarget extends TextView
+        implements DropTarget, DragController.DragListener, OnClickListener {
 
-    protected final int mTransitionDuration;
+    private static int DRAG_VIEW_DROP_DURATION = 285;
 
     protected Launcher mLauncher;
     private int mBottomDragPadding;
-    protected TextView mText;
     protected SearchDropTargetBar mSearchDropTargetBar;
 
     /** Whether this drop target is active for the current drag */
@@ -44,71 +59,196 @@
     /** The paint applied to the drag view on hover */
     protected int mHoverColor = 0;
 
+    protected ColorStateList mOriginalTextColor;
+    protected Drawable mDrawable;
+
+    private AnimatorSet mCurrentColorAnim;
+    @Thunk ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
+
+
     public ButtonDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
     public ButtonDropTarget(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
-        Resources r = getResources();
-        mTransitionDuration = r.getInteger(R.integer.config_dropTargetBgTransitionDuration);
-        mBottomDragPadding = r.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
+        mBottomDragPadding = getResources().getDimensionPixelSize(R.dimen.drop_target_drag_padding);
     }
 
-    void setLauncher(Launcher launcher) {
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mOriginalTextColor = getTextColors();
+
+        // Remove the text in the Phone UI in landscape
+        DeviceProfile grid = ((Launcher) getContext()).getDeviceProfile();
+        if (grid.isVerticalBarLayout()) {
+            setText("");
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    protected void setDrawable(int resId) {
+        // We do not set the drawable in the xml as that inflates two drawables corresponding to
+        // drawableLeft and drawableStart.
+        mDrawable = getResources().getDrawable(resId);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
+        } else {
+            setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null, null);
+        }
+    }
+
+    public void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }
 
-    public boolean acceptDrop(DragObject d) {
-        return false;
-    }
-
     public void setSearchDropTargetBar(SearchDropTargetBar searchDropTargetBar) {
         mSearchDropTargetBar = searchDropTargetBar;
     }
 
-    protected Drawable getCurrentDrawable() {
-        Drawable[] drawables = getCompoundDrawablesRelative();
-        for (int i = 0; i < drawables.length; ++i) {
-            if (drawables[i] != null) {
-                return drawables[i];
-            }
-        }
-        return null;
-    }
+    @Override
+    public void onFlingToDelete(DragObject d, PointF vec) { }
 
-    public void onDrop(DragObject d) {
-    }
-
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
-        // Do nothing
-    }
-
-    public void onDragEnter(DragObject d) {
+    @Override
+    public final void onDragEnter(DragObject d) {
         d.dragView.setColor(mHoverColor);
+        if (Utilities.isLmpOrAbove()) {
+            animateTextColor(mHoverColor);
+        } else {
+            if (mCurrentFilter == null) {
+                mCurrentFilter = new ColorMatrix();
+            }
+            DragView.setColorScale(mHoverColor, mCurrentFilter);
+            mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+            setTextColor(mHoverColor);
+        }
     }
 
+    @Override
     public void onDragOver(DragObject d) {
         // Do nothing
     }
 
-    public void onDragExit(DragObject d) {
-        d.dragView.setColor(0);
+	protected void resetHoverColor() {
+        if (Utilities.isLmpOrAbove()) {
+            animateTextColor(mOriginalTextColor.getDefaultColor());
+        } else {
+            mDrawable.setColorFilter(null);
+            setTextColor(mOriginalTextColor);
+        }
     }
 
-    public void onDragStart(DragSource source, Object info, int dragAction) {
-        // Do nothing
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void animateTextColor(int targetColor) {
+        if (mCurrentColorAnim != null) {
+            mCurrentColorAnim.cancel();
+        }
+
+        mCurrentColorAnim = new AnimatorSet();
+        mCurrentColorAnim.setDuration(DragView.COLOR_CHANGE_DURATION);
+
+        if (mSrcFilter == null) {
+            mSrcFilter = new ColorMatrix();
+            mDstFilter = new ColorMatrix();
+            mCurrentFilter = new ColorMatrix();
+        }
+
+        DragView.setColorScale(getTextColor(), mSrcFilter);
+        DragView.setColorScale(targetColor, mDstFilter);
+        ValueAnimator anim1 = ValueAnimator.ofObject(
+                new FloatArrayEvaluator(mCurrentFilter.getArray()),
+                mSrcFilter.getArray(), mDstFilter.getArray());
+        anim1.addUpdateListener(new AnimatorUpdateListener() {
+
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+                invalidate();
+            }
+        });
+
+        mCurrentColorAnim.play(anim1);
+        mCurrentColorAnim.play(ObjectAnimator.ofArgb(this, "textColor", targetColor));
+        mCurrentColorAnim.start();
     }
 
+    @Override
+    public final void onDragExit(DragObject d) {
+        if (!d.dragComplete) {
+            d.dragView.setColor(0);
+            resetHoverColor();
+        } else {
+            // Restore the hover color
+            d.dragView.setColor(mHoverColor);
+        }
+    }
+
+	@Override
+    public final void onDragStart(DragSource source, Object info, int dragAction) {
+        mActive = supportsDrop(source, info);
+        mDrawable.setColorFilter(null);
+        if (mCurrentColorAnim != null) {
+            mCurrentColorAnim.cancel();
+            mCurrentColorAnim = null;
+        }
+        setTextColor(mOriginalTextColor);
+        ((ViewGroup) getParent()).setVisibility(mActive ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public final boolean acceptDrop(DragObject dragObject) {
+        return supportsDrop(dragObject.dragSource, dragObject.dragInfo);
+    }
+
+    protected abstract boolean supportsDrop(DragSource source, Object info);
+
+    @Override
     public boolean isDropEnabled() {
         return mActive;
     }
 
+    @Override
     public void onDragEnd() {
-        // Do nothing
+        mActive = false;
     }
 
+    /**
+     * On drop animate the dropView to the icon.
+     */
+    @Override
+    public void onDrop(final DragObject d) {
+        final DragLayer dragLayer = mLauncher.getDragLayer();
+        final Rect from = new Rect();
+        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
+
+        int width = mDrawable.getIntrinsicWidth();
+        int height = mDrawable.getIntrinsicHeight();
+        final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
+                width, height);
+        final float scale = (float) to.width() / from.width();
+        mSearchDropTargetBar.deferOnDragEnd();
+
+        Runnable onAnimationEndRunnable = new Runnable() {
+            @Override
+            public void run() {
+                completeDrop(d);
+                mSearchDropTargetBar.onDragEnd();
+                mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null);
+            }
+        };
+        dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
+                DRAG_VIEW_DROP_DURATION, new DecelerateInterpolator(2),
+                new LinearInterpolator(), onAnimationEndRunnable,
+                DragLayer.ANIMATION_END_DISAPPEAR, null);
+    }
+
+    @Override
+    public void prepareAccessibilityDrop() { }
+
+    @Thunk abstract void completeDrop(DragObject d);
+
     @Override
     public void getHitRectRelativeToDragLayer(android.graphics.Rect outRect) {
         super.getHitRect(outRect);
@@ -119,11 +259,7 @@
         outRect.offsetTo(coords[0], coords[1]);
     }
 
-    private boolean isRtl() {
-        return (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
-    }
-
-    Rect getIconRect(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight) {
+    protected Rect getIconRect(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight) {
         DragLayer dragLayer = mLauncher.getDragLayer();
 
         // Find the rect to animate to (the view is center aligned)
@@ -136,7 +272,7 @@
         final int left;
         final int right;
 
-        if (isRtl()) {
+        if (Utilities.isRtl(getResources())) {
             right = to.right - getPaddingRight();
             left = right - width;
         } else {
@@ -157,7 +293,26 @@
         return to;
     }
 
+    @Override
     public void getLocationInDragLayer(int[] loc) {
         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
     }
+
+    public void enableAccessibleDrag(boolean enable) {
+        setOnClickListener(enable ? this : null);
+    }
+
+    protected String getAccessibilityDropConfirmation() {
+        return null;
+    }
+
+    @Override
+    public void onClick(View v) {
+        LauncherAppState.getInstance().getAccessibilityDelegate()
+            .handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
+    }
+
+    public int getTextColor() {
+        return getTextColors().getDefaultColor();
+    }
 }
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 0ff1ef4..8096887 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -22,6 +22,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -33,7 +34,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.os.Build;
 import android.os.Parcelable;
+import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -41,11 +45,16 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
-import android.view.animation.Animation;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
 
+import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
+import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate;
+import com.android.launcher3.accessibility.FolderAccessibilityHelper;
+import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -54,55 +63,47 @@
 import java.util.HashMap;
 import java.util.Stack;
 
-public class CellLayout extends ViewGroup {
+public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
+    public static final int WORKSPACE_ACCESSIBILITY_DRAG = 2;
+    public static final int FOLDER_ACCESSIBILITY_DRAG = 1;
+
     static final String TAG = "CellLayout";
 
     private Launcher mLauncher;
-    private int mCellWidth;
-    private int mCellHeight;
+    @Thunk int mCellWidth;
+    @Thunk int mCellHeight;
     private int mFixedCellWidth;
     private int mFixedCellHeight;
 
-    private int mCountX;
-    private int mCountY;
+    @Thunk int mCountX;
+    @Thunk int mCountY;
 
     private int mOriginalWidthGap;
     private int mOriginalHeightGap;
-    private int mWidthGap;
-    private int mHeightGap;
+    @Thunk int mWidthGap;
+    @Thunk int mHeightGap;
     private int mMaxGap;
     private boolean mDropPending = false;
     private boolean mIsDragTarget = true;
 
     // These are temporary variables to prevent having to allocate a new object just to
     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
-    private final int[] mTmpXY = new int[2];
-    private final int[] mTmpPoint = new int[2];
-    int[] mTempLocation = new int[2];
+    @Thunk final int[] mTmpPoint = new int[2];
+    @Thunk final int[] mTempLocation = new int[2];
 
     boolean[][] mOccupied;
     boolean[][] mTmpOccupied;
-    private boolean mLastDownOnOccupiedCell = false;
 
     private OnTouchListener mInterceptTouchListener;
+    private StylusEventHelper mStylusEventHelper;
 
     private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
     private int[] mFolderLeaveBehindCell = {-1, -1};
 
-    private float FOREGROUND_ALPHA_DAMPER = 0.65f;
-    private int mForegroundAlpha = 0;
     private float mBackgroundAlpha;
-    private float mBackgroundAlphaMultiplier = 1.0f;
-    private boolean mDrawBackground = true;
 
-    private Drawable mNormalBackground;
-    private Drawable mActiveGlowBackground;
-    private Drawable mOverScrollForegroundDrawable;
-    private Drawable mOverScrollLeft;
-    private Drawable mOverScrollRight;
-    private Rect mBackgroundRect;
-    private Rect mForegroundRect;
-    private int mForegroundPadding;
+    private static final int BACKGROUND_ACTIVATE_DURATION = 120;
+    private final TransitionDrawable mBackground;
 
     // These values allow a fixed measurement to be set on the CellLayout.
     private int mFixedWidth = -1;
@@ -110,12 +111,11 @@
 
     // If we're actively dragging something over this screen, mIsDragOverlapping is true
     private boolean mIsDragOverlapping = false;
-    boolean mUseActiveGlowBackground = false;
 
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
-    private Rect[] mDragOutlines = new Rect[4];
-    private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
+    @Thunk Rect[] mDragOutlines = new Rect[4];
+    @Thunk float[] mDragOutlineAlphas = new float[mDragOutlines.length];
     private InterruptibleInOutAnimator[] mDragOutlineAnims =
             new InterruptibleInOutAnimator[mDragOutlines.length];
 
@@ -123,12 +123,10 @@
     private int mDragOutlineCurrent = 0;
     private final Paint mDragOutlinePaint = new Paint();
 
-    private final FastBitmapView mTouchFeedbackView;
+    private final ClickShadowView mTouchFeedbackView;
 
-    private HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new
-            HashMap<CellLayout.LayoutParams, Animator>();
-    private HashMap<View, ReorderPreviewAnimation>
-            mShakeAnimators = new HashMap<View, ReorderPreviewAnimation>();
+    @Thunk HashMap<CellLayout.LayoutParams, Animator> mReorderAnimators = new HashMap<>();
+    @Thunk HashMap<View, ReorderPreviewAnimation> mShakeAnimators = new HashMap<>();
 
     private boolean mItemPlacementDirty = false;
 
@@ -156,19 +154,22 @@
 
     private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
     private static final int REORDER_ANIMATION_DURATION = 150;
-    private float mReorderPreviewAnimationMagnitude;
+    @Thunk float mReorderPreviewAnimationMagnitude;
 
     private ArrayList<View> mIntersectingViews = new ArrayList<View>();
     private Rect mOccupiedRect = new Rect();
     private int[] mDirectionVector = new int[2];
     int[] mPreviousReorderDirection = new int[2];
     private static final int INVALID_DIRECTION = -100;
-    private DropTarget.DragEnforcer mDragEnforcer;
 
-    private Rect mTempRect = new Rect();
+    private final Rect mTempRect = new Rect();
 
     private final static Paint sPaint = new Paint();
 
+    // Related to accessible drag and drop
+    private DragAndDropAccessibilityDelegate mTouchHelper;
+    private boolean mUseTouchHelper = false;
+
     public CellLayout(Context context) {
         this(context, null);
     }
@@ -179,7 +180,6 @@
 
     public CellLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mDragEnforcer = new DropTarget.DragEnforcer(context);
 
         // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
         // the user where a dragged item will land when dropped.
@@ -187,8 +187,7 @@
         setClipToPadding(false);
         mLauncher = (Launcher) context;
 
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
 
         mCellWidth = mCellHeight = -1;
@@ -196,8 +195,8 @@
         mWidthGap = mOriginalWidthGap = 0;
         mHeightGap = mOriginalHeightGap = 0;
         mMaxGap = Integer.MAX_VALUE;
-        mCountX = (int) grid.numColumns;
-        mCountY = (int) grid.numRows;
+        mCountX = (int) grid.inv.numColumns;
+        mCountY = (int) grid.inv.numRows;
         mOccupied = new boolean[mCountX][mCountY];
         mTmpOccupied = new boolean[mCountX][mCountY];
         mPreviousReorderDirection[0] = INVALID_DIRECTION;
@@ -210,20 +209,12 @@
         final Resources res = getResources();
         mHotseatScale = (float) grid.hotseatIconSizePx / grid.iconSizePx;
 
-        mNormalBackground = res.getDrawable(R.drawable.screenpanel);
-        mActiveGlowBackground = res.getDrawable(R.drawable.screenpanel_hover);
-
-        mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);
-        mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);
-        mForegroundPadding =
-                res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);
+        mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel);
+        mBackground.setCallback(this);
 
         mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE *
                 grid.iconSizePx);
 
-        mNormalBackground.setFilterBitmap(true);
-        mActiveGlowBackground.setFilterBitmap(true);
-
         // Initialize the data structures used for the drag visualization.
         mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease out
         mDragCell[0] = mDragCell[1] = -1;
@@ -281,19 +272,78 @@
             mDragOutlineAnims[i] = anim;
         }
 
-        mBackgroundRect = new Rect();
-        mForegroundRect = new Rect();
-
         mShortcutsAndWidgets = new ShortcutAndWidgetContainer(context);
         mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap,
                 mCountX, mCountY);
 
-        mTouchFeedbackView = new FastBitmapView(context);
-        // Make the feedback view large enough to hold the blur bitmap.
-        addView(mTouchFeedbackView, (int) (grid.cellWidthPx * 1.5), (int) (grid.cellHeightPx * 1.5));
+        mStylusEventHelper = new StylusEventHelper(this);
+
+        mTouchFeedbackView = new ClickShadowView(context);
+        addView(mTouchFeedbackView);
         addView(mShortcutsAndWidgets);
     }
 
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public void enableAccessibleDrag(boolean enable, int dragType) {
+        mUseTouchHelper = enable;
+        if (!enable) {
+            ViewCompat.setAccessibilityDelegate(this, null);
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+            getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+            setOnClickListener(mLauncher);
+        } else {
+            if (dragType == WORKSPACE_ACCESSIBILITY_DRAG &&
+                    !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) {
+                mTouchHelper = new WorkspaceAccessibilityHelper(this);
+            } else if (dragType == FOLDER_ACCESSIBILITY_DRAG &&
+                    !(mTouchHelper instanceof FolderAccessibilityHelper)) {
+                mTouchHelper = new FolderAccessibilityHelper(this);
+            }
+            ViewCompat.setAccessibilityDelegate(this, mTouchHelper);
+            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            setOnClickListener(mTouchHelper);
+        }
+
+        // Invalidate the accessibility hierarchy
+        if (getParent() != null) {
+            getParent().notifySubtreeAccessibilityStateChanged(
+                    this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
+        }
+    }
+
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Always attempt to dispatch hover events to accessibility first.
+        if (mUseTouchHelper && mTouchHelper.dispatchHoverEvent(event)) {
+            return true;
+        }
+        return super.dispatchHoverEvent(event);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (mUseTouchHelper ||
+                (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = super.onTouchEvent(ev);
+        // Stylus button press on a home screen should not switch between overview mode and
+        // the home screen mode, however, once in overview mode stylus button press should be
+        // enabled to allow rearranging the different home screens. So check what mode
+        // the workspace is in, and only perform stylus button presses while in overview mode.
+        if (mLauncher.mWorkspace.isInOverviewMode()
+                && mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            return true;
+        }
+        return handled;
+    }
+
     public void enableHardwareLayer(boolean hasLayer) {
         mShortcutsAndWidgets.setLayerType(hasLayer ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, sPaint);
     }
@@ -337,47 +387,19 @@
         return mDropPending;
     }
 
-    void setOverScrollAmount(float r, boolean left) {
-        if (left && mOverScrollForegroundDrawable != mOverScrollLeft) {
-            mOverScrollForegroundDrawable = mOverScrollLeft;
-        } else if (!left && mOverScrollForegroundDrawable != mOverScrollRight) {
-            mOverScrollForegroundDrawable = mOverScrollRight;
-        }
-
-        r *= FOREGROUND_ALPHA_DAMPER;
-        mForegroundAlpha = (int) Math.round((r * 255));
-        mOverScrollForegroundDrawable.setAlpha(mForegroundAlpha);
-        invalidate();
-    }
-
-    void setPressedIcon(BubbleTextView icon, Bitmap background, int padding) {
+    @Override
+    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
         if (icon == null || background == null) {
             mTouchFeedbackView.setBitmap(null);
             mTouchFeedbackView.animate().cancel();
         } else {
-            int offset = getMeasuredWidth() - getPaddingLeft() - getPaddingRight()
-                    - (mCountX * mCellWidth);
-            mTouchFeedbackView.setTranslationX(icon.getLeft() + (int) Math.ceil(offset / 2f)
-                    - padding);
-            mTouchFeedbackView.setTranslationY(icon.getTop() - padding);
             if (mTouchFeedbackView.setBitmap(background)) {
-                mTouchFeedbackView.setAlpha(0);
-                mTouchFeedbackView.animate().alpha(1)
-                    .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION)
-                    .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR)
-                    .start();
+                mTouchFeedbackView.alignWithIconView(icon, mShortcutsAndWidgets);
+                mTouchFeedbackView.animateShadow();
             }
         }
     }
 
-    void setUseActiveGlowBackground(boolean use) {
-        mUseActiveGlowBackground = use;
-    }
-
-    void disableBackground() {
-        mDrawBackground = false;
-    }
-
     void disableDragTarget() {
         mIsDragTarget = false;
     }
@@ -389,7 +411,11 @@
     void setIsDragOverlapping(boolean isDragOverlapping) {
         if (mIsDragOverlapping != isDragOverlapping) {
             mIsDragOverlapping = isDragOverlapping;
-            setUseActiveGlowBackground(mIsDragOverlapping);
+            if (mIsDragOverlapping) {
+                mBackground.startTransition(BACKGROUND_ACTIVATE_DURATION);
+            } else {
+                mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION);
+            }
             invalidate();
         }
     }
@@ -400,24 +426,17 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if (!mIsDragTarget) {
+            return;
+        }
+
         // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
         // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
         // When we're small, we are either drawn normally or in the "accepts drops" state (during
         // a drag). However, we also drag the mini hover background *over* one of those two
         // backgrounds
-        if (mDrawBackground && mBackgroundAlpha > 0.0f) {
-            Drawable bg;
-
-            if (mUseActiveGlowBackground) {
-                // In the mini case, we draw the active_glow bg *over* the active background
-                bg = mActiveGlowBackground;
-            } else {
-                bg = mNormalBackground;
-            }
-
-            bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
-            bg.setBounds(mBackgroundRect);
-            bg.draw(canvas);
+        if (mBackgroundAlpha > 0.0f) {
+            mBackground.draw(canvas);
         }
 
         final Paint paint = mDragOutlinePaint;
@@ -453,8 +472,7 @@
         int previewOffset = FolderRingAnimator.sPreviewSize;
 
         // The folder outer / inner ring image(s)
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         for (int i = 0; i < mFolderOuterRings.size(); i++) {
             FolderRingAnimator fra = mFolderOuterRings.get(i);
 
@@ -513,15 +531,6 @@
         }
     }
 
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-        if (mForegroundAlpha > 0) {
-            mOverScrollForegroundDrawable.setBounds(mForegroundRect);
-            mOverScrollForegroundDrawable.draw(canvas);
-        }
-    }
-
     public void showFolderAccept(FolderRingAnimator fra) {
         mFolderOuterRings.add(fra);
     }
@@ -578,11 +587,11 @@
         mInterceptTouchListener = listener;
     }
 
-    int getCountX() {
+    public int getCountX() {
         return mCountX;
     }
 
-    int getCountY() {
+    public int getCountY() {
         return mCountY;
     }
 
@@ -591,6 +600,10 @@
         mShortcutsAndWidgets.setIsHotseat(isHotseat);
     }
 
+    public boolean isHotseat() {
+        return mIsHotseat;
+    }
+
     public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
             boolean markCells) {
         final LayoutParams lp = params;
@@ -613,7 +626,6 @@
             if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
 
             child.setId(childId);
-
             mShortcutsAndWidgets.addView(child, index, lp);
 
             if (markCells) markCellsAsOccupiedForView(child);
@@ -637,10 +649,6 @@
         }
     }
 
-    public void removeViewWithoutMarkingCells(View view) {
-        mShortcutsAndWidgets.removeView(view);
-    }
-
     @Override
     public void removeView(View view) {
         markCellsAsUnoccupiedForView(view);
@@ -675,25 +683,13 @@
         mShortcutsAndWidgets.removeViewsInLayout(start, count);
     }
 
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // First we clear the tag to ensure that on every touch down we start with a fresh slate,
-        // even in the case where we return early. Not clearing here was causing bugs whereby on
-        // long-press we'd end up picking up an item from a previous drag operation.
-        if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
-            return true;
-        }
-
-        return false;
-    }
-
     /**
      * Given a point, return the cell that strictly encloses that point
      * @param x X coordinate of the point
      * @param y Y coordinate of the point
      * @param result Array of 2 ints to hold the x and y coordinate of the cell
      */
-    void pointToCellExact(int x, int y, int[] result) {
+    public void pointToCellExact(int x, int y, int[] result) {
         final int hStartPadding = getPaddingLeft();
         final int vStartPadding = getPaddingTop();
 
@@ -782,9 +778,7 @@
 
     public float getDistanceFromCell(float x, float y, int[] cell) {
         cellToCenterPoint(cell[0], cell[1], mTmpPoint);
-        float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
-                Math.pow(y - mTmpPoint[1], 2));
-        return distance;
+        return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
     }
 
     int getCellWidth() {
@@ -803,28 +797,6 @@
         return mHeightGap;
     }
 
-    Rect getContentRect(Rect r) {
-        if (r == null) {
-            r = new Rect();
-        }
-        int left = getPaddingLeft();
-        int top = getPaddingTop();
-        int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
-        int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
-        r.set(left, top, right, bottom);
-        return r;
-    }
-
-    /** Return a rect that has the cellWidth/cellHeight (left, top), and
-     * widthGap/heightGap (right, bottom) */
-    static void getMetrics(Rect metrics, int paddedMeasureWidth,
-            int paddedMeasureHeight, int countX, int countY) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX),
-                grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0);
-    }
-
     public void setFixedSize(int width, int height) {
         mFixedWidth = width;
         mFixedHeight = height;
@@ -832,9 +804,6 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
         int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
         int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
         int widthSize = MeasureSpec.getSize(widthMeasureSpec);
@@ -842,8 +811,8 @@
         int childWidthSize = widthSize - (getPaddingLeft() + getPaddingRight());
         int childHeightSize = heightSize - (getPaddingTop() + getPaddingBottom());
         if (mFixedCellWidth < 0 || mFixedCellHeight < 0) {
-            int cw = grid.calculateCellWidth(childWidthSize, mCountX);
-            int ch = grid.calculateCellHeight(childHeightSize, mCountY);
+            int cw = DeviceProfile.calculateCellWidth(childWidthSize, mCountX);
+            int ch = DeviceProfile.calculateCellHeight(childHeightSize, mCountY);
             if (cw != mCellWidth || ch != mCellHeight) {
                 mCellWidth = cw;
                 mCellHeight = ch;
@@ -877,19 +846,20 @@
             mWidthGap = mOriginalWidthGap;
             mHeightGap = mOriginalHeightGap;
         }
-        int count = getChildCount();
-        int maxWidth = 0;
-        int maxHeight = 0;
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth,
-                    MeasureSpec.EXACTLY);
-            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight,
-                    MeasureSpec.EXACTLY);
-            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-            maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
-            maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
-        }
+
+        // Make the feedback view large enough to hold the blur bitmap.
+        mTouchFeedbackView.measure(
+                MeasureSpec.makeMeasureSpec(mCellWidth + mTouchFeedbackView.getExtraSize(),
+                        MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(mCellHeight + mTouchFeedbackView.getExtraSize(),
+                        MeasureSpec.EXACTLY));
+
+        mShortcutsAndWidgets.measure(
+                MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY),
+                MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY));
+
+        int maxWidth = mShortcutsAndWidgets.getMeasuredWidth();
+        int maxHeight = mShortcutsAndWidgets.getMeasuredHeight();
         if (mFixedWidth > 0 && mFixedHeight > 0) {
             setMeasuredDimension(maxWidth, maxHeight);
         } else {
@@ -903,13 +873,13 @@
                 (mCountX * mCellWidth);
         int left = getPaddingLeft() + (int) Math.ceil(offset / 2f);
         int top = getPaddingTop();
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            child.layout(left, top,
-                    left + r - l,
-                    top + b - t);
-        }
+
+        mTouchFeedbackView.layout(left, top,
+                left + mTouchFeedbackView.getMeasuredWidth(),
+                top + mTouchFeedbackView.getMeasuredHeight());
+        mShortcutsAndWidgets.layout(left, top,
+                left + r - l,
+                top + b - t);
     }
 
     @Override
@@ -917,12 +887,9 @@
         super.onSizeChanged(w, h, oldw, oldh);
 
         // Expand the background drawing bounds by the padding baked into the background drawable
-        Rect padding = new Rect();
-        mNormalBackground.getPadding(padding);
-        mBackgroundRect.set(-padding.left, -padding.top, w + padding.right, h + padding.bottom);
-
-        mForegroundRect.set(mForegroundPadding, mForegroundPadding,
-                w - mForegroundPadding, h - mForegroundPadding);
+        mBackground.getPadding(mTempRect);
+        mBackground.setBounds(-mTempRect.left, -mTempRect.top,
+                w + mTempRect.right, h + mTempRect.bottom);
     }
 
     @Override
@@ -939,25 +906,18 @@
         return mBackgroundAlpha;
     }
 
-    public void setBackgroundAlphaMultiplier(float multiplier) {
-
-        if (mBackgroundAlphaMultiplier != multiplier) {
-            mBackgroundAlphaMultiplier = multiplier;
-            invalidate();
-        }
-    }
-
-    public float getBackgroundAlphaMultiplier() {
-        return mBackgroundAlphaMultiplier;
-    }
-
     public void setBackgroundAlpha(float alpha) {
         if (mBackgroundAlpha != alpha) {
             mBackgroundAlpha = alpha;
-            invalidate();
+            mBackground.setAlpha((int) (mBackgroundAlpha * 255));
         }
     }
 
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || (mIsDragTarget && who == mBackground);
+    }
+
     public void setShortcutAndWidgetAlpha(float alpha) {
         mShortcutsAndWidgets.setAlpha(alpha);
     }
@@ -1054,36 +1014,6 @@
         return false;
     }
 
-    /**
-     * Estimate where the top left cell of the dragged item will land if it is dropped.
-     *
-     * @param originX The X value of the top left corner of the item
-     * @param originY The Y value of the top left corner of the item
-     * @param spanX The number of horizontal cells that the item spans
-     * @param spanY The number of vertical cells that the item spans
-     * @param result The estimated drop cell X and Y.
-     */
-    void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
-        final int countX = mCountX;
-        final int countY = mCountY;
-
-        // pointToCellRounded takes the top left of a cell but will pad that with
-        // cellWidth/2 and cellHeight/2 when finding the matching cell
-        pointToCellRounded(originX, originY, result);
-
-        // If the item isn't fully on this screen, snap to the edges
-        int rightOverhang = result[0] + spanX - countX;
-        if (rightOverhang > 0) {
-            result[0] -= rightOverhang; // Snap to right
-        }
-        result[0] = Math.max(0, result[0]); // Snap to left
-        int bottomOverhang = result[1] + spanY - countY;
-        if (bottomOverhang > 0) {
-            result[1] -= bottomOverhang; // Snap to bottom
-        }
-        result[1] = Math.max(0, result[1]); // Snap to top
-    }
-
     void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
             int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
         final int oldDragCellX = mDragCell[0];
@@ -1167,9 +1097,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
-            int[] result) {
-        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+    int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
     }
 
     /**
@@ -1189,30 +1118,10 @@
      */
     int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
             int spanY, int[] result, int[] resultSpan) {
-        return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
+        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
                 result, resultSpan);
     }
 
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreOccupied If true, the result can be an occupied cell
-     * @param result Array in which to place the result, or null (in which case a new array will
-     *        be allocated)
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
-            boolean ignoreOccupied, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY,
-                spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
-    }
-
     private final Stack<Rect> mTempRectStack = new Stack<Rect>();
     private void lazyInitTempRectStack() {
         if (mTempRectStack.isEmpty()) {
@@ -1244,12 +1153,9 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
-            View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
-            boolean[][] occupied) {
+    private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
+            int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
         lazyInitTempRectStack();
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
 
         // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
         // to the center of the item, but we are searching based on the top-left cell, so
@@ -1280,7 +1186,7 @@
                     // First, let's see if this thing fits anywhere
                     for (int i = 0; i < minSpanX; i++) {
                         for (int j = 0; j < minSpanY; j++) {
-                            if (occupied[x + i][y + j]) {
+                            if (mOccupied[x + i][y + j]) {
                                 continue inner;
                             }
                         }
@@ -1297,7 +1203,7 @@
                     while (!(hitMaxX && hitMaxY)) {
                         if (incX && !hitMaxX) {
                             for (int j = 0; j < ySize; j++) {
-                                if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
+                                if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
                                     // We can't move out horizontally
                                     hitMaxX = true;
                                 }
@@ -1307,7 +1213,7 @@
                             }
                         } else if (!hitMaxY) {
                             for (int i = 0; i < xSize; i++) {
-                                if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
+                                if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
                                     // We can't move out vertically
                                     hitMaxY = true;
                                 }
@@ -1324,7 +1230,7 @@
                     hitMaxX = xSize >= spanX;
                     hitMaxY = ySize >= spanY;
                 }
-                final int[] cellXY = mTmpXY;
+                final int[] cellXY = mTmpPoint;
                 cellToCenterPoint(x, y, cellXY);
 
                 // We verify that the current rect is not a sub-rect of any of our previous
@@ -1340,8 +1246,7 @@
                     }
                 }
                 validRegions.push(currentRect);
-                double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
-                        + Math.pow(cellXY[1] - pixelY, 2));
+                double distance = Math.hypot(cellXY[0] - pixelX,  cellXY[1] - pixelY);
 
                 if ((distance <= bestDistance && !contained) ||
                         currentRect.contains(bestRect)) {
@@ -1356,8 +1261,6 @@
                 }
             }
         }
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
 
         // Return -1, -1 if no suitable location found
         if (bestDistance == Double.MAX_VALUE) {
@@ -1411,8 +1314,7 @@
                     }
                 }
 
-                float distance = (float)
-                        Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
+                float distance = (float) Math.hypot(x - cellX, y - cellY);
                 int[] curDirection = mTmpPoint;
                 computeDirectionVector(x - cellX, y - cellY, curDirection);
                 // The direction score is just the dot product of the two candidate direction
@@ -2028,7 +1930,7 @@
         }
     }
 
-    ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, int[] direction, View dragView, boolean decX,
             ItemConfiguration solution) {
         // Copy the current state into the solution. This solution will be manipulated as necessary.
@@ -2264,7 +2166,7 @@
             }
         }
 
-        private void completeAnimationImmediately() {
+        @Thunk void completeAnimationImmediately() {
             if (a != null) {
                 a.cancel();
             }
@@ -2317,7 +2219,7 @@
         mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
     }
 
-    public void setUseTempCoords(boolean useTempCoords) {
+    private void setUseTempCoords(boolean useTempCoords) {
         int childCount = mShortcutsAndWidgets.getChildCount();
         for (int i = 0; i < childCount; i++) {
             LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
@@ -2325,11 +2227,11 @@
         }
     }
 
-    ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
+    private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, View dragView, ItemConfiguration solution) {
         int[] result = new int[2];
         int[] resultSpan = new int[2];
-        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
+        findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
                 resultSpan);
         if (result[0] >= 0 && result[1] >= 0) {
             copyCurrentStateToSolution(solution, false);
@@ -2585,7 +2487,7 @@
         return mItemPlacementDirty;
     }
 
-    private class ItemConfiguration {
+    @Thunk class ItemConfiguration {
         HashMap<View, CellAndSpan> map = new HashMap<View, CellAndSpan>();
         private HashMap<View, CellAndSpan> savedMap = new HashMap<View, CellAndSpan>();
         ArrayList<View> sortedViews = new ArrayList<View>();
@@ -2646,45 +2548,6 @@
     }
 
     /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
-    }
-
-    /**
-     * Find a vacant area that will fit the given bounds nearest the requested
-     * cell location. Uses Euclidean distance to score multiple vacant areas.
-     *
-     * @param pixelX The X location at which you want to search for a vacant area.
-     * @param pixelY The Y location at which you want to search for a vacant area.
-     * @param minSpanX The minimum horizontal span required
-     * @param minSpanY The minimum vertical span required
-     * @param spanX Horizontal span of the object.
-     * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
-     * @return The X, Y cell of a vacant area that can contain this object,
-     *         nearest the requested location.
-     */
-    int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
-            int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
-        return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
-                result, resultSpan, mOccupied);
-    }
-
-    /**
      * Find a starting cell position that will fit the given bounds nearest the requested
      * cell location. Uses Euclidean distance to score multiple vacant areas.
      *
@@ -2697,9 +2560,8 @@
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestArea(
-            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
-        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
     }
 
     boolean existsEmptyCell() {
@@ -2719,104 +2581,33 @@
      *
      * @return True if a vacant cell of the specified dimension was found, false otherwise.
      */
-    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
-    }
-
-    /**
-     * Like above, but ignores any cells occupied by the item "ignoreView"
-     *
-     * @param cellXY The array that will contain the position of a vacant cell if such a cell
-     *               can be found.
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @return
-     */
-    boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
-        return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
-                ignoreView, mOccupied);
-    }
-
-    /**
-     * Like above, but if intersectX and intersectY are not -1, then this method will try to
-     * return coordinates for rectangles that contain the cell [intersectX, intersectY]
-     *
-     * @param spanX The horizontal span of the cell we want to find.
-     * @param spanY The vertical span of the cell we want to find.
-     * @param ignoreView The home screen item we should treat as not occupying any space
-     * @param intersectX The X coordinate of the cell that we should try to overlap
-     * @param intersectX The Y coordinate of the cell that we should try to overlap
-     *
-     * @return True if a vacant cell of the specified dimension was found, false otherwise.
-     */
-    boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY) {
-        return findCellForSpanThatIntersectsIgnoring(
-                cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
-    }
-
-    /**
-     * The superset of the above two methods
-     */
-    boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
-            int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
-        // mark space take by ignoreView as available (method checks if ignoreView is null)
-        markCellsAsUnoccupiedForView(ignoreView, occupied);
-
+    public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
         boolean foundCell = false;
-        while (true) {
-            int startX = 0;
-            if (intersectX >= 0) {
-                startX = Math.max(startX, intersectX - (spanX - 1));
-            }
-            int endX = mCountX - (spanX - 1);
-            if (intersectX >= 0) {
-                endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
-            }
-            int startY = 0;
-            if (intersectY >= 0) {
-                startY = Math.max(startY, intersectY - (spanY - 1));
-            }
-            int endY = mCountY - (spanY - 1);
-            if (intersectY >= 0) {
-                endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
-            }
+        final int endX = mCountX - (spanX - 1);
+        final int endY = mCountY - (spanY - 1);
 
-            for (int y = startY; y < endY && !foundCell; y++) {
-                inner:
-                for (int x = startX; x < endX; x++) {
-                    for (int i = 0; i < spanX; i++) {
-                        for (int j = 0; j < spanY; j++) {
-                            if (occupied[x + i][y + j]) {
-                                // small optimization: we can skip to after the column we just found
-                                // an occupied cell
-                                x += i;
-                                continue inner;
-                            }
+        for (int y = 0; y < endY && !foundCell; y++) {
+            inner:
+            for (int x = 0; x < endX; x++) {
+                for (int i = 0; i < spanX; i++) {
+                    for (int j = 0; j < spanY; j++) {
+                        if (mOccupied[x + i][y + j]) {
+                            // small optimization: we can skip to after the column we just found
+                            // an occupied cell
+                            x += i;
+                            continue inner;
                         }
                     }
-                    if (cellXY != null) {
-                        cellXY[0] = x;
-                        cellXY[1] = y;
-                    }
-                    foundCell = true;
-                    break;
                 }
-            }
-            if (intersectX == -1 && intersectY == -1) {
+                if (cellXY != null) {
+                    cellXY[0] = x;
+                    cellXY[1] = y;
+                }
+                foundCell = true;
                 break;
-            } else {
-                // if we failed to find anything, try again but without any requirements of
-                // intersecting
-                intersectX = -1;
-                intersectY = -1;
-                continue;
             }
         }
 
-        // re-mark space taken by ignoreView as occupied
-        markCellsAsOccupiedForView(ignoreView, occupied);
         return foundCell;
     }
 
@@ -2826,7 +2617,6 @@
      * or it may have begun on another layout.
      */
     void onDragEnter() {
-        mDragEnforcer.onDragEnter();
         mDragging = true;
     }
 
@@ -2834,7 +2624,6 @@
      * Called when drag has left this CellLayout or has been completed (successfully or not)
      */
     void onDragExit() {
-        mDragEnforcer.onDragExit();
         // This can actually be called when we aren't in a drag, e.g. when adding a new
         // item to this layout via the customize drawer.
         // Guard against that case.
@@ -2900,18 +2689,20 @@
      * @param height Height in pixels
      * @param result An array of length 2 in which to store the result (may be null).
      */
-    public static int[] rectToCell(int width, int height, int[] result) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        Rect padding = grid.getWorkspacePadding(grid.isLandscape ?
-                CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
+    public static int[] rectToCell(Launcher launcher, int width, int height, int[] result) {
+        return rectToCell(launcher.getDeviceProfile(), launcher, width, height, result);
+    }
+
+    public static int[] rectToCell(DeviceProfile grid, Context context, int width, int height,
+            int[] result) {
+        Rect padding = grid.getWorkspacePadding(Utilities.isRtl(context.getResources()));
 
         // Always assume we're working with the smallest span to make sure we
         // reserve enough space in both orientations.
-        int parentWidth = grid.calculateCellWidth(grid.widthPx
-                - padding.left - padding.right, (int) grid.numColumns);
-        int parentHeight = grid.calculateCellHeight(grid.heightPx
-                - padding.top - padding.bottom, (int) grid.numRows);
+        int parentWidth = DeviceProfile.calculateCellWidth(grid.widthPx
+                - padding.left - padding.right, (int) grid.inv.numColumns);
+        int parentHeight = DeviceProfile.calculateCellHeight(grid.heightPx
+                - padding.top - padding.bottom, (int) grid.inv.numRows);
         int smallerSize = Math.min(parentWidth, parentHeight);
 
         // Always round up to next largest cell
@@ -2926,13 +2717,6 @@
         return result;
     }
 
-    public int[] cellSpansToSize(int hSpans, int vSpans) {
-        int[] size = new int[2];
-        size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
-        size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
-        return size;
-    }
-
     /**
      * Calculate the grid spans needed to fit given item
      */
@@ -2951,49 +2735,11 @@
             info.spanX = info.spanY = 1;
             return;
         }
-        int[] spans = rectToCell(minWidth, minHeight, null);
+        int[] spans = rectToCell(mLauncher, minWidth, minHeight, null);
         info.spanX = spans[0];
         info.spanY = spans[1];
     }
 
-    /**
-     * Find the first vacant cell, if there is one.
-     *
-     * @param vacant Holds the x and y coordinate of the vacant cell
-     * @param spanX Horizontal cell span.
-     * @param spanY Vertical cell span.
-     *
-     * @return True if a vacant cell was found
-     */
-    public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
-
-        return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
-    }
-
-    static boolean findVacantCell(int[] vacant, int spanX, int spanY,
-            int xCount, int yCount, boolean[][] occupied) {
-
-        for (int y = 0; y < yCount; y++) {
-            for (int x = 0; x < xCount; x++) {
-                boolean available = !occupied[x][y];
-out:            for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
-                    for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
-                        available = available && !occupied[i][j];
-                        if (!available) break out;
-                    }
-                }
-
-                if (available) {
-                    vacant[0] = x;
-                    vacant[1] = y;
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
     private void clearOccupiedCells() {
         for (int x = 0; x < mCountX; x++) {
             for (int y = 0; y < mCountY; y++) {
@@ -3002,27 +2748,16 @@
         }
     }
 
-    public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
-        markCellsAsUnoccupiedForView(view);
-        markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
-    }
-
     public void markCellsAsOccupiedForView(View view) {
-        markCellsAsOccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
     }
 
     public void markCellsAsUnoccupiedForView(View view) {
-        markCellsAsUnoccupiedForView(view, mOccupied);
-    }
-    public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
         if (view == null || view.getParent() != mShortcutsAndWidgets) return;
         LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
+        markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
     }
 
     private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
@@ -3068,17 +2803,6 @@
         return new CellLayout.LayoutParams(p);
     }
 
-    public static class CellLayoutAnimationController extends LayoutAnimationController {
-        public CellLayoutAnimationController(Animation animation, float delay) {
-            super(animation, delay);
-        }
-
-        @Override
-        protected long getDelayForView(View view) {
-            return (int) (Math.random() * 150);
-        }
-    }
-
     public static class LayoutParams extends ViewGroup.MarginLayoutParams {
         /**
          * Horizontal location of the item in the grid.
@@ -3237,7 +2961,7 @@
     // 2. When long clicking on an empty cell in a CellLayout, we save information about the
     //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
     //    the CellLayout that was long clicked
-    static final class CellInfo {
+    public static final class CellInfo {
         View cell;
         int cellX = -1;
         int cellY = -1;
@@ -3246,7 +2970,7 @@
         long screenId;
         long container;
 
-        CellInfo(View v, ItemInfo info) {
+        public CellInfo(View v, ItemInfo info) {
             cell = v;
             cellX = info.cellX;
             cellY = info.cellY;
@@ -3263,7 +2987,24 @@
         }
     }
 
-    public boolean lastDownOnOccupiedCell() {
-        return mLastDownOnOccupiedCell;
+    public boolean findVacantCell(int spanX, int spanY, int[] outXY) {
+        return Utilities.findVacantCell(outXY, spanX, spanY, mCountX, mCountY, mOccupied);
+    }
+
+    public boolean isRegionVacant(int x, int y, int spanX, int spanY) {
+        int x2 = x + spanX - 1;
+        int y2 = y + spanY - 1;
+        if (x < 0 || y < 0 || x2 >= mCountX || y2 >= mCountY) {
+            return false;
+        }
+        for (int i = x; i <= x2; i++) {
+            for (int j = y; j <= y2; j++) {
+                if (mOccupied[i][j]) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
     }
 }
diff --git a/src/com/android/launcher3/CheckLongPressHelper.java b/src/com/android/launcher3/CheckLongPressHelper.java
index 8114979..483c622 100644
--- a/src/com/android/launcher3/CheckLongPressHelper.java
+++ b/src/com/android/launcher3/CheckLongPressHelper.java
@@ -18,16 +18,27 @@
 
 import android.view.View;
 
+import com.android.launcher3.util.Thunk;
+
 public class CheckLongPressHelper {
-    private View mView;
-    private boolean mHasPerformedLongPress;
+
+    @Thunk View mView;
+    @Thunk View.OnLongClickListener mListener;
+    @Thunk boolean mHasPerformedLongPress;
+    private int mLongPressTimeout = 300;
     private CheckForLongPress mPendingCheckForLongPress;
 
     class CheckForLongPress implements Runnable {
         public void run() {
             if ((mView.getParent() != null) && mView.hasWindowFocus()
                     && !mHasPerformedLongPress) {
-                if (mView.performLongClick()) {
+                boolean handled;
+                if (mListener != null) {
+                    handled = mListener.onLongClick(mView);
+                } else {
+                    handled = mView.performLongClick();
+                }
+                if (handled) {
                     mView.setPressed(false);
                     mHasPerformedLongPress = true;
                 }
@@ -39,14 +50,25 @@
         mView = v;
     }
 
+    public CheckLongPressHelper(View v, View.OnLongClickListener listener) {
+        mView = v;
+        mListener = listener;
+    }
+
+    /**
+     * Overrides the default long press timeout.
+     */
+    public void setLongPressTimeout(int longPressTimeout) {
+        mLongPressTimeout = longPressTimeout;
+    }
+
     public void postCheckForLongPress() {
         mHasPerformedLongPress = false;
 
         if (mPendingCheckForLongPress == null) {
             mPendingCheckForLongPress = new CheckForLongPress();
         }
-        mView.postDelayed(mPendingCheckForLongPress,
-                LauncherAppState.getInstance().getLongPressTimeout());
+        mView.postDelayed(mPendingCheckForLongPress, mLongPressTimeout);
     }
 
     public void cancelLongPress() {
diff --git a/src/com/android/launcher3/ClickShadowView.java b/src/com/android/launcher3/ClickShadowView.java
new file mode 100644
index 0000000..e31d7f7
--- /dev/null
+++ b/src/com/android/launcher3/ClickShadowView.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ClickShadowView extends View {
+
+    private static final int SHADOW_SIZE_FACTOR = 3;
+    private static final int SHADOW_LOW_ALPHA = 30;
+    private static final int SHADOW_HIGH_ALPHA = 60;
+
+    private final Paint mPaint;
+
+    private final float mShadowOffset;
+    private final float mShadowPadding;
+
+    private Bitmap mBitmap;
+
+    public ClickShadowView(Context context) {
+        super(context);
+        mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+        mPaint.setColor(Color.BLACK);
+
+        mShadowPadding = getResources().getDimension(R.dimen.blur_size_click_shadow);
+        mShadowOffset = getResources().getDimension(R.dimen.click_shadow_high_shift);
+    }
+
+    /**
+     * @return extra space required by the view to show the shadow.
+     */
+    public int getExtraSize() {
+        return (int) (SHADOW_SIZE_FACTOR * mShadowPadding);
+    }
+
+    /**
+     * Applies the new bitmap.
+     * @return true if the view was invalidated.
+     */
+    public boolean setBitmap(Bitmap b) {
+        if (b != mBitmap){
+            mBitmap = b;
+            invalidate();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mBitmap != null) {
+            mPaint.setAlpha(SHADOW_LOW_ALPHA);
+            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
+            mPaint.setAlpha(SHADOW_HIGH_ALPHA);
+            canvas.drawBitmap(mBitmap, 0, mShadowOffset, mPaint);
+        }
+    }
+
+    public void animateShadow() {
+        setAlpha(0);
+        animate().alpha(1)
+            .setDuration(FastBitmapDrawable.CLICK_FEEDBACK_DURATION)
+            .setInterpolator(FastBitmapDrawable.CLICK_FEEDBACK_INTERPOLATOR)
+            .start();
+    }
+
+    /**
+     * Aligns the shadow with {@param view}
+     * @param viewParent immediate parent of {@param view}. It must be a sibling of this view.
+     */
+    public void alignWithIconView(BubbleTextView view, ViewGroup viewParent) {
+        float leftShift = view.getLeft() + viewParent.getLeft() - getLeft();
+        float topShift = view.getTop() + viewParent.getTop() - getTop();
+        int iconWidth = view.getRight() - view.getLeft();
+        int iconHSpace = iconWidth - view.getCompoundPaddingRight() - view.getCompoundPaddingLeft();
+        float drawableWidth = view.getIcon().getBounds().width();
+
+        setTranslationX(leftShift
+                + viewParent.getTranslationX()
+                + view.getCompoundPaddingLeft() * view.getScaleX()
+                + (iconHSpace - drawableWidth) * view.getScaleX() / 2  /* drawable gap */
+                + iconWidth * (1 - view.getScaleX()) / 2  /* gap due to scale */
+                - mShadowPadding  /* extra shadow size */
+                );
+        setTranslationY(topShift
+                + viewParent.getTranslationY()
+                + view.getPaddingTop() * view.getScaleY()  /* drawable gap */
+                + view.getHeight() * (1 - view.getScaleY()) / 2  /* gap due to scale */
+                - mShadowPadding  /* extra shadow size */
+                );
+    }
+}
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
new file mode 100644
index 0000000..5314ecf
--- /dev/null
+++ b/src/com/android/launcher3/CommonAppTypeParser.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.XmlResourceParser;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.backup.BackupProtos.Favorite;
+import com.android.launcher3.util.Thunk;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * A class that parses content values corresponding to some common app types.
+ */
+public class CommonAppTypeParser implements LayoutParserCallback {
+    private static final String TAG = "CommonAppTypeParser";
+
+    // Including TARGET_NONE
+    public static final int SUPPORTED_TYPE_COUNT = 7;
+
+    private static final int RESTORE_FLAG_BIT_SHIFT = 4;
+
+
+    private final long mItemId;
+    @Thunk final int mResId;
+    @Thunk final Context mContext;
+
+    ContentValues parsedValues;
+    Intent parsedIntent;
+    String parsedTitle;
+
+    public CommonAppTypeParser(long itemId, int itemType, Context context) {
+        mItemId = itemId;
+        mContext = context;
+        mResId = getResourceForItemType(itemType);
+    }
+
+    @Override
+    public long generateNewItemId() {
+        return mItemId;
+    }
+
+    @Override
+    public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
+        parsedValues = values;
+
+        // Remove unwanted values
+        values.put(Favorites.ICON_TYPE, (Integer) null);
+        values.put(Favorites.ICON_PACKAGE, (String) null);
+        values.put(Favorites.ICON_RESOURCE, (String) null);
+        values.put(Favorites.ICON, (byte[]) null);
+        return 1;
+    }
+
+    /**
+     * Tries to find a suitable app to the provided app type.
+     */
+    public boolean findDefaultApp() {
+        if (mResId == 0) {
+            return false;
+        }
+
+        parsedIntent = null;
+        parsedValues = null;
+        new MyLayoutParser().parseValues();
+        return (parsedValues != null) && (parsedIntent != null);
+    }
+
+    private class MyLayoutParser extends DefaultLayoutParser {
+
+        public MyLayoutParser() {
+            super(CommonAppTypeParser.this.mContext, null, CommonAppTypeParser.this,
+                    CommonAppTypeParser.this.mContext.getResources(), mResId, TAG_RESOLVE, 0);
+        }
+
+        @Override
+        protected long addShortcut(String title, Intent intent, int type) {
+            if (type == Favorites.ITEM_TYPE_APPLICATION) {
+                parsedIntent = intent;
+                parsedTitle = title;
+            }
+            return super.addShortcut(title, intent, type);
+        }
+
+        public void parseValues() {
+            XmlResourceParser parser = mSourceRes.getXml(mLayoutId);
+            try {
+                beginDocument(parser, mRootTag);
+                new ResolveParser().parseAndAdd(parser);
+            } catch (IOException | XmlPullParserException e) {
+                Log.e(TAG, "Unable to parse default app info", e);
+            }
+            parser.close();
+        }
+    }
+
+    public static int getResourceForItemType(int type) {
+        switch (type) {
+            case Favorite.TARGET_PHONE:
+                return R.xml.app_target_phone;
+
+            case Favorite.TARGET_MESSENGER:
+                return R.xml.app_target_messenger;
+
+            case Favorite.TARGET_EMAIL:
+                return R.xml.app_target_email;
+
+            case Favorite.TARGET_BROWSER:
+                return R.xml.app_target_browser;
+
+            case Favorite.TARGET_GALLERY:
+                return R.xml.app_target_gallery;
+
+            case Favorite.TARGET_CAMERA:
+                return R.xml.app_target_camera;
+
+            default:
+                return 0;
+        }
+    }
+
+    public static int encodeItemTypeToFlag(int itemType) {
+        return itemType << RESTORE_FLAG_BIT_SHIFT;
+    }
+
+    public static int decodeItemTypeFromFlag(int flag) {
+        return (flag & ShortcutInfo.FLAG_RESTORED_APP_TYPE) >> RESTORE_FLAG_BIT_SHIFT;
+    }
+
+}
diff --git a/src/com/android/launcher3/CustomAppWidget.java b/src/com/android/launcher3/CustomAppWidget.java
new file mode 100644
index 0000000..1b4ed79
--- /dev/null
+++ b/src/com/android/launcher3/CustomAppWidget.java
@@ -0,0 +1,14 @@
+package com.android.launcher3;
+
+public interface CustomAppWidget {
+    public String getLabel();
+    public int getPreviewImage();
+    public int getIcon();
+    public int getWidgetLayout();
+
+    public int getSpanX();
+    public int getSpanY();
+    public int getMinSpanX();
+    public int getMinSpanY();
+    public int getResizeMode();
+}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index e3ea40e..7b91c67 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -13,13 +13,13 @@
 import android.util.Log;
 
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.util.Thunk;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
@@ -29,17 +29,15 @@
 public class DefaultLayoutParser extends AutoInstallsLayout {
     private static final String TAG = "DefaultLayoutParser";
 
-    private static final String TAG_RESOLVE = "resolve";
+    protected static final String TAG_RESOLVE = "resolve";
     private static final String TAG_FAVORITES = "favorites";
-    private static final String TAG_FAVORITE = "favorite";
+    protected static final String TAG_FAVORITE = "favorite";
     private static final String TAG_APPWIDGET = "appwidget";
     private static final String TAG_SHORTCUT = "shortcut";
     private static final String TAG_FOLDER = "folder";
     private static final String TAG_PARTNER_FOLDER = "partner-folder";
-    private static final String TAG_INCLUDE = "include";
 
-    private static final String ATTR_URI = "uri";
-    private static final String ATTR_WORKSPACE = "workspace";
+    protected static final String ATTR_URI = "uri";
     private static final String ATTR_CONTAINER = "container";
     private static final String ATTR_SCREEN = "screen";
     private static final String ATTR_FOLDER_ITEMS = "folderItems";
@@ -47,7 +45,12 @@
     public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
             LayoutParserCallback callback, Resources sourceRes, int layoutId) {
         super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
-        Log.e(TAG, "Default layout parser initialized");
+    }
+
+    public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
+            LayoutParserCallback callback, Resources sourceRes, int layoutId, String rootTag,
+            int hotseatAllAppsRank) {
+        super(context, appWidgetHost, callback, sourceRes, layoutId, rootTag, hotseatAllAppsRank);
     }
 
     @Override
@@ -55,7 +58,7 @@
         return getFolderElementsMap(mSourceRes);
     }
 
-    private HashMap<String, TagParser> getFolderElementsMap(Resources res) {
+    @Thunk HashMap<String, TagParser> getFolderElementsMap(Resources res) {
         HashMap<String, TagParser> parsers = new HashMap<String, TagParser>();
         parsers.put(TAG_FAVORITE, new AppShortcutWithUriParser());
         parsers.put(TAG_SHORTCUT, new UriShortcutParser(res));
@@ -84,29 +87,10 @@
         out[1] = Long.parseLong(getAttributeValue(parser, ATTR_SCREEN));
     }
 
-    @Override
-    protected int parseAndAddNode(
-            XmlResourceParser parser,
-            HashMap<String, TagParser> tagParserMap,
-            ArrayList<Long> screenIds)
-                    throws XmlPullParserException, IOException {
-        if (TAG_INCLUDE.equals(parser.getName())) {
-            final int resId = getAttributeResourceValue(parser, ATTR_WORKSPACE, 0);
-            if (resId != 0) {
-                // recursively load some more favorites, why not?
-                return parseLayout(resId, screenIds);
-            } else {
-                return 0;
-            }
-        } else {
-            return super.parseAndAddNode(parser, tagParserMap, screenIds);
-        }
-    }
-
     /**
      * AppShortcutParser which also supports adding URI based intents
      */
-    private class AppShortcutWithUriParser extends AppShortcutParser {
+    @Thunk class AppShortcutWithUriParser extends AppShortcutParser {
 
         @Override
         protected long invalidPackageOrClass(XmlResourceParser parser) {
@@ -218,7 +202,7 @@
     /**
      * Contains a list of <favorite> nodes, and accepts the first successfully parsed node.
      */
-    private class ResolveParser implements TagParser {
+    protected class ResolveParser implements TagParser {
 
         private final AppShortcutWithUriParser mChildParser = new AppShortcutWithUriParser();
 
@@ -248,7 +232,7 @@
     /**
      * A parser which adds a folder whose contents come from partner apk.
      */
-    private class PartnerFolderParser implements TagParser {
+    @Thunk class PartnerFolderParser implements TagParser {
 
         @Override
         public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
@@ -274,7 +258,7 @@
     /**
      * An extension of FolderParser which allows adding items from a different xml.
      */
-    private class MyFolderParser extends FolderParser {
+    @Thunk class MyFolderParser extends FolderParser {
 
         @Override
         public long parseAndAdd(XmlResourceParser parser) throws XmlPullParserException,
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
index a2d121d..a43ab67 100644
--- a/src/com/android/launcher3/DeferredHandler.java
+++ b/src/com/android/launcher3/DeferredHandler.java
@@ -20,10 +20,10 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
-import android.util.Pair;
+
+import com.android.launcher3.util.Thunk;
 
 import java.util.LinkedList;
-import java.util.ListIterator;
 
 /**
  * Queue of things to run on a looper thread.  Items posted with {@link #post} will not
@@ -33,20 +33,18 @@
  * This class is fifo.
  */
 public class DeferredHandler {
-    private LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
+    @Thunk LinkedList<Runnable> mQueue = new LinkedList<>();
     private MessageQueue mMessageQueue = Looper.myQueue();
     private Impl mHandler = new Impl();
 
-    private class Impl extends Handler implements MessageQueue.IdleHandler {
+    @Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
         public void handleMessage(Message msg) {
-            Pair<Runnable, Integer> p;
             Runnable r;
             synchronized (mQueue) {
                 if (mQueue.size() == 0) {
                     return;
                 }
-                p = mQueue.removeFirst();
-                r = p.first;
+                r = mQueue.removeFirst();
             }
             r.run();
             synchronized (mQueue) {
@@ -77,11 +75,8 @@
 
     /** Schedule runnable to run after everything that's on the queue right now. */
     public void post(Runnable runnable) {
-        post(runnable, 0);
-    }
-    public void post(Runnable runnable, int type) {
         synchronized (mQueue) {
-            mQueue.add(new Pair<Runnable, Integer>(runnable, type));
+            mQueue.add(runnable);
             if (mQueue.size() == 1) {
                 scheduleNextLocked();
             }
@@ -90,31 +85,10 @@
 
     /** Schedule runnable to run when the queue goes idle. */
     public void postIdle(final Runnable runnable) {
-        postIdle(runnable, 0);
-    }
-    public void postIdle(final Runnable runnable, int type) {
-        post(new IdleRunnable(runnable), type);
+        post(new IdleRunnable(runnable));
     }
 
-    public void cancelRunnable(Runnable runnable) {
-        synchronized (mQueue) {
-            while (mQueue.remove(runnable)) { }
-        }
-    }
-    public void cancelAllRunnablesOfType(int type) {
-        synchronized (mQueue) {
-            ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
-            Pair<Runnable, Integer> p;
-            while (iter.hasNext()) {
-                p = iter.next();
-                if (p.second == type) {
-                    iter.remove();
-                }
-            }
-        }
-    }
-
-    public void cancel() {
+    public void cancelAll() {
         synchronized (mQueue) {
             mQueue.clear();
         }
@@ -122,20 +96,19 @@
 
     /** Runs all queued Runnables from the calling thread. */
     public void flush() {
-        LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
+        LinkedList<Runnable> queue = new LinkedList<>();
         synchronized (mQueue) {
             queue.addAll(mQueue);
             mQueue.clear();
         }
-        for (Pair<Runnable, Integer> p : queue) {
-            p.first.run();
+        for (Runnable r : queue) {
+            r.run();
         }
     }
 
     void scheduleNextLocked() {
         if (mQueue.size() > 0) {
-            Pair<Runnable, Integer> p = mQueue.getFirst();
-            Runnable peek = p.first;
+            Runnable peek = mQueue.getFirst();
             if (peek instanceof IdleRunnable) {
                 mMessageQueue.addIdleHandler(mHandler);
             } else {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index ea058ea..9c8659c 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -17,45 +17,17 @@
 package com.android.launcher3;
 
 import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.drawable.TransitionDrawable;
 import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.UserManager;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LinearInterpolator;
 
-import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.FlingAnimation;
+import com.android.launcher3.util.Thunk;
 
 public class DeleteDropTarget extends ButtonDropTarget {
-    private static int DELETE_ANIMATION_DURATION = 285;
-    private static int FLING_DELETE_ANIMATION_DURATION = 350;
-    private static float FLING_TO_DELETE_FRICTION = 0.035f;
-    private static int MODE_FLING_DELETE_TO_TRASH = 0;
-    private static int MODE_FLING_DELETE_ALONG_VECTOR = 1;
-
-    private final int mFlingDeleteMode = MODE_FLING_DELETE_ALONG_VECTOR;
-
-    private ColorStateList mOriginalTextColor;
-    private TransitionDrawable mUninstallDrawable;
-    private TransitionDrawable mRemoveDrawable;
-    private TransitionDrawable mCurrentDrawable;
-
-    private boolean mWaitingForUninstall = false;
 
     public DeleteDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -68,442 +40,86 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        // Get the drawable
-        mOriginalTextColor = getTextColors();
-
         // Get the hover color
-        Resources r = getResources();
-        mHoverColor = r.getColor(R.color.delete_target_hover_tint);
-        mUninstallDrawable = (TransitionDrawable) 
-                r.getDrawable(R.drawable.uninstall_target_selector);
-        mRemoveDrawable = (TransitionDrawable) r.getDrawable(R.drawable.remove_target_selector);
+        mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
 
-        mRemoveDrawable.setCrossFadeEnabled(true);
-        mUninstallDrawable.setCrossFadeEnabled(true);
-
-        // The current drawable is set to either the remove drawable or the uninstall drawable 
-        // and is initially set to the remove drawable, as set in the layout xml.
-        mCurrentDrawable = (TransitionDrawable) getCurrentDrawable();
-
-        // Remove the text in the Phone UI in landscape
-        int orientation = getResources().getConfiguration().orientation;
-        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            if (!LauncherAppState.getInstance().isScreenLarge()) {
-                setText("");
-            }
-        }
+        setDrawable(R.drawable.ic_remove_launcher);
     }
 
-    private boolean isAllAppsApplication(DragSource source, Object info) {
-        return source.supportsAppInfoDropTarget() && (info instanceof AppInfo);
-    }
-    private boolean isAllAppsWidget(DragSource source, Object info) {
-        if (source instanceof AppsCustomizePagedView) {
-            if (info instanceof PendingAddItemInfo) {
-                PendingAddItemInfo addInfo = (PendingAddItemInfo) info;
-                switch (addInfo.itemType) {
-                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        return true;
-                }
-            }
-        }
-        return false;
-    }
-    private boolean isDragSourceWorkspaceOrFolder(DragObject d) {
-        return (d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder);
-    }
-    private boolean isWorkspaceOrFolderApplication(DragObject d) {
-        return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof ShortcutInfo);
-    }
-    private boolean isWorkspaceOrFolderWidget(DragObject d) {
-        return isDragSourceWorkspaceOrFolder(d) && (d.dragInfo instanceof LauncherAppWidgetInfo);
-    }
-    private boolean isWorkspaceFolder(DragObject d) {
-        return (d.dragSource instanceof Workspace) && (d.dragInfo instanceof FolderInfo);
-    }
-
-    private void setHoverColor() {
-        if (mCurrentDrawable != null) {
-            mCurrentDrawable.startTransition(mTransitionDuration);
-        }
-        setTextColor(mHoverColor);
-    }
-    private void resetHoverColor() {
-        if (mCurrentDrawable != null) {
-            mCurrentDrawable.resetTransition();
-        }
-        setTextColor(mOriginalTextColor);
+    public static boolean supportsDrop(Object info) {
+        return (info instanceof ShortcutInfo)
+                || (info instanceof LauncherAppWidgetInfo)
+                || (info instanceof FolderInfo);
     }
 
     @Override
-    public boolean acceptDrop(DragObject d) {
-        return willAcceptDrop(d.dragInfo);
-    }
-
-    public static boolean willAcceptDrop(Object info) {
-        if (info instanceof ItemInfo) {
-            ItemInfo item = (ItemInfo) info;
-            if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET ||
-                    item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
-                return true;
-            }
-
-            if (!LauncherAppState.isDisableAllApps() &&
-                    item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
-                return true;
-            }
-
-            if (!LauncherAppState.isDisableAllApps() &&
-                    item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
-                    item instanceof AppInfo) {
-                AppInfo appInfo = (AppInfo) info;
-                return (appInfo.flags & AppInfo.DOWNLOADED_FLAG) != 0;
-            }
-
-            if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
-                item instanceof ShortcutInfo) {
-                if (LauncherAppState.isDisableAllApps()) {
-                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;
-                    return (shortcutInfo.flags & AppInfo.DOWNLOADED_FLAG) != 0;
-                } else {
-                    return true;
-                }
-            }
-        }
-        return false;
+    protected boolean supportsDrop(DragSource source, Object info) {
+        return source.supportsDeleteDropTarget() && supportsDrop(info);
     }
 
     @Override
-    public void onDragStart(DragSource source, Object info, int dragAction) {
-        boolean isVisible = true;
-        boolean useUninstallLabel = !LauncherAppState.isDisableAllApps() &&
-                isAllAppsApplication(source, info);
-        boolean useDeleteLabel = !useUninstallLabel && source.supportsDeleteDropTarget();
-
-        // If we are dragging an application from AppsCustomize, only show the control if we can
-        // delete the app (it was downloaded), and rename the string to "uninstall" in such a case.
-        // Hide the delete target if it is a widget from AppsCustomize.
-        if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) {
-            isVisible = false;
-        }
-        if (useUninstallLabel) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-                UserManager userManager = (UserManager)
-                        getContext().getSystemService(Context.USER_SERVICE);
-                Bundle restrictions = userManager.getUserRestrictions();
-                if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
-                        || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
-                    isVisible = false;
-                }
-            }
-        }
-
-        if (useUninstallLabel) {
-            setCompoundDrawablesRelativeWithIntrinsicBounds(mUninstallDrawable, null, null, null);
-        } else if (useDeleteLabel) {
-            setCompoundDrawablesRelativeWithIntrinsicBounds(mRemoveDrawable, null, null, null);
-        } else {
-            isVisible = false;
-        }
-        mCurrentDrawable = (TransitionDrawable) getCurrentDrawable();
-
-        mActive = isVisible;
-        resetHoverColor();
-        ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE);
-        if (isVisible && getText().length() > 0) {
-            setText(useUninstallLabel ? R.string.delete_target_uninstall_label
-                : R.string.delete_target_label);
-        }
-    }
-
-    @Override
-    public void onDragEnd() {
-        super.onDragEnd();
-        mActive = false;
-    }
-
-    public void onDragEnter(DragObject d) {
-        super.onDragEnter(d);
-
-        setHoverColor();
-    }
-
-    public void onDragExit(DragObject d) {
-        super.onDragExit(d);
-
-        if (!d.dragComplete) {
-            resetHoverColor();
-        } else {
-            // Restore the hover color if we are deleting
-            d.dragView.setColor(mHoverColor);
-        }
-    }
-
-    private void animateToTrashAndCompleteDrop(final DragObject d) {
-        final DragLayer dragLayer = mLauncher.getDragLayer();
-        final Rect from = new Rect();
-        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
-        int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth();
-        int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight();
-        final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
-                width, height);
-        final float scale = (float) to.width() / from.width();
-
-        mSearchDropTargetBar.deferOnDragEnd();
-        deferCompleteDropIfUninstalling(d);
-
-        Runnable onAnimationEndRunnable = new Runnable() {
-            @Override
-            public void run() {
-                completeDrop(d);
-                mSearchDropTargetBar.onDragEnd();
-                mLauncher.exitSpringLoadedDragModeDelayed(true, 0, null);
-            }
-        };
-        dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
-                DELETE_ANIMATION_DURATION, new DecelerateInterpolator(2),
-                new LinearInterpolator(), onAnimationEndRunnable,
-                DragLayer.ANIMATION_END_DISAPPEAR, null);
-    }
-
-    private void deferCompleteDropIfUninstalling(DragObject d) {
-        mWaitingForUninstall = false;
-        if (isUninstallFromWorkspace(d)) {
-            if (d.dragSource instanceof Folder) {
-                ((Folder) d.dragSource).deferCompleteDropAfterUninstallActivity();
-            } else if (d.dragSource instanceof Workspace) {
-                ((Workspace) d.dragSource).deferCompleteDropAfterUninstallActivity();
-            }
-            mWaitingForUninstall = true;
-        }
-    }
-
-    private boolean isUninstallFromWorkspace(DragObject d) {
-        if (LauncherAppState.isDisableAllApps() && isWorkspaceOrFolderApplication(d)) {
-            ShortcutInfo shortcut = (ShortcutInfo) d.dragInfo;
-            // Only allow manifest shortcuts to initiate an un-install.
-            return !InstallShortcutReceiver.isValidShortcutLaunchIntent(shortcut.intent);
-        }
-        return false;
-    }
-
-    private void completeDrop(DragObject d) {
+    @Thunk void completeDrop(DragObject d) {
         ItemInfo item = (ItemInfo) d.dragInfo;
-        boolean wasWaitingForUninstall = mWaitingForUninstall;
-        mWaitingForUninstall = false;
-        if (isAllAppsApplication(d.dragSource, item)) {
-            // Uninstall the application if it is being dragged from AppsCustomize
-            AppInfo appInfo = (AppInfo) item;
-            mLauncher.startApplicationUninstallActivity(appInfo.componentName, appInfo.flags,
-                    appInfo.user);
-        } else if (isUninstallFromWorkspace(d)) {
-            ShortcutInfo shortcut = (ShortcutInfo) item;
-            if (shortcut.intent != null && shortcut.intent.getComponent() != null) {
-                final ComponentName componentName = shortcut.intent.getComponent();
-                final DragSource dragSource = d.dragSource;
-                final UserHandleCompat user = shortcut.user;
-                mWaitingForUninstall = mLauncher.startApplicationUninstallActivity(
-                        componentName, shortcut.flags, user);
-                if (mWaitingForUninstall) {
-                    final Runnable checkIfUninstallWasSuccess = new Runnable() {
-                        @Override
-                        public void run() {
-                            mWaitingForUninstall = false;
-                            String packageName = componentName.getPackageName();
-                            boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
-                                    getContext(), packageName, user);
-                            if (dragSource instanceof Folder) {
-                                ((Folder) dragSource).
-                                    onUninstallActivityReturned(uninstallSuccessful);
-                            } else if (dragSource instanceof Workspace) {
-                                ((Workspace) dragSource).
-                                    onUninstallActivityReturned(uninstallSuccessful);
-                            }
-                        }
-                    };
-                    mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);
-                }
-            }
-        } else if (isWorkspaceOrFolderApplication(d)) {
-            LauncherModel.deleteItemFromDatabase(mLauncher, item);
-        } else if (isWorkspaceFolder(d)) {
-            // Remove the folder from the workspace and delete the contents from launcher model
-            FolderInfo folderInfo = (FolderInfo) item;
-            mLauncher.removeFolder(folderInfo);
-            LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
-        } else if (isWorkspaceOrFolderWidget(d)) {
-            // Remove the widget from the workspace
-            mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
-            LauncherModel.deleteItemFromDatabase(mLauncher, item);
+        if ((d.dragSource instanceof Workspace) || (d.dragSource instanceof Folder)) {
+            removeWorkspaceOrFolderItem(mLauncher, item, null);
+        }
+    }
 
-            final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
-            final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
-            if ((appWidgetHost != null) && launcherAppWidgetInfo.isWidgetIdValid()) {
+    /**
+     * Removes the item from the workspace. If the view is not null, it also removes the view.
+     * @return true if the item was removed.
+     */
+    public static boolean removeWorkspaceOrFolderItem(Launcher launcher, ItemInfo item, View view) {
+        if (item instanceof ShortcutInfo) {
+            LauncherModel.deleteItemFromDatabase(launcher, item);
+        } else if (item instanceof FolderInfo) {
+            FolderInfo folder = (FolderInfo) item;
+            launcher.removeFolder(folder);
+            LauncherModel.deleteFolderContentsFromDatabase(launcher, folder);
+        } else if (item instanceof LauncherAppWidgetInfo) {
+            final LauncherAppWidgetInfo widget = (LauncherAppWidgetInfo) item;
+
+            // Remove the widget from the workspace
+            launcher.removeAppWidget(widget);
+            LauncherModel.deleteItemFromDatabase(launcher, widget);
+
+            final LauncherAppWidgetHost appWidgetHost = launcher.getAppWidgetHost();
+
+            if (appWidgetHost != null && !widget.isCustomWidget()
+                    && widget.isWidgetIdValid()) {
                 // Deleting an app widget ID is a void call but writes to disk before returning
                 // to the caller...
                 new AsyncTask<Void, Void, Void>() {
                     public Void doInBackground(Void ... args) {
-                        appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);
+                        appWidgetHost.deleteAppWidgetId(widget.appWidgetId);
                         return null;
                     }
-                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
             }
-        }
-        if (wasWaitingForUninstall && !mWaitingForUninstall) {
-            if (d.dragSource instanceof Folder) {
-                ((Folder) d.dragSource).onUninstallActivityReturned(false);
-            } else if (d.dragSource instanceof Workspace) {
-                ((Workspace) d.dragSource).onUninstallActivityReturned(false);
-            }
-        }
-    }
-
-    public void onDrop(DragObject d) {
-        animateToTrashAndCompleteDrop(d);
-    }
-
-    /**
-     * Creates an animation from the current drag view to the delete trash icon.
-     */
-    private AnimatorUpdateListener createFlingToTrashAnimatorListener(final DragLayer dragLayer,
-            DragObject d, PointF vel, ViewConfiguration config) {
-
-        int width = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicWidth();
-        int height = mCurrentDrawable == null ? 0 : mCurrentDrawable.getIntrinsicHeight();
-        final Rect to = getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
-                width, height);
-        final Rect from = new Rect();
-        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
-        // Calculate how far along the velocity vector we should put the intermediate point on
-        // the bezier curve
-        float velocity = Math.abs(vel.length());
-        float vp = Math.min(1f, velocity / (config.getScaledMaximumFlingVelocity() / 2f));
-        int offsetY = (int) (-from.top * vp);
-        int offsetX = (int) (offsetY / (vel.y / vel.x));
-        final float y2 = from.top + offsetY;                        // intermediate t/l
-        final float x2 = from.left + offsetX;
-        final float x1 = from.left;                                 // drag view t/l
-        final float y1 = from.top;
-        final float x3 = to.left;                                   // delete target t/l
-        final float y3 = to.top;
-
-        final TimeInterpolator scaleAlphaInterpolator = new TimeInterpolator() {
-            @Override
-            public float getInterpolation(float t) {
-                return t * t * t * t * t * t * t * t;
-            }
-        };
-        return new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final DragView dragView = (DragView) dragLayer.getAnimatedView();
-                float t = ((Float) animation.getAnimatedValue()).floatValue();
-                float tp = scaleAlphaInterpolator.getInterpolation(t);
-                float initialScale = dragView.getInitialScale();
-                float finalAlpha = 0.5f;
-                float scale = dragView.getScaleX();
-                float x1o = ((1f - scale) * dragView.getMeasuredWidth()) / 2f;
-                float y1o = ((1f - scale) * dragView.getMeasuredHeight()) / 2f;
-                float x = (1f - t) * (1f - t) * (x1 - x1o) + 2 * (1f - t) * t * (x2 - x1o) +
-                        (t * t) * x3;
-                float y = (1f - t) * (1f - t) * (y1 - y1o) + 2 * (1f - t) * t * (y2 - x1o) +
-                        (t * t) * y3;
-
-                dragView.setTranslationX(x);
-                dragView.setTranslationY(y);
-                dragView.setScaleX(initialScale * (1f - tp));
-                dragView.setScaleY(initialScale * (1f - tp));
-                dragView.setAlpha(finalAlpha + (1f - finalAlpha) * (1f - tp));
-            }
-        };
-    }
-
-    /**
-     * Creates an animation from the current drag view along its current velocity vector.
-     * For this animation, the alpha runs for a fixed duration and we update the position
-     * progressively.
-     */
-    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private DragLayer mDragLayer;
-        private PointF mVelocity;
-        private Rect mFrom;
-        private long mPrevTime;
-        private boolean mHasOffsetForScale;
-        private float mFriction;
-
-        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
-        public FlingAlongVectorAnimatorUpdateListener(DragLayer dragLayer, PointF vel, Rect from,
-                long startTime, float friction) {
-            mDragLayer = dragLayer;
-            mVelocity = vel;
-            mFrom = from;
-            mPrevTime = startTime;
-            mFriction = 1f - (dragLayer.getResources().getDisplayMetrics().density * friction);
+        } else {
+            return false;
         }
 
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            final DragView dragView = (DragView) mDragLayer.getAnimatedView();
-            float t = ((Float) animation.getAnimatedValue()).floatValue();
-            long curTime = AnimationUtils.currentAnimationTimeMillis();
-
-            if (!mHasOffsetForScale) {
-                mHasOffsetForScale = true;
-                float scale = dragView.getScaleX();
-                float xOffset = ((scale - 1f) * dragView.getMeasuredWidth()) / 2f;
-                float yOffset = ((scale - 1f) * dragView.getMeasuredHeight()) / 2f;
-
-                mFrom.left += xOffset;
-                mFrom.top += yOffset;
-            }
-
-            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
-            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
-            dragView.setTranslationX(mFrom.left);
-            dragView.setTranslationY(mFrom.top);
-            dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
-            mVelocity.x *= mFriction;
-            mVelocity.y *= mFriction;
-            mPrevTime = curTime;
+        if (view != null) {
+            launcher.getWorkspace().removeWorkspaceItem(view);
+            launcher.getWorkspace().stripEmptyScreens();
         }
-    };
-    private AnimatorUpdateListener createFlingAlongVectorAnimatorListener(final DragLayer dragLayer,
-            DragObject d, PointF vel, final long startTime, final int duration,
-            ViewConfiguration config) {
-        final Rect from = new Rect();
-        dragLayer.getViewRectRelativeToSelf(d.dragView, from);
-
-        return new FlingAlongVectorAnimatorUpdateListener(dragLayer, vel, from, startTime,
-                FLING_TO_DELETE_FRICTION);
+        return true;
     }
 
-    public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
-        final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView;
-
+    @Override
+    public void onFlingToDelete(final DragObject d, PointF vel) {
         // Don't highlight the icon as it's animating
         d.dragView.setColor(0);
         d.dragView.updateInitialScaleToCurrentScale();
-        // Don't highlight the target if we are flinging from AllApps
-        if (isAllApps) {
-            resetHoverColor();
-        }
 
-        if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
-            // Defer animating out the drop target if we are animating to it
-            mSearchDropTargetBar.deferOnDragEnd();
-            mSearchDropTargetBar.finishAnimations();
-        }
-
-        final ViewConfiguration config = ViewConfiguration.get(mLauncher);
         final DragLayer dragLayer = mLauncher.getDragLayer();
-        final int duration = FLING_DELETE_ANIMATION_DURATION;
+        FlingAnimation fling = new FlingAnimation(d, vel,
+                getIconRect(d.dragView.getMeasuredWidth(), d.dragView.getMeasuredHeight(),
+                        mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight()),
+                        dragLayer);
+
+        final int duration = fling.getDuration();
         final long startTime = AnimationUtils.currentAnimationTimeMillis();
 
         // NOTE: Because it takes time for the first frame of animation to actually be
@@ -527,28 +143,22 @@
                 return Math.min(1f, mOffset + t);
             }
         };
-        AnimatorUpdateListener updateCb = null;
-        if (mFlingDeleteMode == MODE_FLING_DELETE_TO_TRASH) {
-            updateCb = createFlingToTrashAnimatorListener(dragLayer, d, vel, config);
-        } else if (mFlingDeleteMode == MODE_FLING_DELETE_ALONG_VECTOR) {
-            updateCb = createFlingAlongVectorAnimatorListener(dragLayer, d, vel, startTime,
-                    duration, config);
-        }
-        deferCompleteDropIfUninstalling(d);
 
         Runnable onAnimationEndRunnable = new Runnable() {
             @Override
             public void run() {
-                // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
-                // itself, otherwise, complete the drop to initiate the deletion process
-                if (!isAllApps) {
-                    mLauncher.exitSpringLoadedDragMode();
-                    completeDrop(d);
-                }
+                mLauncher.exitSpringLoadedDragMode();
+                completeDrop(d);
                 mLauncher.getDragController().onDeferredEndFling(d);
             }
         };
-        dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
+
+        dragLayer.animateView(d.dragView, fling, duration, tInterpolator, onAnimationEndRunnable,
                 DragLayer.ANIMATION_END_DISAPPEAR, null);
     }
+
+    @Override
+    protected String getAccessibilityDropConfirmation() {
+        return getResources().getString(R.string.item_removed);
+    }
 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index d6aadce..62b05b0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -19,155 +19,103 @@
 import android.appwidget.AppWidgetHostView;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetrics;
 import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
-import android.view.Display;
 import android.view.Gravity;
-import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewGroup.MarginLayoutParams;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-
-class DeviceProfileQuery {
-    DeviceProfile profile;
-    float widthDps;
-    float heightDps;
-    float value;
-    PointF dimens;
-
-    DeviceProfileQuery(DeviceProfile p, float v) {
-        widthDps = p.minWidthDps;
-        heightDps = p.minHeightDps;
-        value = v;
-        dimens = new PointF(widthDps, heightDps);
-        profile = p;
-    }
-}
-
 public class DeviceProfile {
-    public static interface DeviceProfileCallbacks {
-        public void onAvailableSizeChanged(DeviceProfile grid);
-    }
 
-    String name;
-    float minWidthDps;
-    float minHeightDps;
-    float numRows;
-    float numColumns;
-    float numHotseatIcons;
-    float iconSize;
-    private float iconTextSize;
-    private int iconDrawablePaddingOriginalPx;
-    private float hotseatIconSize;
+    public final InvariantDeviceProfile inv;
 
-    int defaultLayoutId;
+    // Device properties
+    public final boolean isTablet;
+    public final boolean isLargeTablet;
+    public final boolean isPhone;
+    public final boolean transposeLayoutWithOrientation;
 
-    boolean isLandscape;
-    boolean isTablet;
-    boolean isLargeTablet;
-    boolean isLayoutRtl;
-    boolean transposeLayoutWithOrientation;
+    // Device properties in current orientation
+    public final boolean isLandscape;
+    public final int widthPx;
+    public final int heightPx;
+    public final int availableWidthPx;
+    public final int availableHeightPx;
 
-    int desiredWorkspaceLeftRightMarginPx;
-    int edgeMarginPx;
-    Rect defaultWidgetPadding;
+    // Overview mode
+    private final int overviewModeMinIconZoneHeightPx;
+    private final int overviewModeMaxIconZoneHeightPx;
+    private final int overviewModeBarItemWidthPx;
+    private final int overviewModeBarSpacerWidthPx;
+    private final float overviewModeIconZoneRatio;
+    private final float overviewModeScaleFactor;
 
-    int widthPx;
-    int heightPx;
-    int availableWidthPx;
-    int availableHeightPx;
-    int defaultPageSpacingPx;
+    // Workspace
+    private int desiredWorkspaceLeftRightMarginPx;
+    public final int edgeMarginPx;
+    public final Rect defaultWidgetPadding;
+    private final int pageIndicatorHeightPx;
+    private final int defaultPageSpacingPx;
+    private float dragViewScale;
 
-    int overviewModeMinIconZoneHeightPx;
-    int overviewModeMaxIconZoneHeightPx;
-    int overviewModeBarItemWidthPx;
-    int overviewModeBarSpacerWidthPx;
-    float overviewModeIconZoneRatio;
-    float overviewModeScaleFactor;
+    // Workspace icons
+    public int iconSizePx;
+    public int iconTextSizePx;
+    public int iconDrawablePaddingPx;
+    public int iconDrawablePaddingOriginalPx;
 
-    int iconSizePx;
-    int iconTextSizePx;
-    int iconDrawablePaddingPx;
-    int cellWidthPx;
-    int cellHeightPx;
-    int allAppsIconSizePx;
-    int allAppsIconTextSizePx;
-    int allAppsCellWidthPx;
-    int allAppsCellHeightPx;
-    int allAppsCellPaddingPx;
-    int folderBackgroundOffset;
-    int folderIconSizePx;
-    int folderCellWidthPx;
-    int folderCellHeightPx;
-    int hotseatCellWidthPx;
-    int hotseatCellHeightPx;
-    int hotseatIconSizePx;
-    int hotseatBarHeightPx;
-    int hotseatAllAppsRank;
-    int allAppsNumRows;
-    int allAppsNumCols;
-    int searchBarSpaceWidthPx;
-    int searchBarSpaceHeightPx;
-    int pageIndicatorHeightPx;
-    int allAppsButtonVisualSize;
+    public int cellWidthPx;
+    public int cellHeightPx;
 
-    float dragViewScale;
+    // Folder
+    public int folderBackgroundOffset;
+    public int folderIconSizePx;
+    public int folderCellWidthPx;
+    public int folderCellHeightPx;
 
-    int allAppsShortEdgeCount = -1;
-    int allAppsLongEdgeCount = -1;
+    // Hotseat
+    public int hotseatCellWidthPx;
+    public int hotseatCellHeightPx;
+    public int hotseatIconSizePx;
+    private int hotseatBarHeightPx;
 
-    private ArrayList<DeviceProfileCallbacks> mCallbacks = new ArrayList<DeviceProfileCallbacks>();
+    // All apps
+    public int allAppsNumCols;
+    public int allAppsNumPredictiveCols;
+    public int allAppsButtonVisualSize;
+    public final int allAppsIconSizePx;
+    public final int allAppsIconTextSizePx;
 
-    DeviceProfile(String n, float w, float h, float r, float c,
-                  float is, float its, float hs, float his, int dlId) {
-        // Ensure that we have an odd number of hotseat items (since we need to place all apps)
-        if (!LauncherAppState.isDisableAllApps() && hs % 2 == 0) {
-            throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
-        }
+    // QSB
+    private int searchBarSpaceWidthPx;
+    private int searchBarSpaceHeightPx;
 
-        name = n;
-        minWidthDps = w;
-        minHeightDps = h;
-        numRows = r;
-        numColumns = c;
-        iconSize = is;
-        iconTextSize = its;
-        numHotseatIcons = hs;
-        hotseatIconSize = his;
-        defaultLayoutId = dlId;
-    }
+    public DeviceProfile(Context context, InvariantDeviceProfile inv,
+            Point minSize, Point maxSize,
+            int width, int height, boolean isLandscape) {
 
-    DeviceProfile() {
-    }
+        this.inv = inv;
+        this.isLandscape = isLandscape;
 
-    DeviceProfile(Context context,
-                  ArrayList<DeviceProfile> profiles,
-                  float minWidth, float minHeight,
-                  int wPx, int hPx,
-                  int awPx, int ahPx,
-                  Resources res) {
+        Resources res = context.getResources();
         DisplayMetrics dm = res.getDisplayMetrics();
-        ArrayList<DeviceProfileQuery> points =
-                new ArrayList<DeviceProfileQuery>();
+
+        // Constants from resources
+        isTablet = res.getBoolean(R.bool.is_tablet);
+        isLargeTablet = res.getBoolean(R.bool.is_large_tablet);
+        isPhone = !isTablet && !isLargeTablet;
+
+        // Some more constants
         transposeLayoutWithOrientation =
                 res.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
-        minWidthDps = minWidth;
-        minHeightDps = minHeight;
 
         ComponentName cn = new ComponentName(context.getPackageName(),
                 this.getClass().getName());
@@ -178,8 +126,6 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_page_indicator_height);
         defaultPageSpacingPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_workspace_page_spacing);
-        allAppsCellPaddingPx =
-                res.getDimensionPixelSize(R.dimen.dynamic_grid_all_apps_cell_padding);
         overviewModeMinIconZoneHeightPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_min_icon_zone_height);
         overviewModeMaxIconZoneHeightPx =
@@ -192,188 +138,71 @@
                 res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f;
         overviewModeScaleFactor =
                 res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f;
-
-        // Find the closes profile given the width/height
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p, 0f));
-        }
-        DeviceProfile closestProfile = findClosestDeviceProfile(minWidth, minHeight, points);
-
-        // Snap to the closest row count
-        numRows = closestProfile.numRows;
-
-        // Snap to the closest column count
-        numColumns = closestProfile.numColumns;
-
-        // Snap to the closest hotseat size
-        numHotseatIcons = closestProfile.numHotseatIcons;
-        hotseatAllAppsRank = (int) (numHotseatIcons / 2);
-
-        // Snap to the closest default layout id
-        defaultLayoutId = closestProfile.defaultLayoutId;
-
-        // Interpolate the icon size
-        points.clear();
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p, p.iconSize));
-        }
-        iconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
-
-        // AllApps uses the original non-scaled icon size
-        allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm);
-
-        // Interpolate the icon text size
-        points.clear();
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p, p.iconTextSize));
-        }
-        iconTextSize = invDistWeightedInterpolate(minWidth, minHeight, points);
         iconDrawablePaddingOriginalPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
+
         // AllApps uses the original non-scaled icon text size
-        allAppsIconTextSizePx = DynamicGrid.pxFromDp(iconTextSize, dm);
+        allAppsIconTextSizePx = Utilities.pxFromDp(inv.iconTextSize, dm);
 
-        // Interpolate the hotseat icon size
-        points.clear();
-        for (DeviceProfile p : profiles) {
-            points.add(new DeviceProfileQuery(p, p.hotseatIconSize));
+        // AllApps uses the original non-scaled icon size
+        allAppsIconSizePx = Utilities.pxFromDp(inv.iconSize, dm);
+
+        // Determine sizes.
+        widthPx = width;
+        heightPx = height;
+        if (isLandscape) {
+            availableWidthPx = maxSize.x;
+            availableHeightPx = minSize.y;
+        } else {
+            availableWidthPx = minSize.x;
+            availableHeightPx = maxSize.y;
         }
-        // Hotseat
-        hotseatIconSize = invDistWeightedInterpolate(minWidth, minHeight, points);
-
-        // If the partner customization apk contains any grid overrides, apply them
-        applyPartnerDeviceProfileOverrides(context, dm);
 
         // Calculate the remaining vars
-        updateFromConfiguration(context, res, wPx, hPx, awPx, ahPx);
-        updateAvailableDimensions(context);
+        updateAvailableDimensions(dm, res);
         computeAllAppsButtonSize(context);
     }
 
     /**
-     * Apply any Partner customization grid overrides.
-     *
-     * Currently we support: all apps row / column count.
-     */
-    private void applyPartnerDeviceProfileOverrides(Context ctx, DisplayMetrics dm) {
-        Partner p = Partner.get(ctx.getPackageManager());
-        if (p != null) {
-            DeviceProfile partnerDp = p.getDeviceProfileOverride(dm);
-            if (partnerDp != null) {
-                if (partnerDp.numRows > 0 && partnerDp.numColumns > 0) {
-                    numRows = partnerDp.numRows;
-                    numColumns = partnerDp.numColumns;
-                }
-                if (partnerDp.allAppsShortEdgeCount > 0 && partnerDp.allAppsLongEdgeCount > 0) {
-                    allAppsShortEdgeCount = partnerDp.allAppsShortEdgeCount;
-                    allAppsLongEdgeCount = partnerDp.allAppsLongEdgeCount;
-                }
-                if (partnerDp.iconSize > 0) {
-                    iconSize = partnerDp.iconSize;
-                    // AllApps uses the original non-scaled icon size
-                    allAppsIconSizePx = DynamicGrid.pxFromDp(iconSize, dm);
-                }
-            }
-        }
-    }
-
-    /**
      * Determine the exact visual footprint of the all apps button, taking into account scaling
      * and internal padding of the drawable.
      */
     private void computeAllAppsButtonSize(Context context) {
         Resources res = context.getResources();
         float padding = res.getInteger(R.integer.config_allAppsButtonPaddingPercent) / 100f;
-        LauncherAppState app = LauncherAppState.getInstance();
         allAppsButtonVisualSize = (int) (hotseatIconSizePx * (1 - padding));
     }
 
-    void addCallback(DeviceProfileCallbacks cb) {
-        mCallbacks.add(cb);
-        cb.onAvailableSizeChanged(this);
-    }
-    void removeCallback(DeviceProfileCallbacks cb) {
-        mCallbacks.remove(cb);
-    }
-
-    private int getDeviceOrientation(Context context) {
-        WindowManager windowManager =  (WindowManager)
-                context.getSystemService(Context.WINDOW_SERVICE);
-        Resources resources = context.getResources();
-        DisplayMetrics dm = resources.getDisplayMetrics();
-        Configuration config = resources.getConfiguration();
-        int rotation = windowManager.getDefaultDisplay().getRotation();
-
-        boolean isLandscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE) &&
-                (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180);
-        boolean isRotatedPortrait = (config.orientation == Configuration.ORIENTATION_PORTRAIT) &&
-                (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
-        if (isLandscape || isRotatedPortrait) {
-            return CellLayout.LANDSCAPE;
-        } else {
-            return CellLayout.PORTRAIT;
-        }
-    }
-
-    private void updateAvailableDimensions(Context context) {
-        WindowManager windowManager =  (WindowManager)
-                context.getSystemService(Context.WINDOW_SERVICE);
-        Display display = windowManager.getDefaultDisplay();
-        Resources resources = context.getResources();
-        DisplayMetrics dm = resources.getDisplayMetrics();
-        Configuration config = resources.getConfiguration();
-
-        // There are three possible configurations that the dynamic grid accounts for, portrait,
-        // landscape with the nav bar at the bottom, and landscape with the nav bar at the side.
-        // To prevent waiting for fitSystemWindows(), we make the observation that in landscape,
-        // the height is the smallest height (either with the nav bar at the bottom or to the
-        // side) and otherwise, the height is simply the largest possible height for a portrait
-        // device.
-        Point size = new Point();
-        Point smallestSize = new Point();
-        Point largestSize = new Point();
-        display.getSize(size);
-        display.getCurrentSizeRange(smallestSize, largestSize);
-        availableWidthPx = size.x;
-        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            availableHeightPx = smallestSize.y;
-        } else {
-            availableHeightPx = largestSize.y;
-        }
-
+    private void updateAvailableDimensions(DisplayMetrics dm, Resources res) {
         // Check to see if the icons fit in the new available height.  If not, then we need to
         // shrink the icon size.
         float scale = 1f;
         int drawablePadding = iconDrawablePaddingOriginalPx;
-        updateIconSize(1f, drawablePadding, resources, dm);
-        float usedHeight = (cellHeightPx * numRows);
+        updateIconSize(1f, drawablePadding, res, dm);
+        float usedHeight = (cellHeightPx * inv.numRows);
 
-        Rect workspacePadding = getWorkspacePadding();
+        // We only care about the top and bottom workspace padding, which is not affected by RTL.
+        Rect workspacePadding = getWorkspacePadding(false /* isLayoutRtl */);
         int maxHeight = (availableHeightPx - workspacePadding.top - workspacePadding.bottom);
         if (usedHeight > maxHeight) {
             scale = maxHeight / usedHeight;
             drawablePadding = 0;
         }
-        updateIconSize(scale, drawablePadding, resources, dm);
-
-        // Make the callbacks
-        for (DeviceProfileCallbacks cb : mCallbacks) {
-            cb.onAvailableSizeChanged(this);
-        }
+        updateIconSize(scale, drawablePadding, res, dm);
     }
 
-    private void updateIconSize(float scale, int drawablePadding, Resources resources,
+    private void updateIconSize(float scale, int drawablePadding, Resources res,
                                 DisplayMetrics dm) {
-        iconSizePx = (int) (DynamicGrid.pxFromDp(iconSize, dm) * scale);
-        iconTextSizePx = (int) (DynamicGrid.pxFromSp(iconTextSize, dm) * scale);
+        iconSizePx = (int) (Utilities.pxFromDp(inv.iconSize, dm) * scale);
+        iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
         iconDrawablePaddingPx = drawablePadding;
-        hotseatIconSizePx = (int) (DynamicGrid.pxFromDp(hotseatIconSize, dm) * scale);
+        hotseatIconSizePx = (int) (Utilities.pxFromDp(inv.hotseatIconSize, dm) * scale);
 
         // Search Bar
         searchBarSpaceWidthPx = Math.min(widthPx,
-                resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width));
+                res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_max_width));
         searchBarSpaceHeightPx = getSearchBarTopOffset()
-                + resources.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height);
+                + res.getDimensionPixelSize(R.dimen.dynamic_grid_search_bar_height);
 
         // Calculate the actual text height
         Paint textPaint = new Paint();
@@ -381,7 +210,7 @@
         FontMetrics fm = textPaint.getFontMetrics();
         cellWidthPx = iconSizePx;
         cellHeightPx = iconSizePx + iconDrawablePaddingPx + (int) Math.ceil(fm.bottom - fm.top);
-        final float scaleDps = resources.getDimensionPixelSize(R.dimen.dragViewScale);
+        final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale);
         dragViewScale = (iconSizePx + scaleDps) / iconSizePx;
 
         // Hotseat
@@ -394,123 +223,27 @@
         folderCellHeightPx = cellHeightPx + edgeMarginPx;
         folderBackgroundOffset = -edgeMarginPx;
         folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
-
-        // All Apps
-        allAppsCellWidthPx = allAppsIconSizePx;
-        allAppsCellHeightPx = allAppsIconSizePx + drawablePadding + iconTextSizePx;
-        int maxLongEdgeCellCount =
-                resources.getInteger(R.integer.config_dynamic_grid_max_long_edge_cell_count);
-        int maxShortEdgeCellCount =
-                resources.getInteger(R.integer.config_dynamic_grid_max_short_edge_cell_count);
-        int minEdgeCellCount =
-                resources.getInteger(R.integer.config_dynamic_grid_min_edge_cell_count);
-        int maxRows = (isLandscape ? maxShortEdgeCellCount : maxLongEdgeCellCount);
-        int maxCols = (isLandscape ? maxLongEdgeCellCount : maxShortEdgeCellCount);
-
-        if (allAppsShortEdgeCount > 0 && allAppsLongEdgeCount > 0) {
-            allAppsNumRows = isLandscape ? allAppsShortEdgeCount : allAppsLongEdgeCount;
-            allAppsNumCols = isLandscape ? allAppsLongEdgeCount : allAppsShortEdgeCount;
-        } else {
-            allAppsNumRows = (availableHeightPx - pageIndicatorHeightPx) /
-                    (allAppsCellHeightPx + allAppsCellPaddingPx);
-            allAppsNumRows = Math.max(minEdgeCellCount, Math.min(maxRows, allAppsNumRows));
-            allAppsNumCols = (availableWidthPx) /
-                    (allAppsCellWidthPx + allAppsCellPaddingPx);
-            allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols));
-        }
     }
 
-    void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx,
-                                 int awPx, int ahPx) {
-        Configuration configuration = resources.getConfiguration();
-        isLandscape = (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE);
-        isTablet = resources.getBoolean(R.bool.is_tablet);
-        isLargeTablet = resources.getBoolean(R.bool.is_large_tablet);
-        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            isLayoutRtl = (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
-        } else {
-            isLayoutRtl = false;
-        }
-        widthPx = wPx;
-        heightPx = hPx;
-        availableWidthPx = awPx;
-        availableHeightPx = ahPx;
-
-        updateAvailableDimensions(context);
-    }
-
-    private float dist(PointF p0, PointF p1) {
-        return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
-                (p1.y-p0.y)*(p1.y-p0.y));
-    }
-
-    private float weight(PointF a, PointF b,
-                        float pow) {
-        float d = dist(a, b);
-        if (d == 0f) {
-            return Float.POSITIVE_INFINITY;
-        }
-        return (float) (1f / Math.pow(d, pow));
-    }
-
-    /** Returns the closest device profile given the width and height and a list of profiles */
-    private DeviceProfile findClosestDeviceProfile(float width, float height,
-                                                   ArrayList<DeviceProfileQuery> points) {
-        return findClosestDeviceProfiles(width, height, points).get(0).profile;
-    }
-
-    /** Returns the closest device profiles ordered by closeness to the specified width and height */
-    private ArrayList<DeviceProfileQuery> findClosestDeviceProfiles(float width, float height,
-                                                   ArrayList<DeviceProfileQuery> points) {
-        final PointF xy = new PointF(width, height);
-
-        // Sort the profiles by their closeness to the dimensions
-        ArrayList<DeviceProfileQuery> pointsByNearness = points;
-        Collections.sort(pointsByNearness, new Comparator<DeviceProfileQuery>() {
-            public int compare(DeviceProfileQuery a, DeviceProfileQuery b) {
-                return (int) (dist(xy, a.dimens) - dist(xy, b.dimens));
-            }
-        });
-
-        return pointsByNearness;
-    }
-
-    private float invDistWeightedInterpolate(float width, float height,
-                ArrayList<DeviceProfileQuery> points) {
-        float sum = 0;
-        float weights = 0;
-        float pow = 5;
-        float kNearestNeighbors = 3;
-        final PointF xy = new PointF(width, height);
-
-        ArrayList<DeviceProfileQuery> pointsByNearness = findClosestDeviceProfiles(width, height,
-                points);
-
-        for (int i = 0; i < pointsByNearness.size(); ++i) {
-            DeviceProfileQuery p = pointsByNearness.get(i);
-            if (i < kNearestNeighbors) {
-                float w = weight(xy, p.dimens, pow);
-                if (w == Float.POSITIVE_INFINITY) {
-                    return p.value;
-                }
-                weights += w;
-            }
-        }
-
-        for (int i = 0; i < pointsByNearness.size(); ++i) {
-            DeviceProfileQuery p = pointsByNearness.get(i);
-            if (i < kNearestNeighbors) {
-                float w = weight(xy, p.dimens, pow);
-                sum += w * p.value / weights;
-            }
-        }
-
-        return sum;
+    /**
+     * @param recyclerViewWidth the available width of the AllAppsRecyclerView
+     */
+    public void updateAppsViewNumCols(Resources res, int recyclerViewWidth) {
+        int appsViewLeftMarginPx =
+                res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
+        int allAppsCellWidthGap =
+                res.getDimensionPixelSize(R.dimen.all_apps_icon_width_gap);
+        int availableAppsWidthPx = (recyclerViewWidth > 0) ? recyclerViewWidth : availableWidthPx;
+        int numAppsCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
+                (allAppsIconSizePx + allAppsCellWidthGap);
+        int numPredictiveAppCols = Math.max(inv.minAllAppsPredictionColumns, numAppsCols);
+        allAppsNumCols = numAppsCols;
+        allAppsNumPredictiveCols = numPredictiveAppCols;
     }
 
     /** Returns the search bar top offset */
-    int getSearchBarTopOffset() {
-        if (isTablet() && !isVerticalBarLayout()) {
+    private int getSearchBarTopOffset() {
+        if (isTablet && !isVerticalBarLayout()) {
             return 4 * edgeMarginPx;
         } else {
             return 2 * edgeMarginPx;
@@ -518,14 +251,9 @@
     }
 
     /** Returns the search bar bounds in the current orientation */
-    Rect getSearchBarBounds() {
-        return getSearchBarBounds(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
-    }
-    /** Returns the search bar bounds in the specified orientation */
-    Rect getSearchBarBounds(int orientation) {
+    public Rect getSearchBarBounds(boolean isLayoutRtl) {
         Rect bounds = new Rect();
-        if (orientation == CellLayout.LANDSCAPE &&
-                transposeLayoutWithOrientation) {
+        if (isLandscape && transposeLayoutWithOrientation) {
             if (isLayoutRtl) {
                 bounds.set(availableWidthPx - searchBarSpaceHeightPx, edgeMarginPx,
                         availableWidthPx, availableHeightPx - edgeMarginPx);
@@ -534,16 +262,14 @@
                         availableHeightPx - edgeMarginPx);
             }
         } else {
-            if (isTablet()) {
+            if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
-                int width = (orientation == CellLayout.LANDSCAPE)
-                        ? Math.max(widthPx, heightPx)
-                        : Math.min(widthPx, heightPx);
+                int width = getCurrentWidth();
                 // XXX: If the icon size changes across orientations, we will have to take
                 //      that into account here too.
                 int gap = (int) ((width - 2 * edgeMarginPx -
-                        (numColumns * cellWidthPx)) / (2 * (numColumns + 1)));
+                        (inv.numColumns * cellWidthPx)) / (2 * (inv.numColumns + 1)));
                 bounds.set(edgeMarginPx + gap, getSearchBarTopOffset(),
                         availableWidthPx - (edgeMarginPx + gap),
                         searchBarSpaceHeightPx);
@@ -557,36 +283,11 @@
         return bounds;
     }
 
-    /** Returns the bounds of the workspace page indicators. */
-    Rect getWorkspacePageIndicatorBounds(Rect insets) {
-        Rect workspacePadding = getWorkspacePadding();
-        if (isLandscape && transposeLayoutWithOrientation) {
-            if (isLayoutRtl) {
-                return new Rect(workspacePadding.left, workspacePadding.top,
-                        workspacePadding.left + pageIndicatorHeightPx,
-                        heightPx - workspacePadding.bottom - insets.bottom);
-            } else {
-                int pageIndicatorLeft = widthPx - workspacePadding.right;
-                return new Rect(pageIndicatorLeft, workspacePadding.top,
-                        pageIndicatorLeft + pageIndicatorHeightPx,
-                        heightPx - workspacePadding.bottom - insets.bottom);
-            }
-        } else {
-            int pageIndicatorTop = heightPx - insets.bottom - workspacePadding.bottom;
-            return new Rect(workspacePadding.left, pageIndicatorTop,
-                    widthPx - workspacePadding.right, pageIndicatorTop + pageIndicatorHeightPx);
-        }
-    }
-
     /** Returns the workspace padding in the specified orientation */
-    Rect getWorkspacePadding() {
-        return getWorkspacePadding(isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
-    }
-    Rect getWorkspacePadding(int orientation) {
-        Rect searchBarBounds = getSearchBarBounds(orientation);
+    Rect getWorkspacePadding(boolean isLayoutRtl) {
+        Rect searchBarBounds = getSearchBarBounds(isLayoutRtl);
         Rect padding = new Rect();
-        if (orientation == CellLayout.LANDSCAPE &&
-                transposeLayoutWithOrientation) {
+        if (isLandscape && transposeLayoutWithOrientation) {
             // Pad the left and right of the workspace with search/hotseat bar sizes
             if (isLayoutRtl) {
                 padding.set(hotseatBarHeightPx, edgeMarginPx,
@@ -596,22 +297,18 @@
                         hotseatBarHeightPx, edgeMarginPx);
             }
         } else {
-            if (isTablet()) {
+            if (isTablet) {
                 // Pad the left and right of the workspace to ensure consistent spacing
                 // between all icons
                 float gapScale = 1f + (dragViewScale - 1f) / 2f;
-                int width = (orientation == CellLayout.LANDSCAPE)
-                        ? Math.max(widthPx, heightPx)
-                        : Math.min(widthPx, heightPx);
-                int height = (orientation != CellLayout.LANDSCAPE)
-                        ? Math.max(widthPx, heightPx)
-                        : Math.min(widthPx, heightPx);
+                int width = getCurrentWidth();
+                int height = getCurrentHeight();
                 int paddingTop = searchBarBounds.bottom;
                 int paddingBottom = hotseatBarHeightPx + pageIndicatorHeightPx;
-                int availableWidth = Math.max(0, width - (int) ((numColumns * cellWidthPx) +
-                        (numColumns * gapScale * cellWidthPx)));
+                int availableWidth = Math.max(0, width - (int) ((inv.numColumns * cellWidthPx) +
+                        (inv.numColumns * gapScale * cellWidthPx)));
                 int availableHeight = Math.max(0, height - paddingTop - paddingBottom
-                        - (int) (2 * numRows * cellHeightPx));
+                        - (int) (2 * inv.numRows * cellHeightPx));
                 padding.set(availableWidth / 2, paddingTop + availableHeight / 2,
                         availableWidth / 2, paddingBottom + availableHeight / 2);
             } else {
@@ -625,16 +322,15 @@
         return padding;
     }
 
-    int getWorkspacePageSpacing(int orientation) {
-        if ((orientation == CellLayout.LANDSCAPE &&
-                transposeLayoutWithOrientation) || isLargeTablet()) {
+    private int getWorkspacePageSpacing(boolean isLayoutRtl) {
+        if ((isLandscape && transposeLayoutWithOrientation) || isLargeTablet) {
             // In landscape mode the page spacing is set to the default.
             return defaultPageSpacingPx;
         } else {
             // In portrait, we want the pages spaced such that there is no
             // overhang of the previous / next page into the current page viewport.
             // We assume symmetrical padding in portrait mode.
-            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding().left);
+            return Math.max(defaultPageSpacingPx, 2 * getWorkspacePadding(isLayoutRtl).left);
         }
     }
 
@@ -645,8 +341,8 @@
         return new Rect(0, availableHeightPx - zoneHeight, 0, availableHeightPx);
     }
 
-    float getOverviewModeScale() {
-        Rect workspacePadding = getWorkspacePadding();
+    public float getOverviewModeScale(boolean isLayoutRtl) {
+        Rect workspacePadding = getWorkspacePadding(isLayoutRtl);
         Rect overviewBar = getOverviewModeButtonBarRect();
         int pageSpace = availableHeightPx - workspacePadding.top - workspacePadding.bottom;
         return (overviewModeScaleFactor * (pageSpace - overviewBar.height())) / pageSpace;
@@ -663,32 +359,26 @@
         }
     }
 
-    int calculateCellWidth(int width, int countX) {
+    public static int calculateCellWidth(int width, int countX) {
         return width / countX;
     }
-    int calculateCellHeight(int height, int countY) {
+    public static int calculateCellHeight(int height, int countY) {
         return height / countY;
     }
 
-    boolean isPhone() {
-        return !isTablet && !isLargeTablet;
-    }
-    boolean isTablet() {
-        return isTablet;
-    }
-    boolean isLargeTablet() {
-        return isLargeTablet;
-    }
-
+    /**
+     * When {@code true}, hotseat is on the bottom row when in landscape mode.
+     * If {@code false}, hotseat is on the right column when in landscape mode.
+     */
     boolean isVerticalBarLayout() {
         return isLandscape && transposeLayoutWithOrientation;
     }
 
     boolean shouldFadeAdjacentWorkspaceScreens() {
-        return isVerticalBarLayout() || isLargeTablet();
+        return isVerticalBarLayout() || isLargeTablet;
     }
 
-    int getVisibleChildCount(ViewGroup parent) {
+    private int getVisibleChildCount(ViewGroup parent) {
         int visibleChildren = 0;
         for (int i = 0; i < parent.getChildCount(); i++) {
             if (parent.getChildAt(i).getVisibility() != View.GONE) {
@@ -700,25 +390,31 @@
 
     public void layout(Launcher launcher) {
         FrameLayout.LayoutParams lp;
-        Resources res = launcher.getResources();
         boolean hasVerticalBarLayout = isVerticalBarLayout();
+        final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
 
         // Layout the search bar space
         View searchBar = launcher.getSearchBar();
         lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams();
         if (hasVerticalBarLayout) {
-            // Vertical search bar space
-            lp.gravity = Gravity.TOP | Gravity.LEFT;
+            // Vertical search bar space -- The search bar is fixed in the layout to be on the left
+            //                              of the screen regardless of RTL
+            lp.gravity = Gravity.LEFT;
             lp.width = searchBarSpaceHeightPx;
-            lp.height = LayoutParams.WRAP_CONTENT;
 
             LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
             targets.setOrientation(LinearLayout.VERTICAL);
+            FrameLayout.LayoutParams targetsLp = (FrameLayout.LayoutParams) targets.getLayoutParams();
+            targetsLp.gravity = Gravity.TOP;
+            targetsLp.height = LayoutParams.WRAP_CONTENT;
+
         } else {
             // Horizontal search bar space
-            lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
-            lp.width = searchBarSpaceWidthPx;
+            lp.gravity = Gravity.TOP;
             lp.height = searchBarSpaceHeightPx;
+
+            LinearLayout targets = (LinearLayout) searchBar.findViewById(R.id.drag_target_bar);
+            targets.getLayoutParams().width = searchBarSpaceWidthPx;
         }
         searchBar.setLayoutParams(lp);
 
@@ -726,22 +422,22 @@
         PagedView workspace = (PagedView) launcher.findViewById(R.id.workspace);
         lp = (FrameLayout.LayoutParams) workspace.getLayoutParams();
         lp.gravity = Gravity.CENTER;
-        int orientation = isLandscape ? CellLayout.LANDSCAPE : CellLayout.PORTRAIT;
-        Rect padding = getWorkspacePadding(orientation);
+        Rect padding = getWorkspacePadding(isLayoutRtl);
         workspace.setLayoutParams(lp);
         workspace.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-        workspace.setPageSpacing(getWorkspacePageSpacing(orientation));
+        workspace.setPageSpacing(getWorkspacePageSpacing(isLayoutRtl));
 
         // Layout the hotseat
         View hotseat = launcher.findViewById(R.id.hotseat);
         lp = (FrameLayout.LayoutParams) hotseat.getLayoutParams();
         if (hasVerticalBarLayout) {
-            // Vertical hotseat
-            lp.gravity = Gravity.END;
+            // Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
+            //                     screen regardless of RTL
+            lp.gravity = Gravity.RIGHT;
             lp.width = hotseatBarHeightPx;
             lp.height = LayoutParams.MATCH_PARENT;
             hotseat.findViewById(R.id.layout).setPadding(0, 2 * edgeMarginPx, 0, 2 * edgeMarginPx);
-        } else if (isTablet()) {
+        } else if (isTablet) {
             // Pad the hotseat with the workspace padding calculated above
             lp.gravity = Gravity.BOTTOM;
             lp.width = LayoutParams.MATCH_PARENT;
@@ -777,64 +473,6 @@
             }
         }
 
-        // Layout AllApps
-        AppsCustomizeTabHost host = (AppsCustomizeTabHost)
-                launcher.findViewById(R.id.apps_customize_pane);
-        if (host != null) {
-            // Center the all apps page indicator
-            int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f,
-                    (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX)));
-            pageIndicator = host.findViewById(R.id.apps_customize_page_indicator);
-            if (pageIndicator != null) {
-                LinearLayout.LayoutParams lllp = (LinearLayout.LayoutParams) pageIndicator.getLayoutParams();
-                lllp.width = LayoutParams.WRAP_CONTENT;
-                lllp.height = pageIndicatorHeight;
-                pageIndicator.setLayoutParams(lllp);
-            }
-
-            AppsCustomizePagedView pagedView = (AppsCustomizePagedView)
-                    host.findViewById(R.id.apps_customize_pane_content);
-
-            FrameLayout fakePageContainer = (FrameLayout)
-                    host.findViewById(R.id.fake_page_container);
-            FrameLayout fakePage = (FrameLayout) host.findViewById(R.id.fake_page);
-
-            padding = new Rect();
-            if (pagedView != null) {
-                // Constrain the dimensions of all apps so that it does not span the full width
-                int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) /
-                        (2 * (allAppsNumCols + 1));
-                int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) /
-                        (2 * (allAppsNumRows + 1));
-                paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f));
-                paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f));
-                int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR));
-                int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2;
-                // Only adjust the side paddings on landscape phones, or tablets
-                if ((isTablet() || isLandscape) && gridPaddingLR > (allAppsCellWidthPx / 4)) {
-                    padding.left = padding.right = gridPaddingLR;
-                }
-
-                // The icons are centered, so we can't just offset by the page indicator height
-                // because the empty space will actually be pageIndicatorHeight + paddingTB
-                padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB);
-
-                pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
-                fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel));
-
-                // Horizontal padding for the whole paged view
-                int pagedFixedViewPadding =
-                        res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding);
-
-                padding.left += pagedFixedViewPadding;
-                padding.right += pagedFixedViewPadding;
-
-                pagedView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-                fakePageContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-
-            }
-        }
-
         // Layout the Overview Mode
         ViewGroup overviewMode = launcher.getOverviewPanel();
         if (overviewMode != null) {
@@ -875,4 +513,16 @@
             }
         }
     }
+
+    private int getCurrentWidth() {
+        return isLandscape
+                ? Math.max(widthPx, heightPx)
+                : Math.min(widthPx, heightPx);
+    }
+
+    private int getCurrentHeight() {
+        return isLandscape
+                ? Math.min(widthPx, heightPx)
+                : Math.max(widthPx, heightPx);
+    }
 }
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index 480dce9..2191455 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -34,6 +34,8 @@
 import android.view.ViewConfiguration;
 import android.view.inputmethod.InputMethodManager;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -49,8 +51,8 @@
     /** Indicates the drag is a copy.  */
     public static int DRAG_ACTION_COPY = 1;
 
-    private static final int SCROLL_DELAY = 500;
-    private static final int RESCROLL_DELAY = PagedView.PAGE_SNAP_ANIMATION_DURATION + 150;
+    public static final int SCROLL_DELAY = 500;
+    public static final int RESCROLL_DELAY = PagedView.PAGE_SNAP_ANIMATION_DURATION + 150;
 
     private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
 
@@ -63,16 +65,20 @@
 
     private static final float MAX_FLING_DEGREES = 35f;
 
-    private Launcher mLauncher;
+    @Thunk Launcher mLauncher;
     private Handler mHandler;
 
     // temporaries to avoid gc thrash
     private Rect mRectTemp = new Rect();
     private final int[] mCoordinatesTemp = new int[2];
+    private final boolean mIsRtl;
 
     /** Whether or not we're dragging. */
     private boolean mDragging;
 
+    /** Whether or not this is an accessible drag operation */
+    private boolean mIsAccessibleDrag;
+
     /** X coordinate of the down event. */
     private int mMotionDownX;
 
@@ -99,17 +105,17 @@
 
     private View mMoveTarget;
 
-    private DragScroller mDragScroller;
-    private int mScrollState = SCROLL_OUTSIDE_ZONE;
+    @Thunk DragScroller mDragScroller;
+    @Thunk int mScrollState = SCROLL_OUTSIDE_ZONE;
     private ScrollRunnable mScrollRunnable = new ScrollRunnable();
 
     private DropTarget mLastDropTarget;
 
     private InputMethodManager mInputMethodManager;
 
-    private int mLastTouch[] = new int[2];
-    private long mLastTouchUpTime = -1;
-    private int mDistanceSinceScroll = 0;
+    @Thunk int mLastTouch[] = new int[2];
+    @Thunk long mLastTouchUpTime = -1;
+    @Thunk int mDistanceSinceScroll = 0;
 
     private int mTmpPoint[] = new int[2];
     private Rect mDragLayerRect = new Rect();
@@ -120,7 +126,7 @@
     /**
      * Interface to receive notifications when a drag starts or stops
      */
-    interface DragListener {
+    public interface DragListener {
         /**
          * A drag has begun
          *
@@ -152,6 +158,7 @@
         float density = r.getDisplayMetrics().density;
         mFlingToDeleteThresholdVelocity =
                 (int) (r.getInteger(R.integer.config_flingToDeleteMinVelocity) * density);
+        mIsRtl = Utilities.isRtl(r);
     }
 
     public boolean dragging() {
@@ -167,22 +174,21 @@
      * @param dragInfo The data associated with the object that is being dragged
      * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
      *        {@link #DRAG_ACTION_COPY}
+     * @param viewImageBounds the position of the image inside the view
      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
      */
-    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo, int dragAction,
-            Point extraPadding, float initialDragViewScale) {
+    public void startDrag(View v, Bitmap bmp, DragSource source, Object dragInfo,
+            Rect viewImageBounds, int dragAction, float initialDragViewScale) {
         int[] loc = mCoordinatesTemp;
         mLauncher.getDragLayer().getLocationInDragLayer(v, loc);
-        int viewExtraPaddingLeft = extraPadding != null ? extraPadding.x : 0;
-        int viewExtraPaddingTop = extraPadding != null ? extraPadding.y : 0;
-        int dragLayerX = loc[0] + v.getPaddingLeft() + viewExtraPaddingLeft +
-                (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
-        int dragLayerY = loc[1] + v.getPaddingTop() + viewExtraPaddingTop +
-                (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
+        int dragLayerX = loc[0] + viewImageBounds.left
+                + (int) ((initialDragViewScale * bmp.getWidth() - bmp.getWidth()) / 2);
+        int dragLayerY = loc[1] + viewImageBounds.top
+                + (int) ((initialDragViewScale * bmp.getHeight() - bmp.getHeight()) / 2);
 
         startDrag(bmp, dragLayerX, dragLayerY, source, dragInfo, dragAction, null,
-                null, initialDragViewScale);
+                null, initialDragViewScale, false);
 
         if (dragAction == DRAG_ACTION_MOVE) {
             v.setVisibility(View.GONE);
@@ -202,10 +208,11 @@
      *        {@link #DRAG_ACTION_COPY}
      * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
      *          Makes dragging feel more precise, e.g. you can clip out a transparent border
+     * @param accessible whether this drag should occur in accessibility mode
      */
     public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
             DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
-            float initialDragViewScale) {
+            float initialDragViewScale, boolean accessible) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
         }
@@ -228,12 +235,21 @@
         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
 
         mDragging = true;
+        mIsAccessibleDrag = accessible;
 
         mDragObject = new DropTarget.DragObject();
 
         mDragObject.dragComplete = false;
-        mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
-        mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
+        if (mIsAccessibleDrag) {
+            // For an accessible drag, we assume the view is being dragged from the center.
+            mDragObject.xOffset = b.getWidth() / 2;
+            mDragObject.yOffset = b.getHeight() / 2;
+            mDragObject.accessibleDrag = true;
+        } else {
+            mDragObject.xOffset = mMotionDownX - (dragLayerX + dragRegionLeft);
+            mDragObject.yOffset = mMotionDownY - (dragLayerY + dragRegionTop);
+        }
+
         mDragObject.dragSource = source;
         mDragObject.dragInfo = dragInfo;
 
@@ -349,6 +365,7 @@
     private void endDrag() {
         if (mDragging) {
             mDragging = false;
+            mIsAccessibleDrag = false;
             clearScrollRunnable();
             boolean isDeferred = false;
             if (mDragObject.dragView != null) {
@@ -361,7 +378,7 @@
 
             // Only end the drag if we are not deferred
             if (!isDeferred) {
-                for (DragListener listener : mListeners) {
+                for (DragListener listener : new ArrayList<>(mListeners)) {
                     listener.onDragEnd();
                 }
             }
@@ -378,13 +395,13 @@
 
         if (mDragObject.deferDragViewCleanupPostAnimation) {
             // If we skipped calling onDragEnd() before, do it now
-            for (DragListener listener : mListeners) {
+            for (DragListener listener : new ArrayList<>(mListeners)) {
                 listener.onDragEnd();
             }
         }
     }
 
-    void onDeferredEndFling(DropTarget.DragObject d) {
+    public void onDeferredEndFling(DropTarget.DragObject d) {
         d.dragSource.onFlingToDeleteCompleted();
     }
 
@@ -421,6 +438,10 @@
                     + mDragging);
         }
 
+        if (mIsAccessibleDrag) {
+            return false;
+        }
+
         // Update the velocity tracker
         acquireVelocityTrackerAndAddMovement(ev);
 
@@ -442,7 +463,7 @@
                 mLastTouchUpTime = System.currentTimeMillis();
                 if (mDragging) {
                     PointF vec = isFlingingToDelete(mDragObject.dragSource);
-                    if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragInfo)) {
+                    if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
                         vec = null;
                     }
                     if (vec != null) {
@@ -493,8 +514,7 @@
         checkTouchMove(dropTarget);
 
         // Check if we are hovering over the scroll areas
-        mDistanceSinceScroll +=
-            Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+        mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
         mLastTouch[0] = x;
         mLastTouch[1] = y;
         checkScrollState(x, y);
@@ -525,13 +545,12 @@
         mLastDropTarget = dropTarget;
     }
 
-    private void checkScrollState(int x, int y) {
+    @Thunk void checkScrollState(int x, int y) {
         final int slop = ViewConfiguration.get(mLauncher).getScaledWindowTouchSlop();
         final int delay = mDistanceSinceScroll < slop ? RESCROLL_DELAY : SCROLL_DELAY;
         final DragLayer dragLayer = mLauncher.getDragLayer();
-        final boolean isRtl = (dragLayer.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
-        final int forwardDirection = isRtl ? SCROLL_RIGHT : SCROLL_LEFT;
-        final int backwardsDirection = isRtl ? SCROLL_LEFT : SCROLL_RIGHT;
+        final int forwardDirection = mIsRtl ? SCROLL_RIGHT : SCROLL_LEFT;
+        final int backwardsDirection = mIsRtl ? SCROLL_LEFT : SCROLL_RIGHT;
 
         if (x < mScrollZone) {
             if (mScrollState == SCROLL_OUTSIDE_ZONE) {
@@ -560,7 +579,7 @@
      * Call this from a drag source view.
      */
     public boolean onTouchEvent(MotionEvent ev) {
-        if (!mDragging) {
+        if (!mDragging || mIsAccessibleDrag) {
             return false;
         }
 
@@ -596,7 +615,7 @@
 
             if (mDragging) {
                 PointF vec = isFlingingToDelete(mDragObject.dragSource);
-                if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragInfo)) {
+                if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
                     vec = null;
                 }
                 if (vec != null) {
@@ -617,6 +636,35 @@
     }
 
     /**
+     * Since accessible drag and drop won't cause the same sequence of touch events, we manually
+     * inject the appropriate state.
+     */
+    public void prepareAccessibleDrag(int x, int y) {
+        mMotionDownX = x;
+        mMotionDownY = y;
+        mLastDropTarget = null;
+    }
+
+    /**
+     * As above, since accessible drag and drop won't cause the same sequence of touch events,
+     * we manually ensure appropriate drag and drop events get emulated for accessible drag.
+     */
+    public void completeAccessibleDrag(int[] location) {
+        final int[] coordinates = mCoordinatesTemp;
+
+        // We make sure that we prime the target for drop.
+        DropTarget dropTarget = findDropTarget(location[0], location[1], coordinates);
+        mDragObject.x = coordinates[0];
+        mDragObject.y = coordinates[1];
+        checkTouchMove(dropTarget);
+
+        dropTarget.prepareAccessibilityDrop();
+        // Perform the drop
+        drop(location[0], location[1]);
+        endDrag();
+    }
+
+    /**
      * Determines whether the user flung the current item to delete it.
      *
      * @return the vector at which the item was flung, or null if no fling was detected.
@@ -662,8 +710,7 @@
         mDragObject.dragComplete = true;
         mFlingToDeleteDropTarget.onDragExit(mDragObject);
         if (mFlingToDeleteDropTarget.acceptDrop(mDragObject)) {
-            mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, mDragObject.x, mDragObject.y,
-                    vel);
+            mFlingToDeleteDropTarget.onFlingToDelete(mDragObject, vel);
             accepted = true;
         }
         mDragObject.dragSource.onDropCompleted((View) mFlingToDeleteDropTarget, mDragObject, true,
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index a352b79..aaa14e6 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -38,7 +39,8 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import com.android.launcher3.InsettableFrameLayout.LayoutParams;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
@@ -46,30 +48,34 @@
  * A ViewGroup that coordinates dragging across its descendants
  */
 public class DragLayer extends InsettableFrameLayout {
-    private DragController mDragController;
-    private int[] mTmpXY = new int[2];
+
+    public static final int ANIMATION_END_DISAPPEAR = 0;
+    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
+
+    // Scrim color without any alpha component.
+    private static final int SCRIM_COLOR = Color.BLACK & 0x00FFFFFF;
+
+    private final int[] mTmpXY = new int[2];
+
+    @Thunk DragController mDragController;
 
     private int mXDown, mYDown;
     private Launcher mLauncher;
 
     // Variables relating to resizing widgets
-    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
-            new ArrayList<AppWidgetResizeFrame>();
+    private final ArrayList<AppWidgetResizeFrame> mResizeFrames = new ArrayList<>();
+    private final boolean mIsRtl;
     private AppWidgetResizeFrame mCurrentResizeFrame;
 
     // Variables relating to animation of views after drop
     private ValueAnimator mDropAnim = null;
-    private ValueAnimator mFadeOutAnim = null;
-    private TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
-    private DragView mDropView = null;
-    private int mAnchorViewInitialScrollX = 0;
-    private View mAnchorView = null;
+    private final TimeInterpolator mCubicEaseOutInterpolator = new DecelerateInterpolator(1.5f);
+    @Thunk DragView mDropView = null;
+    @Thunk int mAnchorViewInitialScrollX = 0;
+    @Thunk View mAnchorView = null;
 
     private boolean mHoverPointClosesFolder = false;
-    private Rect mHitRect = new Rect();
-    public static final int ANIMATION_END_DISAPPEAR = 0;
-    public static final int ANIMATION_END_FADE_OUT = 1;
-    public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
+    private final Rect mHitRect = new Rect();
 
     private TouchCompleteListener mTouchCompleteListener;
 
@@ -78,10 +84,10 @@
     private int mChildCountOnLastUpdate = -1;
 
     // Darkening scrim
-    private Drawable mBackground;
     private float mBackgroundAlpha = 0;
 
     // Related to adjacent page hints
+    private final Rect mScrollChildPosition = new Rect();
     private boolean mInScrollArea;
     private boolean mShowPageHints;
     private Drawable mLeftHoverDrawable;
@@ -109,7 +115,7 @@
         mRightHoverDrawable = res.getDrawable(R.drawable.page_hover_right);
         mLeftHoverDrawableActive = res.getDrawable(R.drawable.page_hover_left_active);
         mRightHoverDrawableActive = res.getDrawable(R.drawable.page_hover_right_active);
-        mBackground = res.getDrawable(R.drawable.apps_customize_bg);
+        mIsRtl = Utilities.isRtl(res);
     }
 
     public void setup(Launcher launcher, DragController controller) {
@@ -152,6 +158,14 @@
         return false;
     }
 
+    private boolean isEventOverDropTargetBar(MotionEvent ev) {
+        getDescendantRectRelativeToSelf(mLauncher.getSearchBar(), mHitRect);
+        if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) {
+            return true;
+        }
+        return false;
+    }
+
     public void setBlockTouch(boolean block) {
         mBlockTouches = block;
     }
@@ -187,10 +201,16 @@
                 }
             }
 
-            getDescendantRectRelativeToSelf(currentFolder, hitRect);
             if (!isEventOverFolder(currentFolder, ev)) {
-                mLauncher.closeFolder();
-                return true;
+                if (isInAccessibleDrag()) {
+                    // Do not close the folder if in drag and drop.
+                    if (!isEventOverDropTargetBar(ev)) {
+                        return true;
+                    }
+                } else {
+                    mLauncher.closeFolder();
+                    return true;
+                }
             }
         }
         return false;
@@ -227,11 +247,12 @@
                         getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
             if (accessibilityManager.isTouchExplorationEnabled()) {
                 final int action = ev.getAction();
-                boolean isOverFolder;
+                boolean isOverFolderOrSearchBar;
                 switch (action) {
                     case MotionEvent.ACTION_HOVER_ENTER:
-                        isOverFolder = isEventOverFolder(currentFolder, ev);
-                        if (!isOverFolder) {
+                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
+                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+                        if (!isOverFolderOrSearchBar) {
                             sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
                             mHoverPointClosesFolder = true;
                             return true;
@@ -239,12 +260,13 @@
                         mHoverPointClosesFolder = false;
                         break;
                     case MotionEvent.ACTION_HOVER_MOVE:
-                        isOverFolder = isEventOverFolder(currentFolder, ev);
-                        if (!isOverFolder && !mHoverPointClosesFolder) {
+                        isOverFolderOrSearchBar = isEventOverFolder(currentFolder, ev) ||
+                            (isInAccessibleDrag() && isEventOverDropTargetBar(ev));
+                        if (!isOverFolderOrSearchBar && !mHoverPointClosesFolder) {
                             sendTapOutsideFolderAccessibilityEvent(currentFolder.isEditingName());
                             mHoverPointClosesFolder = true;
                             return true;
-                        } else if (!isOverFolder) {
+                        } else if (!isOverFolderOrSearchBar) {
                             return true;
                         }
                         mHoverPointClosesFolder = false;
@@ -267,6 +289,12 @@
         }
     }
 
+    private boolean isInAccessibleDrag() {
+        LauncherAccessibilityDelegate delegate = LauncherAppState
+                .getInstance().getAccessibilityDelegate();
+        return delegate != null && delegate.isInAccessibleDrag();
+    }
+
     @Override
     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
         Folder currentFolder = mLauncher.getWorkspace().getOpenFolder();
@@ -274,6 +302,10 @@
             if (child == currentFolder) {
                 return super.onRequestSendAccessibilityEvent(child, event);
             }
+
+            if (isInAccessibleDrag() && child instanceof SearchDropTargetBar) {
+                return super.onRequestSendAccessibilityEvent(child, event);
+            }
             // Skip propagating onRequestSendAccessibilityEvent all for other children
             // when a folder is open
             return false;
@@ -287,6 +319,10 @@
         if (currentFolder != null) {
             // Only add the folder as a child for accessibility when it is open
             childrenForAccessibility.add(currentFolder);
+
+            if (isInAccessibleDrag()) {
+                childrenForAccessibility.add(mLauncher.getSearchBar());
+            }
         } else {
             super.addChildrenForAccessibility(childrenForAccessibility);
         }
@@ -656,8 +692,7 @@
             final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
 
         // Calculate the duration of the animation based on the object's distance
-        final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
-                Math.pow(to.top - from.top, 2));
+        final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
         final Resources res = getResources();
         final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
 
@@ -725,7 +760,6 @@
             final int animationEndStyle, View anchorView) {
         // Clean up the previous animations
         if (mDropAnim != null) mDropAnim.cancel();
-        if (mFadeOutAnim != null) mFadeOutAnim.cancel();
 
         // Show the drop view if it was previously hidden
         mDropView = view;
@@ -753,9 +787,6 @@
                 case ANIMATION_END_DISAPPEAR:
                     clearAnimatedView();
                     break;
-                case ANIMATION_END_FADE_OUT:
-                    fadeOutDragView();
-                    break;
                 case ANIMATION_END_REMAIN_VISIBLE:
                     break;
                 }
@@ -779,31 +810,6 @@
         return mDropView;
     }
 
-    private void fadeOutDragView() {
-        mFadeOutAnim = new ValueAnimator();
-        mFadeOutAnim.setDuration(150);
-        mFadeOutAnim.setFloatValues(0f, 1f);
-        mFadeOutAnim.removeAllUpdateListeners();
-        mFadeOutAnim.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = (Float) animation.getAnimatedValue();
-
-                float alpha = 1 - percent;
-                mDropView.setAlpha(alpha);
-            }
-        });
-        mFadeOutAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                if (mDropView != null) {
-                    mDragController.onDeferredEndDrag(mDropView);
-                }
-                mDropView = null;
-                invalidate();
-            }
-        });
-        mFadeOutAnim.start();
-    }
-
     @Override
     public void onChildViewAdded(View parent, View child) {
         super.onChildViewAdded(parent, child);
@@ -880,6 +886,9 @@
 
     void showPageHints() {
         mShowPageHints = true;
+        Workspace workspace = mLauncher.getWorkspace();
+        getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.numCustomPages()),
+                mScrollChildPosition);
         invalidate();
     }
 
@@ -888,21 +897,12 @@
         invalidate();
     }
 
-    /**
-     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
-     */
-    private boolean isLayoutRtl() {
-        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        // Draw the background gradient below children.
-        if (mBackground != null && mBackgroundAlpha > 0.0f) {
+        // Draw the background below children.
+        if (mBackgroundAlpha > 0.0f) {
             int alpha = (int) (mBackgroundAlpha * 255);
-            mBackground.setAlpha(alpha);
-            mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
-            mBackground.draw(canvas);
+            canvas.drawColor((alpha << 24) | SCRIM_COLOR);
         }
 
         super.dispatchDraw(canvas);
@@ -912,27 +912,22 @@
         if (mShowPageHints) {
             Workspace workspace = mLauncher.getWorkspace();
             int width = getMeasuredWidth();
-            Rect childRect = new Rect();
-            getDescendantRectRelativeToSelf(workspace.getChildAt(workspace.getChildCount() - 1),
-                    childRect);
-
             int page = workspace.getNextPage();
-            final boolean isRtl = isLayoutRtl();
-            CellLayout leftPage = (CellLayout) workspace.getChildAt(isRtl ? page + 1 : page - 1);
-            CellLayout rightPage = (CellLayout) workspace.getChildAt(isRtl ? page - 1 : page + 1);
+            CellLayout leftPage = (CellLayout) workspace.getChildAt(mIsRtl ? page + 1 : page - 1);
+            CellLayout rightPage = (CellLayout) workspace.getChildAt(mIsRtl ? page - 1 : page + 1);
 
             if (leftPage != null && leftPage.isDragTarget()) {
                 Drawable left = mInScrollArea && leftPage.getIsDragOverlapping() ?
                         mLeftHoverDrawableActive : mLeftHoverDrawable;
-                left.setBounds(0, childRect.top,
-                        left.getIntrinsicWidth(), childRect.bottom);
+                left.setBounds(0, mScrollChildPosition.top,
+                        left.getIntrinsicWidth(), mScrollChildPosition.bottom);
                 left.draw(canvas);
             }
             if (rightPage != null && rightPage.isDragTarget()) {
                 Drawable right = mInScrollArea && rightPage.getIsDragOverlapping() ?
                         mRightHoverDrawableActive : mRightHoverDrawable;
                 right.setBounds(width - right.getIntrinsicWidth(),
-                        childRect.top, width, childRect.bottom);
+                        mScrollChildPosition.top, width, mScrollChildPosition.bottom);
                 right.draw(canvas);
             }
         }
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 7369eea..2a1346e 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -22,9 +22,9 @@
 
 /**
  * Interface defining an object that can originate a drag.
- *
  */
 public interface DragSource {
+
     /**
      * @return whether items dragged from this source supports
      */
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index ea34e46..dfa8202 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -16,25 +16,35 @@
 
 package com.android.launcher3;
 
+import android.animation.FloatArrayEvaluator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
+import android.os.Build;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 
+import com.android.launcher3.util.Thunk;
+
+import java.util.Arrays;
+
 public class DragView extends View {
-    private static float sDragAlpha = 1f;
+    public static int COLOR_CHANGE_DURATION = 120;
+
+    @Thunk static float sDragAlpha = 1f;
 
     private Bitmap mBitmap;
     private Bitmap mCrossFadeBitmap;
-    private Paint mPaint;
+    @Thunk Paint mPaint;
     private int mRegistrationX;
     private int mRegistrationY;
 
@@ -42,16 +52,19 @@
     private Rect mDragRegion = null;
     private DragLayer mDragLayer = null;
     private boolean mHasDrawn = false;
-    private float mCrossFadeProgress = 0f;
+    @Thunk float mCrossFadeProgress = 0f;
 
     ValueAnimator mAnim;
-    private float mOffsetX = 0.0f;
-    private float mOffsetY = 0.0f;
+    @Thunk float mOffsetX = 0.0f;
+    @Thunk float mOffsetY = 0.0f;
     private float mInitialScale = 1f;
     // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
     // size.  This is ignored for non-icons.
     private float mIntrinsicIconScale = 1f;
 
+    @Thunk float[] mCurrentFilter;
+    private ValueAnimator mFilterAnimator;
+
     /**
      * Construct the drag view.
      * <p>
@@ -63,6 +76,7 @@
      * @param registrationX The x coordinate of the registration point.
      * @param registrationY The y coordinate of the registration point.
      */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public DragView(Launcher launcher, Bitmap bitmap, int registrationX, int registrationY,
             int left, int top, int width, int height, final float initialScale) {
         super(launcher);
@@ -70,8 +84,6 @@
         mInitialScale = initialScale;
 
         final Resources res = getResources();
-        final float offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
-        final float offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
         final float scaleDps = res.getDimensionPixelSize(R.dimen.dragViewScale);
         final float scale = (width + scaleDps) / width;
 
@@ -87,8 +99,8 @@
             public void onAnimationUpdate(ValueAnimator animation) {
                 final float value = (Float) animation.getAnimatedValue();
 
-                final int deltaX = (int) ((value * offsetX) - mOffsetX);
-                final int deltaY = (int) ((value * offsetY) - mOffsetY);
+                final int deltaX = (int) (-mOffsetX);
+                final int deltaY = (int) (-mOffsetY);
 
                 mOffsetX += deltaX;
                 mOffsetY += deltaY;
@@ -118,6 +130,10 @@
         int ms = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
         measure(ms, ms);
         mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
+
+        if (Utilities.isLmpOrAbove()) {
+            setElevation(getResources().getDimension(R.dimen.drag_elevation));
+        }
     }
 
     /** Sets the scale of the view over the normal workspace icon size. */
@@ -229,11 +245,49 @@
             mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
         }
         if (color != 0) {
-            mPaint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+            ColorMatrix m1 = new ColorMatrix();
+            m1.setSaturation(0);
+
+            ColorMatrix m2 = new ColorMatrix();
+            setColorScale(color, m2);
+            m1.postConcat(m2);
+
+            if (Utilities.isLmpOrAbove()) {
+                animateFilterTo(m1.getArray());
+            } else {
+                mPaint.setColorFilter(new ColorMatrixColorFilter(m1));
+                invalidate();
+            }
         } else {
-            mPaint.setColorFilter(null);
+            if (!Utilities.isLmpOrAbove() || mCurrentFilter == null) {
+                mPaint.setColorFilter(null);
+                invalidate();
+            } else {
+                animateFilterTo(new ColorMatrix().getArray());
+            }
         }
-        invalidate();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void animateFilterTo(float[] targetFilter) {
+        float[] oldFilter = mCurrentFilter == null ? new ColorMatrix().getArray() : mCurrentFilter;
+        mCurrentFilter = Arrays.copyOf(oldFilter, oldFilter.length);
+
+        if (mFilterAnimator != null) {
+            mFilterAnimator.cancel();
+        }
+        mFilterAnimator = ValueAnimator.ofObject(new FloatArrayEvaluator(mCurrentFilter),
+                oldFilter, targetFilter);
+        mFilterAnimator.setDuration(COLOR_CHANGE_DURATION);
+        mFilterAnimator.addUpdateListener(new AnimatorUpdateListener() {
+
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mPaint.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+                invalidate();
+            }
+        });
+        mFilterAnimator.start();
     }
 
     public boolean hasDrawn() {
@@ -300,5 +354,9 @@
             mDragLayer.removeView(DragView.this);
         }
     }
-}
 
+    public static void setColorScale(int color, ColorMatrix target) {
+        target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+                Color.blue(color) / 255f, Color.alpha(color) / 255f);
+    }
+}
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index 64f0ac8..c8fac54 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -16,10 +16,8 @@
 
 package com.android.launcher3;
 
-import android.content.Context;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.util.Log;
 
 /**
  * Interface defining an object that can receive a drag.
@@ -29,7 +27,7 @@
 
     public static final String TAG = "DropTarget";
 
-    class DragObject {
+    public static class DragObject {
         public int x = -1;
         public int y = -1;
 
@@ -54,6 +52,9 @@
         /** Where the drag originated */
         public DragSource dragSource = null;
 
+        /** The object is part of an accessible drag operation */
+        public boolean accessibleDrag;
+
         /** Post drag animation runnable */
         public Runnable postAnimationRunnable = null;
 
@@ -65,42 +66,28 @@
 
         public DragObject() {
         }
-    }
 
-    public static class DragEnforcer implements DragController.DragListener {
-        int dragParity = 0;
+        /**
+         * This is used to compute the visual center of the dragView. This point is then
+         * used to visualize drop locations and determine where to drop an item. The idea is that
+         * the visual center represents the user's interpretation of where the item is, and hence
+         * is the appropriate point to use when determining drop location.
+         */
+        public final float[] getVisualCenter(float[] recycle) {
+            final float res[] = (recycle == null) ? new float[2] : recycle;
 
-        public DragEnforcer(Context context) {
-            Launcher launcher = (Launcher) context;
-            launcher.getDragController().addDragListener(this);
-        }
+            // These represent the visual top and left of drag view if a dragRect was provided.
+            // If a dragRect was not provided, then they correspond to the actual view left and
+            // top, as the dragRect is in that case taken to be the entire dragView.
+            // R.dimen.dragViewOffsetY.
+            int left = x - xOffset;
+            int top = y - yOffset;
 
-        void onDragEnter() {
-            dragParity++;
-            if (dragParity != 1) {
-                Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
-            }
-        }
+            // In order to find the visual center, we shift by half the dragRect
+            res[0] = left + dragView.getDragRegion().width() / 2;
+            res[1] = top + dragView.getDragRegion().height() / 2;
 
-        void onDragExit() {
-            dragParity--;
-            if (dragParity != 0) {
-                Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
-            }
-        }
-
-        @Override
-        public void onDragStart(DragSource source, Object info, int dragAction) {
-            if (dragParity != 0) {
-                Log.e(TAG, "onDragEnter: Drag contract violated: " + dragParity);
-            }
-        }
-
-        @Override
-        public void onDragEnd() {
-            if (dragParity != 0) {
-                Log.e(TAG, "onDragExit: Drag contract violated: " + dragParity);
-            }
+            return res;
         }
     }
 
@@ -113,7 +100,7 @@
 
     /**
      * Handle an object being dropped on the DropTarget
-     * 
+     *
      * @param source DragSource where the drag started
      * @param x X coordinate of the drop location
      * @param y Y coordinate of the drop location
@@ -138,12 +125,12 @@
      * of onDrop().  (This is only called on objects that are set as the DragController's
      * fling-to-delete target.
      */
-    void onFlingToDelete(DragObject dragObject, int x, int y, PointF vec);
+    void onFlingToDelete(DragObject dragObject, PointF vec);
 
     /**
      * Check if a drop action can occur at, or near, the requested location.
      * This will be called just before onDrop.
-     * 
+     *
      * @param source DragSource where the drag started
      * @param x X coordinate of the drop location
      * @param y Y coordinate of the drop location
@@ -157,6 +144,8 @@
      */
     boolean acceptDrop(DragObject dragObject);
 
+    void prepareAccessibilityDrop();
+
     // These methods are implemented in Views
     void getHitRectRelativeToDragLayer(Rect outRect);
     void getLocationInDragLayer(int[] loc);
diff --git a/src/com/android/launcher3/DummyWidget.java b/src/com/android/launcher3/DummyWidget.java
new file mode 100644
index 0000000..59cd805
--- /dev/null
+++ b/src/com/android/launcher3/DummyWidget.java
@@ -0,0 +1,50 @@
+package com.android.launcher3;
+
+import android.appwidget.AppWidgetProviderInfo;
+
+public class DummyWidget implements CustomAppWidget {
+    @Override
+    public String getLabel() {
+        return "Dumb Launcher Widget";
+    }
+
+    @Override
+    public int getPreviewImage() {
+        return 0;
+    }
+
+    @Override
+    public int getIcon() {
+        return 0;
+    }
+
+    @Override
+    public int getWidgetLayout() {
+        return R.layout.dummy_widget;
+    }
+
+    @Override
+    public int getSpanX() {
+        return 2;
+    }
+
+    @Override
+    public int getSpanY() {
+        return 2;
+    }
+
+    @Override
+    public int getMinSpanX() {
+        return 1;
+    }
+
+    @Override
+    public int getMinSpanY() {
+        return 1;
+    }
+
+    @Override
+    public int getResizeMode() {
+        return AppWidgetProviderInfo.RESIZE_BOTH;
+    }
+}
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
deleted file mode 100644
index aa08148..0000000
--- a/src/com/android/launcher3/DynamicGrid.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-
-import java.util.ArrayList;
-
-
-public class DynamicGrid {
-    @SuppressWarnings("unused")
-    private static final String TAG = "DynamicGrid";
-
-    private DeviceProfile mProfile;
-    private float mMinWidth;
-    private float mMinHeight;
-
-    // This is a static that we use for the default icon size on a 4/5-inch phone
-    static float DEFAULT_ICON_SIZE_DP = 60;
-    static float DEFAULT_ICON_SIZE_PX = 0;
-
-    public static float dpiFromPx(int size, DisplayMetrics metrics){
-        float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
-        return (size / densityRatio);
-    }
-    public static int pxFromDp(float size, DisplayMetrics metrics) {
-        return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                size, metrics));
-    }
-    public static int pxFromSp(float size, DisplayMetrics metrics) {
-        return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
-                size, metrics));
-    }
-
-    public DynamicGrid(Context context, Resources resources,
-                       int minWidthPx, int minHeightPx,
-                       int widthPx, int heightPx,
-                       int awPx, int ahPx) {
-        DisplayMetrics dm = resources.getDisplayMetrics();
-        ArrayList<DeviceProfile> deviceProfiles =
-                new ArrayList<DeviceProfile>();
-        boolean hasAA = !LauncherAppState.isDisableAllApps();
-        DEFAULT_ICON_SIZE_PX = pxFromDp(DEFAULT_ICON_SIZE_DP, dm);
-        // Our phone profiles include the bar sizes in each orientation
-        deviceProfiles.add(new DeviceProfile("Super Short Stubby",
-                255, 300,  2, 3,  48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Shorter Stubby",
-                255, 400,  3, 3,  48, 13, (hasAA ? 3 : 5), 48, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Short Stubby",
-                275, 420,  3, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Stubby",
-                255, 450,  3, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Nexus S",
-                296, 491.33f,  4, 4,  48, 13, (hasAA ? 5 : 5), 48, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Nexus 4",
-                335, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Nexus 5",
-                359, 567,  4, 4,  DEFAULT_ICON_SIZE_DP, 13, (hasAA ? 5 : 5), 56, R.xml.default_workspace_4x4));
-        deviceProfiles.add(new DeviceProfile("Large Phone",
-                406, 694,  5, 5,  64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
-        // The tablet profile is odd in that the landscape orientation
-        // also includes the nav bar on the side
-        deviceProfiles.add(new DeviceProfile("Nexus 7",
-                575, 904,  5, 6,  72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
-        // Larger tablet profiles always have system bars on the top & bottom
-        deviceProfiles.add(new DeviceProfile("Nexus 10",
-                727, 1207,  5, 6,  76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
-        deviceProfiles.add(new DeviceProfile("20-inch Tablet",
-                1527, 2527,  7, 7,  100, 20,  7, 72, R.xml.default_workspace_4x4));
-        mMinWidth = dpiFromPx(minWidthPx, dm);
-        mMinHeight = dpiFromPx(minHeightPx, dm);
-        mProfile = new DeviceProfile(context, deviceProfiles,
-                mMinWidth, mMinHeight,
-                widthPx, heightPx,
-                awPx, ahPx,
-                resources);
-    }
-
-    public DeviceProfile getDeviceProfile() {
-        return mProfile;
-    }
-
-    public String toString() {
-        return "-------- DYNAMIC GRID ------- \n" +
-                "Wd: " + mProfile.minWidthDps + ", Hd: " + mProfile.minHeightDps +
-                ", W: " + mProfile.widthPx + ", H: " + mProfile.heightPx +
-                " [r: " + mProfile.numRows + ", c: " + mProfile.numColumns +
-                ", is: " + mProfile.iconSizePx + ", its: " + mProfile.iconTextSizePx +
-                ", cw: " + mProfile.cellWidthPx + ", ch: " + mProfile.cellHeightPx +
-                ", hc: " + mProfile.numHotseatIcons + ", his: " + mProfile.hotseatIconSizePx + "]";
-    }
-}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index ff02bbb..28e923e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -32,7 +32,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.SparseArray;
 
-class FastBitmapDrawable extends Drawable {
+public class FastBitmapDrawable extends Drawable {
 
     static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
 
@@ -72,7 +72,7 @@
     private boolean mPressed = false;
     private ObjectAnimator mPressedAnimator;
 
-    FastBitmapDrawable(Bitmap b) {
+    public FastBitmapDrawable(Bitmap b) {
         mAlpha = 255;
         mBitmap = b;
         setBounds(0, 0, b.getWidth(), b.getHeight());
diff --git a/src/com/android/launcher3/FastBitmapView.java b/src/com/android/launcher3/FastBitmapView.java
deleted file mode 100644
index 0937eb7..0000000
--- a/src/com/android/launcher3/FastBitmapView.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.view.View;
-
-public class FastBitmapView extends View {
-
-    private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
-    private Bitmap mBitmap;
-
-    public FastBitmapView(Context context) {
-        super(context);
-    }
-
-    /**
-     * Applies the new bitmap.
-     * @return true if the view was invalidated.
-     */
-    public boolean setBitmap(Bitmap b) {
-        if (b != mBitmap){
-            if (mBitmap != null) {
-                invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
-            }
-            mBitmap = b;
-            if (mBitmap != null) {
-                invalidate(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mBitmap != null) {
-            canvas.drawBitmap(mBitmap, 0, 0, mPaint);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index 095c563..a51ddd4 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -24,6 +24,8 @@
 import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
 
+import com.android.launcher3.util.Thunk;
+
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
  *  For the first two frames, it adjusts the current play time of the animation to
@@ -41,7 +43,7 @@
     private boolean mAdjustedSecondFrameTime;
 
     private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
-    private static long sGlobalFrameCounter;
+    @Thunk static long sGlobalFrameCounter;
     private static boolean sVisible;
 
     public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index e607047..57aec32 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,658 +16,445 @@
 
 package com.android.launcher3;
 
-import android.content.res.Configuration;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ScrollView;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
+import com.android.launcher3.util.FocusLogic;
+import com.android.launcher3.util.Thunk;
 
 /**
  * A keyboard listener we set on all the workspace icons.
  */
 class IconKeyEventListener implements View.OnKeyListener {
+    @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         return FocusHelper.handleIconKeyEvent(v, keyCode, event);
     }
 }
 
 /**
- * A keyboard listener we set on all the workspace icons.
- */
-class FolderKeyEventListener implements View.OnKeyListener {
-    public boolean onKey(View v, int keyCode, KeyEvent event) {
-        return FocusHelper.handleFolderKeyEvent(v, keyCode, event);
-    }
-}
-
-/**
  * A keyboard listener we set on all the hotseat buttons.
  */
 class HotseatIconKeyEventListener implements View.OnKeyListener {
+    @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
-        final Configuration configuration = v.getResources().getConfiguration();
-        return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event, configuration.orientation);
+        return FocusHelper.handleHotseatButtonKeyEvent(v, keyCode, event);
     }
 }
 
 public class FocusHelper {
 
+    private static final String TAG = "FocusHelper";
+    private static final boolean DEBUG = false;
+
     /**
-     * Returns the Viewgroup containing page contents for the page at the index specified.
+     * Handles key events in paged folder.
      */
-    private static ViewGroup getAppsCustomizePage(ViewGroup container, int index) {
-        ViewGroup page = (ViewGroup) ((PagedView) container).getPageAt(index);
-        if (page instanceof CellLayout) {
-            // There are two layers, a PagedViewCellLayout and PagedViewCellLayoutChildren
-            page = ((CellLayout) page).getShortcutsAndWidgets();
+    public static class PagedFolderKeyEventListener implements View.OnKeyListener {
+
+        private final Folder mFolder;
+
+        public PagedFolderKeyEventListener(Folder folder) {
+            mFolder = folder;
         }
-        return page;
+
+        @Override
+        public boolean onKey(View v, int keyCode, KeyEvent e) {
+            boolean consume = FocusLogic.shouldConsume(keyCode);
+            if (e.getAction() == KeyEvent.ACTION_UP) {
+                return consume;
+            }
+            if (DEBUG) {
+                Log.v(TAG, String.format("Handle ALL Folders keyevent=[%s].",
+                        KeyEvent.keyCodeToString(keyCode)));
+            }
+
+
+            if (!(v.getParent() instanceof ShortcutAndWidgetContainer)) {
+                if (LauncherAppState.isDogfoodBuild()) {
+                    throw new IllegalStateException("Parent of the focused item is not supported.");
+                } else {
+                    return false;
+                }
+            }
+
+            // Initialize variables.
+            final ShortcutAndWidgetContainer itemContainer = (ShortcutAndWidgetContainer) v.getParent();
+            final CellLayout cellLayout = (CellLayout) itemContainer.getParent();
+            final int countX = cellLayout.getCountX();
+            final int countY = cellLayout.getCountY();
+
+            final int iconIndex = itemContainer.indexOfChild(v);
+            final FolderPagedView pagedView = (FolderPagedView) cellLayout.getParent();
+
+            final int pageIndex = pagedView.indexOfChild(cellLayout);
+            final int pageCount = pagedView.getPageCount();
+            final boolean isLayoutRtl = Utilities.isRtl(v.getResources());
+
+            int[][] matrix = FocusLogic.createSparseMatrix(cellLayout);
+            // Process focus.
+            int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
+                    countY, matrix, iconIndex, pageIndex, pageCount, isLayoutRtl);
+            if (newIconIndex == FocusLogic.NOOP) {
+                handleNoopKey(keyCode, v);
+                return consume;
+            }
+            ShortcutAndWidgetContainer newParent = null;
+            View child = null;
+
+            switch (newIconIndex) {
+                case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
+                case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
+                    newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
+                    if (newParent != null) {
+                        int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
+                        pagedView.snapToPage(pageIndex - 1);
+                        child = newParent.getChildAt(
+                                ((newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN)
+                                    ^ newParent.invertLayoutHorizontally()) ? 0 : countX - 1, row);
+                    }
+                    break;
+                case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
+                    newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
+                    if (newParent != null) {
+                        pagedView.snapToPage(pageIndex - 1);
+                        child = newParent.getChildAt(0, 0);
+                    }
+                    break;
+                case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
+                    newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex - 1);
+                    if (newParent != null) {
+                        pagedView.snapToPage(pageIndex - 1);
+                        child = newParent.getChildAt(countX - 1, countY - 1);
+                    }
+                    break;
+                case FocusLogic.NEXT_PAGE_FIRST_ITEM:
+                    newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
+                    if (newParent != null) {
+                        pagedView.snapToPage(pageIndex + 1);
+                        child = newParent.getChildAt(0, 0);
+                    }
+                    break;
+                case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
+                case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
+                    newParent = getCellLayoutChildrenForIndex(pagedView, pageIndex + 1);
+                    if (newParent != null) {
+                        pagedView.snapToPage(pageIndex + 1);
+                        child = FocusLogic.getAdjacentChildInNextPage(newParent, v, newIconIndex);
+                    }
+                    break;
+                case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
+                    child = cellLayout.getChildAt(0, 0);
+                    break;
+                case FocusLogic.CURRENT_PAGE_LAST_ITEM:
+                    child = pagedView.getLastItem();
+                    break;
+                default: // Go to some item on the current page.
+                    child = itemContainer.getChildAt(newIconIndex);
+                    break;
+            }
+            if (child != null) {
+                child.requestFocus();
+                playSoundEffect(keyCode, v);
+            } else {
+                handleNoopKey(keyCode, v);
+            }
+            return consume;
+        }
+
+        public void handleNoopKey(int keyCode, View v) {
+            if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+                mFolder.mFolderName.requestFocus();
+                playSoundEffect(keyCode, v);
+            }
+        }
     }
 
     /**
-     * Handles key events in a PageViewCellLayout containing PagedViewIcons.
+     * Handles key events in the workspace hot seat (bottom of the screen).
+     * <p>Currently we don't special case for the phone UI in different orientations, even though
+     * the hotseat is on the side in landscape mode. This is to ensure that accessibility
+     * consistency is maintained across rotations.
      */
-    static boolean handleAppsCustomizeKeyEvent(View v, int keyCode, KeyEvent e) {
-        ViewGroup parentLayout;
-        ViewGroup itemContainer;
-        int countX;
-        int countY;
-        if (v.getParent() instanceof ShortcutAndWidgetContainer) {
-            itemContainer = (ViewGroup) v.getParent();
-            parentLayout = (ViewGroup) itemContainer.getParent();
-            countX = ((CellLayout) parentLayout).getCountX();
-            countY = ((CellLayout) parentLayout).getCountY();
-        } else {
-            itemContainer = parentLayout = (ViewGroup) v.getParent();
-            countX = ((PagedViewGridLayout) parentLayout).getCellCountX();
-            countY = ((PagedViewGridLayout) parentLayout).getCellCountY();
+    static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e) {
+        boolean consume = FocusLogic.shouldConsume(keyCode);
+        if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
+            return consume;
         }
 
-        // Note we have an extra parent because of the
-        // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
-        final PagedView container = (PagedView) parentLayout.getParent();
-        final int iconIndex = itemContainer.indexOfChild(v);
-        final int itemCount = itemContainer.getChildCount();
-        final int pageIndex = ((PagedView) container).indexToPage(container.indexOfChild(parentLayout));
-        final int pageCount = container.getChildCount();
+        DeviceProfile profile = ((Launcher) v.getContext()).getDeviceProfile();
 
-        final int x = iconIndex % countX;
-        final int y = iconIndex / countX;
-
-        final int action = e.getAction();
-        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        ViewGroup newParent = null;
-        // Side pages do not always load synchronously, so check before focusing child siblings
-        // willy-nilly
-        View child = null;
-        boolean wasHandled = false;
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (handleKeyEvent) {
-                    // Select the previous icon or the last icon on the previous page
-                    if (iconIndex > 0) {
-                        itemContainer.getChildAt(iconIndex - 1).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                    } else {
-                        if (pageIndex > 0) {
-                            newParent = getAppsCustomizePage(container, pageIndex - 1);
-                            if (newParent != null) {
-                                container.snapToPage(pageIndex - 1);
-                                child = newParent.getChildAt(newParent.getChildCount() - 1);
-                                if (child != null) {
-                                    child.requestFocus();
-                                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                                }
-                            }
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (handleKeyEvent) {
-                    // Select the next icon or the first icon on the next page
-                    if (iconIndex < (itemCount - 1)) {
-                        itemContainer.getChildAt(iconIndex + 1).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                    } else {
-                        if (pageIndex < (pageCount - 1)) {
-                            newParent = getAppsCustomizePage(container, pageIndex + 1);
-                            if (newParent != null) {
-                                container.snapToPage(pageIndex + 1);
-                                child = newParent.getChildAt(0);
-                                if (child != null) {
-                                    child.requestFocus();
-                                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                                }
-                            }
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_UP:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the previous row, otherwise select the tab bar
-                    if (y > 0) {
-                        int newiconIndex = ((y - 1) * countX) + x;
-                        itemContainer.getChildAt(newiconIndex).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the next row, otherwise do nothing
-                    if (y < (countY - 1)) {
-                        int newiconIndex = Math.min(itemCount - 1, ((y + 1) * countX) + x);
-                        int newIconY = newiconIndex / countX;
-                        if (newIconY != y) {
-                            itemContainer.getChildAt(newiconIndex).requestFocus();
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_PAGE_UP:
-                if (handleKeyEvent) {
-                    // Select the first icon on the previous page, or the first icon on this page
-                    // if there is no previous page
-                    if (pageIndex > 0) {
-                        newParent = getAppsCustomizePage(container, pageIndex - 1);
-                        if (newParent != null) {
-                            container.snapToPage(pageIndex - 1);
-                            child = newParent.getChildAt(0);
-                            if (child != null) {
-                                child.requestFocus();
-                                v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                            }
-                        }
-                    } else {
-                        itemContainer.getChildAt(0).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_PAGE_DOWN:
-                if (handleKeyEvent) {
-                    // Select the first icon on the next page, or the last icon on this page
-                    // if there is no next page
-                    if (pageIndex < (pageCount - 1)) {
-                        newParent = getAppsCustomizePage(container, pageIndex + 1);
-                        if (newParent != null) {
-                            container.snapToPage(pageIndex + 1);
-                            child = newParent.getChildAt(0);
-                            if (child != null) {
-                                child.requestFocus();
-                                v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                            }
-                        }
-                    } else {
-                        itemContainer.getChildAt(itemCount - 1).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_MOVE_HOME:
-                if (handleKeyEvent) {
-                    // Select the first icon on this page
-                    itemContainer.getChildAt(0).requestFocus();
-                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_MOVE_END:
-                if (handleKeyEvent) {
-                    // Select the last icon on this page
-                    itemContainer.getChildAt(itemCount - 1).requestFocus();
-                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                }
-                wasHandled = true;
-                break;
-            default: break;
+        if (DEBUG) {
+            Log.v(TAG, String.format(
+                    "Handle HOTSEAT BUTTONS keyevent=[%s] on hotseat buttons, isVertical=%s",
+                    KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
         }
-        return wasHandled;
+
+        // Initialize the variables.
+        final ShortcutAndWidgetContainer hotseatParent = (ShortcutAndWidgetContainer) v.getParent();
+        final CellLayout hotseatLayout = (CellLayout) hotseatParent.getParent();
+        Hotseat hotseat = (Hotseat) hotseatLayout.getParent();
+
+        Workspace workspace = (Workspace) v.getRootView().findViewById(R.id.workspace);
+        int pageIndex = workspace.getNextPage();
+        int pageCount = workspace.getChildCount();
+        int countX = -1;
+        int countY = -1;
+        int iconIndex = hotseatParent.indexOfChild(v);
+        int iconRank = ((CellLayout.LayoutParams) hotseatLayout.getShortcutsAndWidgets()
+                .getChildAt(iconIndex).getLayoutParams()).cellX;
+
+        final CellLayout iconLayout = (CellLayout) workspace.getChildAt(pageIndex);
+        if (iconLayout == null) {
+            // This check is to guard against cases where key strokes rushes in when workspace
+            // child creation/deletion is still in flux. (e.g., during drop or fling
+            // animation.)
+            return consume;
+        }
+        final ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
+
+        ViewGroup parent = null;
+        int[][] matrix = null;
+
+        if (keyCode == KeyEvent.KEYCODE_DPAD_UP &&
+                !profile.isVerticalBarLayout()) {
+            matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
+                    true /* hotseat horizontal */, profile.inv.hotseatAllAppsRank,
+                    iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */);
+            iconIndex += iconParent.getChildCount();
+            countX = iconLayout.getCountX();
+            countY = iconLayout.getCountY() + hotseatLayout.getCountY();
+            parent = iconParent;
+        } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT &&
+                profile.isVerticalBarLayout()) {
+            matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout,
+                    false /* hotseat horizontal */, profile.inv.hotseatAllAppsRank,
+                    iconRank == profile.inv.hotseatAllAppsRank /* include all apps icon */);
+            iconIndex += iconParent.getChildCount();
+            countX = iconLayout.getCountX() + hotseatLayout.getCountX();
+            countY = iconLayout.getCountY();
+            parent = iconParent;
+        } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
+                profile.isVerticalBarLayout()) {
+            keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
+        }else {
+            // For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
+            // matrix extended with hotseat.
+            matrix = FocusLogic.createSparseMatrix(hotseatLayout);
+            countX = hotseatLayout.getCountX();
+            countY = hotseatLayout.getCountY();
+            parent = hotseatParent;
+        }
+
+        // Process the focus.
+        int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
+                countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources()));
+
+        View newIcon = null;
+        if (newIconIndex == FocusLogic.NEXT_PAGE_FIRST_ITEM) {
+            parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+            newIcon = parent.getChildAt(0);
+            // TODO(hyunyoungs): handle cases where the child is not an icon but
+            // a folder or a widget.
+            workspace.snapToPage(pageIndex + 1);
+        }
+        if (parent == iconParent && newIconIndex >= iconParent.getChildCount()) {
+            newIconIndex -= iconParent.getChildCount();
+        }
+        if (parent != null) {
+            if (newIcon == null && newIconIndex >=0) {
+                newIcon = parent.getChildAt(newIconIndex);
+            }
+            if (newIcon != null) {
+                newIcon.requestFocus();
+                playSoundEffect(keyCode, v);
+            }
+        }
+        return consume;
     }
 
     /**
-     * Handles key events in the workspace hotseat (bottom of the screen).
+     * Handles key events in a workspace containing icons.
      */
-    static boolean handleHotseatButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
+    static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
+        boolean consume = FocusLogic.shouldConsume(keyCode);
+        if (e.getAction() == KeyEvent.ACTION_UP || !consume) {
+            return consume;
+        }
+
+        Launcher launcher = (Launcher) v.getContext();
+        DeviceProfile profile = launcher.getDeviceProfile();
+
+        if (DEBUG) {
+            Log.v(TAG, String.format("Handle WORKSPACE ICONS keyevent=[%s] isVerticalBar=%s",
+                    KeyEvent.keyCodeToString(keyCode), profile.isVerticalBarLayout()));
+        }
+
+        // Initialize the variables.
         ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
-        final CellLayout layout = (CellLayout) parent.getParent();
+        CellLayout iconLayout = (CellLayout) parent.getParent();
+        final Workspace workspace = (Workspace) iconLayout.getParent();
+        final ViewGroup dragLayer = (ViewGroup) workspace.getParent();
+        final ViewGroup tabs = (ViewGroup) dragLayer.findViewById(R.id.search_drop_target_bar);
+        final Hotseat hotseat = (Hotseat) dragLayer.findViewById(R.id.hotseat);
 
-        // NOTE: currently we don't special case for the phone UI in different
-        // orientations, even though the hotseat is on the side in landscape mode. This
-        // is to ensure that accessibility consistency is maintained across rotations.
-        final int action = e.getAction();
-        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        boolean wasHandled = false;
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (handleKeyEvent) {
-                    ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
-                    int myIndex = views.indexOf(v);
-                    // Select the previous button, otherwise do nothing
-                    if (myIndex > 0) {
-                        views.get(myIndex - 1).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (handleKeyEvent) {
-                    ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
-                    int myIndex = views.indexOf(v);
-                    // Select the next button, otherwise do nothing
-                    if (myIndex < views.size() - 1) {
-                        views.get(myIndex + 1).requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_UP:
-                if (handleKeyEvent) {
-                    final Workspace workspace = (Workspace)
-                            v.getRootView().findViewById(R.id.workspace);
-                    if (workspace != null) {
-                        int pageIndex = workspace.getCurrentPage();
-                        CellLayout topLayout = (CellLayout) workspace.getChildAt(pageIndex);
-                        ShortcutAndWidgetContainer children = topLayout.getShortcutsAndWidgets();
-                        final View newIcon = getIconInDirection(layout, children, -1, 1);
-                        // Select the first bubble text view in the current page of the workspace
-                        if (newIcon != null) {
-                            newIcon.requestFocus();
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                        } else {
-                            workspace.requestFocus();
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                // Do nothing
-                wasHandled = true;
-                break;
-            default: break;
+        final int iconIndex = parent.indexOfChild(v);
+        final int pageIndex = workspace.indexOfChild(iconLayout);
+        final int pageCount = workspace.getChildCount();
+        int countX = iconLayout.getCountX();
+        int countY = iconLayout.getCountY();
+
+        CellLayout hotseatLayout = (CellLayout) hotseat.getChildAt(0);
+        ShortcutAndWidgetContainer hotseatParent = hotseatLayout.getShortcutsAndWidgets();
+        int[][] matrix;
+
+        // KEYCODE_DPAD_DOWN in portrait (KEYCODE_DPAD_RIGHT in landscape) is the only key allowed
+        // to take a user to the hotseat. For other dpad navigation, do not use the matrix extended
+        // with the hotseat.
+        if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) {
+            matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */,
+                    profile.inv.hotseatAllAppsRank,
+                    !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
+            countY = countY + 1;
+        } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
+                profile.isVerticalBarLayout()) {
+            matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */,
+                    profile.inv.hotseatAllAppsRank,
+                    !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
+            countX = countX + 1;
+        } else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
+            workspace.removeWorkspaceItem(v);
+            return consume;
+        } else {
+            matrix = FocusLogic.createSparseMatrix(iconLayout);
         }
-        return wasHandled;
+
+        // Process the focus.
+        int newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX,
+                countY, matrix, iconIndex, pageIndex, pageCount, Utilities.isRtl(v.getResources()));
+        View newIcon = null;
+        switch (newIconIndex) {
+            case FocusLogic.NOOP:
+                if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+                    newIcon = tabs;
+                }
+                break;
+            case FocusLogic.PREVIOUS_PAGE_RIGHT_COLUMN:
+            case FocusLogic.NEXT_PAGE_RIGHT_COLUMN:
+                int newPageIndex = pageIndex - 1;
+                if (newIconIndex == FocusLogic.NEXT_PAGE_RIGHT_COLUMN) {
+                    newPageIndex = pageIndex + 1;
+                }
+                int row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
+                parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
+                workspace.snapToPage(newPageIndex);
+                if (parent != null) {
+                    workspace.snapToPage(newPageIndex);
+                    iconLayout = (CellLayout) parent.getParent();
+                    matrix = FocusLogic.createSparseMatrix(iconLayout,
+                        iconLayout.getCountX(), row);
+                    newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
+                            matrix, FocusLogic.PIVOT, newPageIndex, pageCount,
+                            Utilities.isRtl(v.getResources()));
+                    newIcon = parent.getChildAt(newIconIndex);
+                }
+                break;
+            case FocusLogic.PREVIOUS_PAGE_FIRST_ITEM:
+                parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+                newIcon = parent.getChildAt(0);
+                workspace.snapToPage(pageIndex - 1);
+                break;
+            case FocusLogic.PREVIOUS_PAGE_LAST_ITEM:
+                parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+                newIcon = parent.getChildAt(parent.getChildCount() - 1);
+                workspace.snapToPage(pageIndex - 1);
+                break;
+            case FocusLogic.NEXT_PAGE_FIRST_ITEM:
+                parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+                newIcon = parent.getChildAt(0);
+                workspace.snapToPage(pageIndex + 1);
+                break;
+            case FocusLogic.NEXT_PAGE_LEFT_COLUMN:
+            case FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN:
+                newPageIndex = pageIndex + 1;
+                if (newIconIndex == FocusLogic.PREVIOUS_PAGE_LEFT_COLUMN) {
+                    newPageIndex = pageIndex - 1;
+                }
+                workspace.snapToPage(newPageIndex);
+                row = ((CellLayout.LayoutParams) v.getLayoutParams()).cellY;
+                parent = getCellLayoutChildrenForIndex(workspace, newPageIndex);
+                if (parent != null) {
+                    workspace.snapToPage(newPageIndex);
+                    iconLayout = (CellLayout) parent.getParent();
+                    matrix = FocusLogic.createSparseMatrix(iconLayout, -1, row);
+                    newIconIndex = FocusLogic.handleKeyEvent(keyCode, countX + 1, countY,
+                            matrix, FocusLogic.PIVOT, newPageIndex, pageCount,
+                            Utilities.isRtl(v.getResources()));
+                    newIcon = parent.getChildAt(newIconIndex);
+                }
+                break;
+            case FocusLogic.CURRENT_PAGE_FIRST_ITEM:
+                newIcon = parent.getChildAt(0);
+                break;
+            case FocusLogic.CURRENT_PAGE_LAST_ITEM:
+                newIcon = parent.getChildAt(parent.getChildCount() - 1);
+                break;
+            default:
+                // current page, some item.
+                if (0 <= newIconIndex && newIconIndex < parent.getChildCount()) {
+                    newIcon = parent.getChildAt(newIconIndex);
+                } else if (parent.getChildCount() <= newIconIndex &&
+                        newIconIndex < parent.getChildCount() + hotseatParent.getChildCount()) {
+                    newIcon = hotseatParent.getChildAt(newIconIndex - parent.getChildCount());
+                }
+                break;
+        }
+        if (newIcon != null) {
+            newIcon.requestFocus();
+            playSoundEffect(keyCode, v);
+        }
+        return consume;
     }
 
+    //
+    // Helper methods.
+    //
+
     /**
      * Private helper method to get the CellLayoutChildren given a CellLayout index.
      */
-    private static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
+    @Thunk static ShortcutAndWidgetContainer getCellLayoutChildrenForIndex(
             ViewGroup container, int i) {
         CellLayout parent = (CellLayout) container.getChildAt(i);
         return parent.getShortcutsAndWidgets();
     }
 
     /**
-     * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
-     * from top left to bottom right.
+     * Helper method to be used for playing sound effects.
      */
-    private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
-            ViewGroup parent) {
-        // First we order each the CellLayout children by their x,y coordinates
-        final int cellCountX = layout.getCountX();
-        final int count = parent.getChildCount();
-        ArrayList<View> views = new ArrayList<View>();
-        for (int j = 0; j < count; ++j) {
-            views.add(parent.getChildAt(j));
-        }
-        Collections.sort(views, new Comparator<View>() {
-            @Override
-            public int compare(View lhs, View rhs) {
-                CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
-                CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
-                int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
-                int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
-                return lvIndex - rvIndex;
-            }
-        });
-        return views;
-    }
-    /**
-     * Private helper method to find the index of the next BubbleTextView or FolderIcon in the 
-     * direction delta.
-     * 
-     * @param delta either -1 or 1 depending on the direction we want to search
-     */
-    private static View findIndexOfIcon(ArrayList<View> views, int i, int delta) {
-        // Then we find the next BubbleTextView offset by delta from i
-        final int count = views.size();
-        int newI = i + delta;
-        while (0 <= newI && newI < count) {
-            View newV = views.get(newI);
-            if (newV instanceof BubbleTextView || newV instanceof FolderIcon) {
-                return newV;
-            }
-            newI += delta;
-        }
-        return null;
-    }
-    private static View getIconInDirection(CellLayout layout, ViewGroup parent, int i,
-            int delta) {
-        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
-        return findIndexOfIcon(views, i, delta);
-    }
-    private static View getIconInDirection(CellLayout layout, ViewGroup parent, View v,
-            int delta) {
-        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
-        return findIndexOfIcon(views, views.indexOf(v), delta);
-    }
-    /**
-     * Private helper method to find the next closest BubbleTextView or FolderIcon in the direction 
-     * delta on the next line.
-     * 
-     * @param delta either -1 or 1 depending on the line and direction we want to search
-     */
-    private static View getClosestIconOnLine(CellLayout layout, ViewGroup parent, View v,
-            int lineDelta) {
-        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
-        final int cellCountY = layout.getCountY();
-        final int row = lp.cellY;
-        final int newRow = row + lineDelta;
-        if (0 <= newRow && newRow < cellCountY) {
-            float closestDistance = Float.MAX_VALUE;
-            int closestIndex = -1;
-            int index = views.indexOf(v);
-            int endIndex = (lineDelta < 0) ? -1 : views.size();
-            while (index != endIndex) {
-                View newV = views.get(index);
-                CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
-                boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
-                if (satisfiesRow &&
-                        (newV instanceof BubbleTextView || newV instanceof FolderIcon)) {
-                    float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
-                            Math.pow(tmpLp.cellY - lp.cellY, 2));
-                    if (tmpDistance < closestDistance) {
-                        closestIndex = index;
-                        closestDistance = tmpDistance;
-                    }
-                }
-                if (index <= endIndex) {
-                    ++index;
-                } else {
-                    --index;
-                }
-            }
-            if (closestIndex > -1) {
-                return views.get(closestIndex);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Handles key events in a Workspace containing.
-     */
-    static boolean handleIconKeyEvent(View v, int keyCode, KeyEvent e) {
-        ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
-        final CellLayout layout = (CellLayout) parent.getParent();
-        final Workspace workspace = (Workspace) layout.getParent();
-        final ViewGroup launcher = (ViewGroup) workspace.getParent();
-        final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.search_drop_target_bar);
-        final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.hotseat);
-        int pageIndex = workspace.indexOfChild(layout);
-        int pageCount = workspace.getChildCount();
-
-        final int action = e.getAction();
-        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        boolean wasHandled = false;
+    @Thunk static void playSoundEffect(int keyCode, View v) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (handleKeyEvent) {
-                    // Select the previous icon or the last icon on the previous page if possible
-                    View newIcon = getIconInDirection(layout, parent, v, -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                    } else {
-                        if (pageIndex > 0) {
-                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
-                            newIcon = getIconInDirection(layout, parent,
-                                    parent.getChildCount(), -1);
-                            if (newIcon != null) {
-                                newIcon.requestFocus();
-                            } else {
-                                // Snap to the previous page
-                                workspace.snapToPage(pageIndex - 1);
-                            }
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                        }
-                    }
-                }
-                wasHandled = true;
+                v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
                 break;
             case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (handleKeyEvent) {
-                    // Select the next icon or the first icon on the next page if possible
-                    View newIcon = getIconInDirection(layout, parent, v, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                    } else {
-                        if (pageIndex < (pageCount - 1)) {
-                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
-                            newIcon = getIconInDirection(layout, parent, -1, 1);
-                            if (newIcon != null) {
-                                newIcon.requestFocus();
-                            } else {
-                                // Snap to the next page
-                                workspace.snapToPage(pageIndex + 1);
-                            }
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_UP:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the previous line, otherwise select the tab bar
-                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        wasHandled = true;
-                    } else {
-                        tabs.requestFocus();
-                    }
-                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                }
+                v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
                 break;
             case KeyEvent.KEYCODE_DPAD_DOWN:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the next line, otherwise select the button bar
-                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                        wasHandled = true;
-                    } else if (hotseat != null) {
-                        hotseat.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                    }
-                }
-                break;
-            case KeyEvent.KEYCODE_PAGE_UP:
-                if (handleKeyEvent) {
-                    // Select the first icon on the previous page or the first icon on this page
-                    // if there is no previous page
-                    if (pageIndex > 0) {
-                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
-                        View newIcon = getIconInDirection(layout, parent, -1, 1);
-                        if (newIcon != null) {
-                            newIcon.requestFocus();
-                        } else {
-                            // Snap to the previous page
-                            workspace.snapToPage(pageIndex - 1);
-                        }
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    } else {
-                        View newIcon = getIconInDirection(layout, parent, -1, 1);
-                        if (newIcon != null) {
-                            newIcon.requestFocus();
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
             case KeyEvent.KEYCODE_PAGE_DOWN:
-                if (handleKeyEvent) {
-                    // Select the first icon on the next page or the last icon on this page
-                    // if there is no previous page
-                    if (pageIndex < (pageCount - 1)) {
-                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
-                        View newIcon = getIconInDirection(layout, parent, -1, 1);
-                        if (newIcon != null) {
-                            newIcon.requestFocus();
-                        } else {
-                            // Snap to the next page
-                            workspace.snapToPage(pageIndex + 1);
-                        }
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                    } else {
-                        View newIcon = getIconInDirection(layout, parent,
-                                parent.getChildCount(), -1);
-                        if (newIcon != null) {
-                            newIcon.requestFocus();
-                            v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                        }
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_MOVE_HOME:
-                if (handleKeyEvent) {
-                    // Select the first icon on this page
-                    View newIcon = getIconInDirection(layout, parent, -1, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    }
-                }
-                wasHandled = true;
-                break;
             case KeyEvent.KEYCODE_MOVE_END:
-                if (handleKeyEvent) {
-                    // Select the last icon on this page
-                    View newIcon = getIconInDirection(layout, parent,
-                            parent.getChildCount(), -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                    }
-                }
-                wasHandled = true;
-                break;
-            default: break;
-        }
-        return wasHandled;
-    }
-
-    /**
-     * Handles key events for items in a Folder.
-     */
-    static boolean handleFolderKeyEvent(View v, int keyCode, KeyEvent e) {
-        ShortcutAndWidgetContainer parent = (ShortcutAndWidgetContainer) v.getParent();
-        final CellLayout layout = (CellLayout) parent.getParent();
-        final ScrollView scrollView = (ScrollView) layout.getParent();
-        final Folder folder = (Folder) scrollView.getParent();
-        View title = folder.mFolderName;
-
-        final int action = e.getAction();
-        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
-        boolean wasHandled = false;
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (handleKeyEvent) {
-                    // Select the previous icon
-                    View newIcon = getIconInDirection(layout, parent, v, -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (handleKeyEvent) {
-                    // Select the next icon
-                    View newIcon = getIconInDirection(layout, parent, v, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                    } else {
-                        title.requestFocus();
-                    }
-                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
-                }
-                wasHandled = true;
+                v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
                 break;
             case KeyEvent.KEYCODE_DPAD_UP:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the previous line
-                    View newIcon = getClosestIconOnLine(layout, parent, v, -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    }
-                }
-                wasHandled = true;
-                break;
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-                if (handleKeyEvent) {
-                    // Select the closest icon in the next line
-                    View newIcon = getClosestIconOnLine(layout, parent, v, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                    } else {
-                        title.requestFocus();
-                    }
-                    v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                }
-                wasHandled = true;
-                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
             case KeyEvent.KEYCODE_MOVE_HOME:
-                if (handleKeyEvent) {
-                    // Select the first icon on this page
-                    View newIcon = getIconInDirection(layout, parent, -1, 1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-                    }
-                }
-                wasHandled = true;
+                v.playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
                 break;
-            case KeyEvent.KEYCODE_MOVE_END:
-                if (handleKeyEvent) {
-                    // Select the last icon on this page
-                    View newIcon = getIconInDirection(layout, parent,
-                            parent.getChildCount(), -1);
-                    if (newIcon != null) {
-                        newIcon.requestFocus();
-                        v.playSoundEffect(SoundEffectConstants.NAVIGATION_DOWN);
-                    }
-                }
-                wasHandled = true;
+            default:
                 break;
-            default: break;
         }
-        return wasHandled;
     }
 }
diff --git a/src/com/android/launcher3/FocusIndicatorView.java b/src/com/android/launcher3/FocusIndicatorView.java
index 7d4664a..ecf93e4 100644
--- a/src/com/android/launcher3/FocusIndicatorView.java
+++ b/src/com/android/launcher3/FocusIndicatorView.java
@@ -23,7 +23,8 @@
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.view.View;
-import android.view.ViewParent;
+
+import com.android.launcher3.util.Thunk;
 
 public class FocusIndicatorView extends View implements View.OnFocusChangeListener {
 
@@ -32,9 +33,6 @@
     private static final float MIN_VISIBLE_ALPHA = 0.2f;
     private static final long ANIM_DURATION = 150;
 
-    private static final int[] sTempPos = new int[2];
-    private static final int[] sTempShift = new int[2];
-
     private final int[] mIndicatorPos = new int[2];
     private final int[] mTargetViewPos = new int[2];
 
@@ -80,7 +78,8 @@
         }
 
         if (!mInitiated) {
-            getLocationRelativeToParentPagedView(this, mIndicatorPos);
+            // The parent view should always the a parent of the target view.
+            computeLocationRelativeToParent(this, (View) getParent(), mIndicatorPos);
             mInitiated = true;
         }
 
@@ -93,7 +92,7 @@
             nextState.scaleX = v.getScaleX() * v.getWidth() / indicatorWidth;
             nextState.scaleY = v.getScaleY() * v.getHeight() / indicatorHeight;
 
-            getLocationRelativeToParentPagedView(v, mTargetViewPos);
+            computeLocationRelativeToParent(v, (View) getParent(), mTargetViewPos);
             nextState.x = mTargetViewPos[0] - mIndicatorPos[0] - (1 - nextState.scaleX) * indicatorWidth / 2;
             nextState.y = mTargetViewPos[1] - mIndicatorPos[1] - (1 - nextState.scaleY) * indicatorHeight / 2;
 
@@ -150,31 +149,36 @@
     }
 
     /**
-     * Gets the location of a view relative in the window, off-setting any shift due to
-     * page view scroll
+     * Computes the location of a view relative to {@param parent}, off-setting
+     * any shift due to page view scroll.
+     * @param pos an array of two integers in which to hold the coordinates
      */
-    private static void getLocationRelativeToParentPagedView(View v, int[] pos) {
-        getPagedViewScrollShift(v, sTempShift);
-        v.getLocationInWindow(sTempPos);
-        pos[0] = sTempPos[0] + sTempShift[0];
-        pos[1] = sTempPos[1] + sTempShift[1];
+    private static void computeLocationRelativeToParent(View v, View parent, int[] pos) {
+        pos[0] = pos[1] = 0;
+        computeLocationRelativeToParentHelper(v, parent, pos);
+
+        // If a view is scaled, its position will also shift accordingly. For optimization, only
+        // consider this for the last node.
+        pos[0] += (1 - v.getScaleX()) * v.getWidth() / 2;
+        pos[1] += (1 - v.getScaleY()) * v.getHeight() / 2;
     }
 
-    private static void getPagedViewScrollShift(View child, int[] shift) {
-        ViewParent parent = child.getParent();
+    private static void computeLocationRelativeToParentHelper(View child,
+            View commonParent, int[] shift) {
+        View parent = (View) child.getParent();
+        shift[0] += child.getLeft();
+        shift[1] += child.getTop();
         if (parent instanceof PagedView) {
-            View parentView = (View) parent;
-            child.getLocationInWindow(sTempPos);
-            shift[0] = parentView.getPaddingLeft() - sTempPos[0];
-            shift[1] = -(int) child.getTranslationY();
-        } else if (parent instanceof View) {
-            getPagedViewScrollShift((View) parent, shift);
-        } else {
-            shift[0] = shift[1] = 0;
+            PagedView page = (PagedView) parent;
+            shift[0] -= page.getScrollForPage(page.indexOfChild(child));
+        }
+
+        if (parent != commonParent) {
+            computeLocationRelativeToParentHelper(parent, commonParent, shift);
         }
     }
 
-    private static final class ViewAnimState {
+    @Thunk static final class ViewAnimState {
         float x, y, scaleX, scaleY;
     }
 }
diff --git a/src/com/android/launcher3/FocusOnlyTabWidget.java b/src/com/android/launcher3/FocusOnlyTabWidget.java
deleted file mode 100644
index 08fc311..0000000
--- a/src/com/android/launcher3/FocusOnlyTabWidget.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.TabWidget;
-
-public class FocusOnlyTabWidget extends TabWidget {
-    public FocusOnlyTabWidget(Context context) {
-        super(context);
-    }
-
-    public FocusOnlyTabWidget(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public FocusOnlyTabWidget(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    public View getSelectedTab() {
-        final int count = getTabCount();
-        for (int i = 0; i < count; ++i) {
-            View v = getChildTabViewAt(i);
-            if (v.isSelected()) {
-                return v;
-            }
-        }
-        return null;
-    }
-
-    public int getChildTabIndex(View v) {
-        final int tabCount = getTabCount();
-        for (int i = 0; i < tabCount; ++i) {
-            if (getChildTabViewAt(i) == v) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    public void setCurrentTabToFocusedTab() {
-        View tab = null;
-        int index = -1;
-        final int count = getTabCount();
-        for (int i = 0; i < count; ++i) {
-            View v = getChildTabViewAt(i);
-            if (v.hasFocus()) {
-                tab = v;
-                index = i;
-                break;
-            }
-        }
-        if (index > -1) {
-            super.setCurrentTab(index);
-            super.onFocusChange(tab, true);
-        }
-    }
-    public void superOnFocusChange(View v, boolean hasFocus) {
-        super.onFocusChange(v, hasFocus);
-    }
-
-    @Override
-    public void onFocusChange(android.view.View v, boolean hasFocus) {
-        if (v == this && hasFocus && getTabCount() > 0) {
-            getSelectedTab().requestFocus();
-            return;
-        }
-    }
-}
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 1890af4..2e19f6e 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -21,12 +21,15 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.os.SystemClock;
-import android.support.v4.widget.AutoScrollHelper;
+import android.os.Build;
+import android.os.Bundle;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
@@ -34,21 +37,28 @@
 import android.util.Log;
 import android.view.ActionMode;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.LinearLayout;
-import android.widget.ScrollView;
 import android.widget.TextView;
 
+import com.android.launcher3.CellLayout.CellInfo;
+import com.android.launcher3.DragController.DragListener;
 import com.android.launcher3.FolderInfo.FolderListener;
+import com.android.launcher3.UninstallDropTarget.UninstallSource;
+import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.UiThreadCircularReveal;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -59,106 +69,109 @@
  */
 public class Folder extends LinearLayout implements DragSource, View.OnClickListener,
         View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
-        View.OnFocusChangeListener {
+        View.OnFocusChangeListener, DragListener, UninstallSource, AccessibilityDragSource,
+        Stats.LaunchSourceProvider {
     private static final String TAG = "Launcher.Folder";
 
-    protected DragController mDragController;
-    protected Launcher mLauncher;
-    protected FolderInfo mInfo;
+    /**
+     * We avoid measuring {@link #mContentWrapper} with a 0 width or height, as this
+     * results in CellLayout being measured as UNSPECIFIED, which it does not support.
+     */
+    private static final int MIN_CONTENT_DIMEN = 5;
 
     static final int STATE_NONE = -1;
     static final int STATE_SMALL = 0;
     static final int STATE_ANIMATING = 1;
     static final int STATE_OPEN = 2;
 
-    private static final int CLOSE_FOLDER_DELAY_MS = 150;
+    /**
+     * Time for which the scroll hint is shown before automatically changing page.
+     */
+    public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
 
-    private int mExpandDuration;
-    private int mMaterialExpandDuration;
-    private int mMaterialExpandStagger;
-    protected CellLayout mContent;
-    private ScrollView mScrollView;
-    private final LayoutInflater mInflater;
-    private final IconCache mIconCache;
-    private int mState = STATE_NONE;
-    private static final int REORDER_ANIMATION_DURATION = 230;
+    /**
+     * Fraction of icon width which behave as scroll region.
+     */
+    private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
+
+    private static final int FOLDER_NAME_ANIMATION_DURATION = 633;
+
     private static final int REORDER_DELAY = 250;
     private static final int ON_EXIT_CLOSE_DELAY = 400;
+    private static final Rect sTempRect = new Rect();
+
+    private static String sDefaultFolderName;
+    private static String sHintText;
+
+    private final Alarm mReorderAlarm = new Alarm();
+    private final Alarm mOnExitAlarm = new Alarm();
+    private final Alarm mOnScrollHintAlarm = new Alarm();
+    @Thunk final Alarm mScrollPauseAlarm = new Alarm();
+
+    @Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
+
+    private final int mExpandDuration;
+    private final int mMaterialExpandDuration;
+    private final int mMaterialExpandStagger;
+
+    private final InputMethodManager mInputMethodManager;
+
+    protected final Launcher mLauncher;
+    protected DragController mDragController;
+    protected FolderInfo mInfo;
+
+    @Thunk FolderIcon mFolderIcon;
+
+    @Thunk FolderPagedView mContent;
+    @Thunk View mContentWrapper;
+    FolderEditText mFolderName;
+
+    private View mFooter;
+    private int mFooterHeight;
+
+    // Cell ranks used for drag and drop
+    @Thunk int mTargetRank, mPrevTargetRank, mEmptyCellRank;
+
+    @Thunk int mState = STATE_NONE;
     private boolean mRearrangeOnClose = false;
-    private FolderIcon mFolderIcon;
-    private int mMaxCountX;
-    private int mMaxCountY;
-    private int mMaxNumItems;
-    private ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
     boolean mItemsInvalidated = false;
     private ShortcutInfo mCurrentDragInfo;
     private View mCurrentDragView;
     private boolean mIsExternalDrag;
     boolean mSuppressOnAdd = false;
-    private int[] mTargetCell = new int[2];
-    private int[] mPreviousTargetCell = new int[2];
-    private int[] mEmptyCell = new int[2];
-    private Alarm mReorderAlarm = new Alarm();
-    private Alarm mOnExitAlarm = new Alarm();
-    private int mFolderNameHeight;
-    private Rect mTempRect = new Rect();
     private boolean mDragInProgress = false;
     private boolean mDeleteFolderOnDropCompleted = false;
     private boolean mSuppressFolderDeletion = false;
     private boolean mItemAddedBackToSelfViaIcon = false;
-    FolderEditText mFolderName;
-    private float mFolderIconPivotX;
-    private float mFolderIconPivotY;
-
+    @Thunk float mFolderIconPivotX;
+    @Thunk float mFolderIconPivotY;
     private boolean mIsEditingName = false;
-    private InputMethodManager mInputMethodManager;
-
-    private static String sDefaultFolderName;
-    private static String sHintText;
-
-    private FocusIndicatorView mFocusIndicatorHandler;
-
-    // We avoid measuring the scroll view with a 0 width or height, as this
-    // results in CellLayout being measured as UNSPECIFIED, which it does
-    // not support.
-    private static final int MIN_CONTENT_DIMEN = 5;
 
     private boolean mDestroyed;
 
-    private AutoScrollHelper mAutoScrollHelper;
-
-    private Runnable mDeferredAction;
+    @Thunk Runnable mDeferredAction;
     private boolean mDeferDropAfterUninstall;
     private boolean mUninstallSuccessful;
 
+    // Folder scrolling
+    private int mScrollAreaOffset;
+
+    @Thunk int mScrollHintDir = DragController.SCROLL_NONE;
+    @Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
+
     /**
      * Used to inflate the Workspace from XML.
      *
      * @param context The application's context.
-     * @param attrs The attribtues set containing the Workspace's customization values.
+     * @param attrs The attributes set containing the Workspace's customization values.
      */
     public Folder(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
         setAlwaysDrawnWithCacheEnabled(false);
-        mInflater = LayoutInflater.from(context);
-        mIconCache = app.getIconCache();
-
-        Resources res = getResources();
-        mMaxCountX = (int) grid.numColumns;
-        // Allow scrolling folders when DISABLE_ALL_APPS is true.
-        if (LauncherAppState.isDisableAllApps()) {
-            mMaxCountY = mMaxNumItems = Integer.MAX_VALUE;
-        } else {
-            mMaxCountY = (int) grid.numRows;
-            mMaxNumItems = mMaxCountX * mMaxCountY;
-        }
-
         mInputMethodManager = (InputMethodManager)
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
+        Resources res = getResources();
         mExpandDuration = res.getInteger(R.integer.config_folderExpandDuration);
         mMaterialExpandDuration = res.getInteger(R.integer.config_materialFolderExpandDuration);
         mMaterialExpandStagger = res.getInteger(R.integer.config_materialFolderExpandStagger);
@@ -172,45 +185,35 @@
         mLauncher = (Launcher) context;
         // We need this view to be focusable in touch mode so that when text editing of the folder
         // name is complete, we have something to focus on, thus hiding the cursor and giving
-        // reliable behvior when clicking the text field (since it will always gain focus on click).
+        // reliable behavior when clicking the text field (since it will always gain focus on click).
         setFocusableInTouchMode(true);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mScrollView = (ScrollView) findViewById(R.id.scroll_view);
-        mContent = (CellLayout) findViewById(R.id.folder_content);
+        mContentWrapper = findViewById(R.id.folder_content_wrapper);
+        mContent = (FolderPagedView) findViewById(R.id.folder_content);
+        mContent.setFolder(this);
 
-        mFocusIndicatorHandler = new FocusIndicatorView(getContext());
-        mContent.addView(mFocusIndicatorHandler, 0);
-        mFocusIndicatorHandler.getLayoutParams().height = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
-        mFocusIndicatorHandler.getLayoutParams().width = FocusIndicatorView.DEFAULT_LAYOUT_SIZE;
-
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
-        mContent.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
-        mContent.setGridSize(0, 0);
-        mContent.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
-        mContent.setInvertIfRtl(true);
         mFolderName = (FolderEditText) findViewById(R.id.folder_name);
         mFolderName.setFolder(this);
         mFolderName.setOnFocusChangeListener(this);
 
-        // We find out how tall the text view wants to be (it is set to wrap_content), so that
-        // we can allocate the appropriate amount of space for it.
-        int measureSpec = MeasureSpec.UNSPECIFIED;
-        mFolderName.measure(measureSpec, measureSpec);
-        mFolderNameHeight = mFolderName.getMeasuredHeight();
-
         // We disable action mode for now since it messes up the view on phones
         mFolderName.setCustomSelectionActionModeCallback(mActionModeCallback);
         mFolderName.setOnEditorActionListener(this);
         mFolderName.setSelectAllOnFocus(true);
         mFolderName.setInputType(mFolderName.getInputType() |
                 InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
-        mAutoScrollHelper = new FolderAutoScrollHelper(mScrollView);
+
+        mFooter = findViewById(R.id.folder_footer);
+
+        // We find out how tall footer wants to be (it is set to wrap_content), so that
+        // we can allocate the appropriate amount of space for it.
+        int measureSpec = MeasureSpec.UNSPECIFIED;
+        mFooter.measure(measureSpec, measureSpec);
+        mFooterHeight = mFooter.getMeasuredHeight();
     }
 
     private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -240,7 +243,10 @@
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
         if (!mLauncher.isDraggingEnabled()) return true;
+        return beginDrag(v, false);
+    }
 
+    private boolean beginDrag(View v, boolean accessible) {
         Object tag = v.getTag();
         if (tag instanceof ShortcutInfo) {
             ShortcutInfo item = (ShortcutInfo) tag;
@@ -248,14 +254,13 @@
                 return false;
             }
 
-            mLauncher.getWorkspace().beginDragShared(v, this);
+            mLauncher.getWorkspace().beginDragShared(v, new Point(), this, accessible);
 
             mCurrentDragInfo = item;
-            mEmptyCell[0] = item.cellX;
-            mEmptyCell[1] = item.cellY;
+            mEmptyCellRank = item.rank;
             mCurrentDragView = v;
 
-            mContent.removeView(mCurrentDragView);
+            mContent.removeItem(mCurrentDragView);
             mInfo.remove(mCurrentDragInfo);
             mDragInProgress = true;
             mItemAddedBackToSelfViaIcon = false;
@@ -263,6 +268,23 @@
         return true;
     }
 
+    @Override
+    public void startDrag(CellInfo cellInfo, boolean accessible) {
+        beginDrag(cellInfo.cell, accessible);
+    }
+
+    @Override
+    public void enableAccessibleDrag(boolean enable) {
+        mLauncher.getSearchBar().enableAccessibleDrag(enable);
+        for (int i = 0; i < mContent.getChildCount(); i++) {
+            mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG);
+        }
+
+        mFooter.setImportantForAccessibility(enable ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS :
+            IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        mLauncher.getWorkspace().setAddNewPageOnDrag(!enable);
+    }
+
     public boolean isEditingName() {
         return mIsEditingName;
     }
@@ -309,13 +331,10 @@
         return mFolderName;
     }
 
-    public CellLayout getContent() {
-        return mContent;
-    }
-
     /**
      * We need to handle touch events to prevent them from falling through to the workspace below.
      */
+    @SuppressLint("ClickableViewAccessibility")
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         return true;
@@ -325,7 +344,7 @@
         mDragController = dragController;
     }
 
-    void setFolderIcon(FolderIcon icon) {
+    public void setFolderIcon(FolderIcon icon) {
         mFolderIcon = icon;
     }
 
@@ -338,64 +357,16 @@
     /**
      * @return the FolderInfo object associated with this folder
      */
-    FolderInfo getInfo() {
+    public FolderInfo getInfo() {
         return mInfo;
     }
 
-    private class GridComparator implements Comparator<ShortcutInfo> {
-        int mNumCols;
-        public GridComparator(int numCols) {
-            mNumCols = numCols;
-        }
-
-        @Override
-        public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
-            int lhIndex = lhs.cellY * mNumCols + lhs.cellX;
-            int rhIndex = rhs.cellY * mNumCols + rhs.cellX;
-            return (lhIndex - rhIndex);
-        }
-    }
-
-    private void placeInReadingOrder(ArrayList<ShortcutInfo> items) {
-        int maxX = 0;
-        int count = items.size();
-        for (int i = 0; i < count; i++) {
-            ShortcutInfo item = items.get(i);
-            if (item.cellX > maxX) {
-                maxX = item.cellX;
-            }
-        }
-
-        GridComparator gridComparator = new GridComparator(maxX + 1);
-        Collections.sort(items, gridComparator);
-        final int countX = mContent.getCountX();
-        for (int i = 0; i < count; i++) {
-            int x = i % countX;
-            int y = i / countX;
-            ShortcutInfo item = items.get(i);
-            item.cellX = x;
-            item.cellY = y;
-        }
-    }
-
     void bind(FolderInfo info) {
         mInfo = info;
         ArrayList<ShortcutInfo> children = info.contents;
-        ArrayList<ShortcutInfo> overflow = new ArrayList<ShortcutInfo>();
-        setupContentForNumItems(children.size());
-        placeInReadingOrder(children);
-        int count = 0;
-        for (int i = 0; i < children.size(); i++) {
-            ShortcutInfo child = (ShortcutInfo) children.get(i);
-            if (createAndAddShortcut(child) == null) {
-                overflow.add(child);
-            } else {
-                count++;
-            }
-        }
+        Collections.sort(children, ITEM_POS_COMPARATOR);
 
-        // We rearrange the items in case there are any empty gaps
-        setupContentForNumItems(count);
+        ArrayList<ShortcutInfo> overflow = mContent.bindItems(children);
 
         // If our folder has too many items we prune them from the list. This is an issue
         // when upgrading from the old Folders implementation which could contain an unlimited
@@ -405,6 +376,14 @@
             LauncherModel.deleteItemFromDatabase(mLauncher, item);
         }
 
+        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+        if (lp == null) {
+            lp = new DragLayer.LayoutParams(0, 0);
+            lp.customPosition = true;
+            setLayoutParams(lp);
+        }
+        centerAboutIcon();
+
         mItemsInvalidated = true;
         updateTextViewFocus();
         mInfo.addListener(this);
@@ -414,7 +393,6 @@
         } else {
             mFolderName.setText("");
         }
-        updateItemLocationsInDatabase();
 
         // In case any children didn't come across during loading, clean up the folder accordingly
         mFolderIcon.post(new Runnable() {
@@ -433,8 +411,9 @@
      *
      * @return A new UserFolder.
      */
-    static Folder fromXml(Context context) {
-        return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
+    @SuppressLint("InflateParams")
+    static Folder fromXml(Launcher launcher) {
+        return (Folder) launcher.getLayoutInflater().inflate(R.layout.user_folder, null);
     }
 
     /**
@@ -459,6 +438,12 @@
     public void animateOpen() {
         if (!(getParent() instanceof DragLayer)) return;
 
+        mContent.completePendingPageChanges();
+        if (!mDragInProgress) {
+            // Open on the first page.
+            mContent.snapToPageImmediately(0);
+        }
+
         Animator openFolderAnim = null;
         final Runnable onCompleteRunnable;
         if (!Utilities.isLmpOrAbove()) {
@@ -484,6 +469,7 @@
             prepareReveal();
             centerAboutIcon();
 
+            AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
             int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
             int height = getFolderHeight();
 
@@ -494,32 +480,32 @@
             PropertyValuesHolder tx = PropertyValuesHolder.ofFloat("translationX", transX, 0);
             PropertyValuesHolder ty = PropertyValuesHolder.ofFloat("translationY", transY, 0);
 
+            Animator drift = ObjectAnimator.ofPropertyValuesHolder(this, tx, ty);
+            drift.setDuration(mMaterialExpandDuration);
+            drift.setStartDelay(mMaterialExpandStagger);
+            drift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
             int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
             int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
-            float radius = (float) Math.sqrt(rx * rx + ry * ry);
-            AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
-            Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
+            float radius = (float) Math.hypot(rx, ry);
+
+            Animator reveal = UiThreadCircularReveal.createCircularReveal(this, (int) getPivotX(),
                     (int) getPivotY(), 0, radius);
             reveal.setDuration(mMaterialExpandDuration);
             reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
 
-            mContent.setAlpha(0f);
-            Animator iconsAlpha = LauncherAnimUtils.ofFloat(mContent, "alpha", 0f, 1f);
+            mContentWrapper.setAlpha(0f);
+            Animator iconsAlpha = ObjectAnimator.ofFloat(mContentWrapper, "alpha", 0f, 1f);
             iconsAlpha.setDuration(mMaterialExpandDuration);
             iconsAlpha.setStartDelay(mMaterialExpandStagger);
             iconsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
 
-            mFolderName.setAlpha(0f);
-            Animator textAlpha = LauncherAnimUtils.ofFloat(mFolderName, "alpha", 0f, 1f);
+            mFooter.setAlpha(0f);
+            Animator textAlpha = ObjectAnimator.ofFloat(mFooter, "alpha", 0f, 1f);
             textAlpha.setDuration(mMaterialExpandDuration);
             textAlpha.setStartDelay(mMaterialExpandStagger);
             textAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
 
-            Animator drift = LauncherAnimUtils.ofPropertyValuesHolder(this, tx, ty);
-            drift.setDuration(mMaterialExpandDuration);
-            drift.setStartDelay(mMaterialExpandStagger);
-            drift.setInterpolator(new LogDecelerateInterpolator(60, 0));
-
             anim.play(drift);
             anim.play(iconsAlpha);
             anim.play(textAlpha);
@@ -527,11 +513,13 @@
 
             openFolderAnim = anim;
 
-            mContent.setLayerType(LAYER_TYPE_HARDWARE, null);
+            mContentWrapper.setLayerType(LAYER_TYPE_HARDWARE, null);
+            mFooter.setLayerType(LAYER_TYPE_HARDWARE, null);
             onCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    mContent.setLayerType(LAYER_TYPE_NONE, null);
+                    mContentWrapper.setLayerType(LAYER_TYPE_NONE, null);
+                    mContentWrapper.setLayerType(LAYER_TYPE_NONE, null);
                 }
             };
         }
@@ -539,8 +527,7 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 sendCustomAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
-                        String.format(getContext().getString(R.string.folder_opened),
-                        mContent.getCountX(), mContent.getCountY()));
+                        mContent.getAccessibilityDescription());
                 mState = STATE_ANIMATING;
             }
             @Override
@@ -551,30 +538,79 @@
                     onCompleteRunnable.run();
                 }
 
-                setFocusOnFirstChild();
+                mContent.setFocusOnFirstChild();
             }
         });
+
+        // Footer animation
+        if (mContent.getPageCount() > 1 && !mInfo.hasOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION)) {
+            int footerWidth = mContent.getDesiredWidth()
+                    - mFooter.getPaddingLeft() - mFooter.getPaddingRight();
+
+            float textWidth =  mFolderName.getPaint().measureText(mFolderName.getText().toString());
+            float translation = (footerWidth - textWidth) / 2;
+            mFolderName.setTranslationX(mContent.mIsRtl ? -translation : translation);
+            mContent.setMarkerScale(0);
+
+            // Do not update the flag if we are in drag mode. The flag will be updated, when we
+            // actually drop the icon.
+            final boolean updateAnimationFlag = !mDragInProgress;
+            openFolderAnim.addListener(new AnimatorListenerAdapter() {
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
+                        .translationX(0)
+                        .setInterpolator(Utilities.isLmpOrAbove() ?
+                                AnimationUtils.loadInterpolator(mLauncher,
+                                        android.R.interpolator.fast_out_slow_in)
+                                : new LogDecelerateInterpolator(100, 0));
+                    mContent.animateMarkers();
+
+                    if (updateAnimationFlag) {
+                        mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher);
+                    }
+                }
+            });
+        } else {
+            mFolderName.setTranslationX(0);
+            mContent.setMarkerScale(1);
+        }
+
         openFolderAnim.start();
 
         // Make sure the folder picks up the last drag move even if the finger doesn't move.
         if (mDragController.isDragging()) {
             mDragController.forceTouchMove();
         }
+
+        FolderPagedView pages = (FolderPagedView) mContent;
+        pages.verifyVisibleHighResIcons(pages.getNextPage());
     }
 
     public void beginExternalDrag(ShortcutInfo item) {
-        setupContentForNumItems(getItemCount() + 1);
-        findAndSetEmptyCells(item);
-
         mCurrentDragInfo = item;
-        mEmptyCell[0] = item.cellX;
-        mEmptyCell[1] = item.cellY;
+        mEmptyCellRank = mContent.allocateRankForNewItem(item);
         mIsExternalDrag = true;
-
         mDragInProgress = true;
+
+        // Since this folder opened by another controller, it might not get onDrop or
+        // onDropComplete. Perform cleanup once drag-n-drop ends.
+        mDragController.addDragListener(this);
     }
 
-    private void sendCustomAccessibilityEvent(int type, String text) {
+    @Override
+    public void onDragStart(DragSource source, Object info, int dragAction) { }
+
+    @Override
+    public void onDragEnd() {
+        if (mIsExternalDrag && mDragInProgress) {
+            completeDragExit();
+        }
+        mDragController.removeDragListener(this);
+    }
+
+    @Thunk void sendCustomAccessibilityEvent(int type, String text) {
         AccessibilityManager accessibilityManager = (AccessibilityManager)
                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
         if (accessibilityManager.isEnabled()) {
@@ -585,13 +621,6 @@
         }
     }
 
-    private void setFocusOnFirstChild() {
-        View firstChild = mContent.getChildAt(0, 0);
-        if (firstChild != null) {
-            firstChild.requestFocus();
-        }
-    }
-
     public void animateClosed() {
         if (!(getParent() instanceof DragLayer)) return;
         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0);
@@ -627,174 +656,90 @@
                     !isFull());
     }
 
-    protected boolean findAndSetEmptyCells(ShortcutInfo item) {
-        int[] emptyCell = new int[2];
-        if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
-            item.cellX = emptyCell[0];
-            item.cellY = emptyCell[1];
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    protected View createAndAddShortcut(ShortcutInfo item) {
-        final BubbleTextView textView =
-            (BubbleTextView) mInflater.inflate(R.layout.folder_application, this, false);
-        textView.applyFromShortcutInfo(item, mIconCache, false);
-
-        textView.setOnClickListener(this);
-        textView.setOnLongClickListener(this);
-        textView.setOnFocusChangeListener(mFocusIndicatorHandler);
-
-        // We need to check here to verify that the given item's location isn't already occupied
-        // by another item.
-        if (mContent.getChildAt(item.cellX, item.cellY) != null || item.cellX < 0 || item.cellY < 0
-                || item.cellX >= mContent.getCountX() || item.cellY >= mContent.getCountY()) {
-            // This shouldn't happen, log it.
-            Log.e(TAG, "Folder order not properly persisted during bind");
-            if (!findAndSetEmptyCells(item)) {
-                return null;
-            }
-        }
-
-        CellLayout.LayoutParams lp =
-            new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
-        boolean insert = false;
-        textView.setOnKeyListener(new FolderKeyEventListener());
-        mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
-        return textView;
-    }
-
     public void onDragEnter(DragObject d) {
-        mPreviousTargetCell[0] = -1;
-        mPreviousTargetCell[1] = -1;
+        mPrevTargetRank = -1;
         mOnExitAlarm.cancelAlarm();
+        // Get the area offset such that the folder only closes if half the drag icon width
+        // is outside the folder area
+        mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
     }
 
     OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
         public void onAlarm(Alarm alarm) {
-            realTimeReorder(mEmptyCell, mTargetCell);
+            mContent.realTimeReorder(mEmptyCellRank, mTargetRank);
+            mEmptyCellRank = mTargetRank;
         }
     };
 
-    boolean readingOrderGreaterThan(int[] v1, int[] v2) {
-        if (v1[1] > v2[1] || (v1[1] == v2[1] && v1[0] > v2[0])) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    private void realTimeReorder(int[] empty, int[] target) {
-        boolean wrap;
-        int startX;
-        int endX;
-        int startY;
-        int delay = 0;
-        float delayAmount = 30;
-        if (readingOrderGreaterThan(target, empty)) {
-            wrap = empty[0] >= mContent.getCountX() - 1;
-            startY = wrap ? empty[1] + 1 : empty[1];
-            for (int y = startY; y <= target[1]; y++) {
-                startX = y == empty[1] ? empty[0] + 1 : 0;
-                endX = y < target[1] ? mContent.getCountX() - 1 : target[0];
-                for (int x = startX; x <= endX; x++) {
-                    View v = mContent.getChildAt(x,y);
-                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
-                            REORDER_ANIMATION_DURATION, delay, true, true)) {
-                        empty[0] = x;
-                        empty[1] = y;
-                        delay += delayAmount;
-                        delayAmount *= 0.9;
-                    }
-                }
-            }
-        } else {
-            wrap = empty[0] == 0;
-            startY = wrap ? empty[1] - 1 : empty[1];
-            for (int y = startY; y >= target[1]; y--) {
-                startX = y == empty[1] ? empty[0] - 1 : mContent.getCountX() - 1;
-                endX = y > target[1] ? 0 : target[0];
-                for (int x = startX; x >= endX; x--) {
-                    View v = mContent.getChildAt(x,y);
-                    if (mContent.animateChildToPosition(v, empty[0], empty[1],
-                            REORDER_ANIMATION_DURATION, delay, true, true)) {
-                        empty[0] = x;
-                        empty[1] = y;
-                        delay += delayAmount;
-                        delayAmount *= 0.9;
-                    }
-                }
-            }
-        }
-    }
-
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public boolean isLayoutRtl() {
         return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
     }
 
+    @Override
     public void onDragOver(DragObject d) {
-        final DragView dragView = d.dragView;
-        final int scrollOffset = mScrollView.getScrollY();
-        final float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, dragView, null);
-        r[0] -= getPaddingLeft();
-        r[1] -= getPaddingTop();
+        onDragOver(d, REORDER_DELAY);
+    }
 
-        final long downTime = SystemClock.uptimeMillis();
-        final MotionEvent translatedEv = MotionEvent.obtain(
-                downTime, downTime, MotionEvent.ACTION_MOVE, d.x, d.y, 0);
+    private int getTargetRank(DragObject d, float[] recycle) {
+        recycle = d.getVisualCenter(recycle);
+        return mContent.findNearestArea(
+                (int) recycle[0] - getPaddingLeft(), (int) recycle[1] - getPaddingTop());
+    }
 
-        if (!mAutoScrollHelper.isEnabled()) {
-            mAutoScrollHelper.setEnabled(true);
+    @Thunk void onDragOver(DragObject d, int reorderDelay) {
+        if (mScrollPauseAlarm.alarmPending()) {
+            return;
+        }
+        final float[] r = new float[2];
+        mTargetRank = getTargetRank(d, r);
+
+        if (mTargetRank != mPrevTargetRank) {
+            mReorderAlarm.cancelAlarm();
+            mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
+            mReorderAlarm.setAlarm(REORDER_DELAY);
+            mPrevTargetRank = mTargetRank;
         }
 
-        final boolean handled = mAutoScrollHelper.onTouch(this, translatedEv);
-        translatedEv.recycle();
+        float x = r[0];
+        int currentPage = mContent.getNextPage();
 
-        if (handled) {
-            mReorderAlarm.cancelAlarm();
+        float cellOverlap = mContent.getCurrentCellLayout().getCellWidth()
+                * ICON_OVERSCROLL_WIDTH_FACTOR;
+        boolean isOutsideLeftEdge = x < cellOverlap;
+        boolean isOutsideRightEdge = x > (getWidth() - cellOverlap);
+
+        if (currentPage > 0 && (mContent.mIsRtl ? isOutsideRightEdge : isOutsideLeftEdge)) {
+            showScrollHint(DragController.SCROLL_LEFT, d);
+        } else if (currentPage < (mContent.getPageCount() - 1)
+                && (mContent.mIsRtl ? isOutsideLeftEdge : isOutsideRightEdge)) {
+            showScrollHint(DragController.SCROLL_RIGHT, d);
         } else {
-            mTargetCell = mContent.findNearestArea(
-                    (int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell);
-            if (isLayoutRtl()) {
-                mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1;
-            }
-            if (mTargetCell[0] != mPreviousTargetCell[0]
-                    || mTargetCell[1] != mPreviousTargetCell[1]) {
-                mReorderAlarm.cancelAlarm();
-                mReorderAlarm.setOnAlarmListener(mReorderAlarmListener);
-                mReorderAlarm.setAlarm(REORDER_DELAY);
-                mPreviousTargetCell[0] = mTargetCell[0];
-                mPreviousTargetCell[1] = mTargetCell[1];
+            mOnScrollHintAlarm.cancelAlarm();
+            if (mScrollHintDir != DragController.SCROLL_NONE) {
+                mContent.clearScrollHint();
+                mScrollHintDir = DragController.SCROLL_NONE;
             }
         }
     }
 
-    // This is used to compute the visual center of the dragView. The idea is that
-    // the visual center represents the user's interpretation of where the item is, and hence
-    // is the appropriate point to use when determining drop location.
-    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
-            DragView dragView, float[] recycle) {
-        float res[];
-        if (recycle == null) {
-            res = new float[2];
-        } else {
-            res = recycle;
+    private void showScrollHint(int direction, DragObject d) {
+        // Show scroll hint on the right
+        if (mScrollHintDir != direction) {
+            mContent.showScrollHint(direction);
+            mScrollHintDir = direction;
         }
 
-        // These represent the visual top and left of drag view if a dragRect was provided.
-        // If a dragRect was not provided, then they correspond to the actual view left and
-        // top, as the dragRect is in that case taken to be the entire dragView.
-        // R.dimen.dragViewOffsetY.
-        int left = x - xOffset;
-        int top = y - yOffset;
+        // Set alarm for when the hint is complete
+        if (!mOnScrollHintAlarm.alarmPending() || mCurrentScrollDir != direction) {
+            mCurrentScrollDir = direction;
+            mOnScrollHintAlarm.cancelAlarm();
+            mOnScrollHintAlarm.setOnAlarmListener(new OnScrollHintListener(d));
+            mOnScrollHintAlarm.setAlarm(SCROLL_HINT_DURATION);
 
-        // In order to find the visual center, we shift by half the dragRect
-        res[0] = left + dragView.getDragRegion().width() / 2;
-        res[1] = top + dragView.getDragRegion().height() / 2;
-
-        return res;
+            mReorderAlarm.cancelAlarm();
+            mTargetRank = mEmptyCellRank;
+        }
     }
 
     OnAlarmListener mOnExitAlarmListener = new OnAlarmListener() {
@@ -804,17 +749,25 @@
     };
 
     public void completeDragExit() {
-        mLauncher.closeFolder();
+        if (mInfo.opened) {
+            mLauncher.closeFolder();
+            mRearrangeOnClose = true;
+        } else if (mState == STATE_ANIMATING) {
+            mRearrangeOnClose = true;
+        } else {
+            rearrangeChildren();
+            clearDragInfo();
+        }
+    }
+
+    private void clearDragInfo() {
         mCurrentDragInfo = null;
         mCurrentDragView = null;
         mSuppressOnAdd = false;
-        mRearrangeOnClose = true;
         mIsExternalDrag = false;
     }
 
     public void onDragExit(DragObject d) {
-        // Exiting folder; stop the auto scroller.
-        mAutoScrollHelper.setEnabled(false);
         // We only close the folder if this is a true drag exit, ie. not because
         // a drop has occurred above the folder.
         if (!d.dragComplete) {
@@ -822,6 +775,25 @@
             mOnExitAlarm.setAlarm(ON_EXIT_CLOSE_DELAY);
         }
         mReorderAlarm.cancelAlarm();
+
+        mOnScrollHintAlarm.cancelAlarm();
+        mScrollPauseAlarm.cancelAlarm();
+        if (mScrollHintDir != DragController.SCROLL_NONE) {
+            mContent.clearScrollHint();
+            mScrollHintDir = DragController.SCROLL_NONE;
+        }
+    }
+
+    /**
+     * When performing an accessibility drop, onDrop is sent immediately after onDragEnter. So we
+     * need to complete all transient states based on timers.
+     */
+    @Override
+    public void prepareAccessibilityDrop() {
+        if (mReorderAlarm.alarmPending()) {
+            mReorderAlarm.cancelAlarm();
+            mReorderAlarmListener.onAlarm(mReorderAlarm);
+        }
     }
 
     public void onDropCompleted(final View target, final DragObject d,
@@ -846,9 +818,18 @@
                 replaceFolderWithFinalItem();
             }
         } else {
-            setupContentForNumItems(getItemCount());
             // The drag failed, we need to return the item to the folder
+            ShortcutInfo info = (ShortcutInfo) d.dragInfo;
+            View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
+                    ? mCurrentDragView : mContent.createNewView(info);
+            ArrayList<View> views = getItemsInReadingOrder();
+            views.add(info.rank, icon);
+            mContent.arrangeChildren(views, views.size());
+            mItemsInvalidated = true;
+
+            mSuppressOnAdd = true;
             mFolderIcon.onDrop(d);
+            mSuppressOnAdd = false;
         }
 
         if (target != this) {
@@ -857,6 +838,7 @@
                 if (!successfulDrop) {
                     mSuppressFolderDeletion = true;
                 }
+                mScrollPauseAlarm.cancelAlarm();
                 completeDragExit();
             }
         }
@@ -871,12 +853,22 @@
         // Reordering may have occured, and we need to save the new item locations. We do this once
         // at the end to prevent unnecessary database operations.
         updateItemLocationsInDatabaseBatch();
+
+        // Use the item count to check for multi-page as the folder UI may not have
+        // been refreshed yet.
+        if (getItemCount() <= mContent.itemsPerPage()) {
+            // Show the animation, next time something is added to the folder.
+            mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false, mLauncher);
+        }
+
     }
 
+    @Override
     public void deferCompleteDropAfterUninstallActivity() {
         mDeferDropAfterUninstall = true;
     }
 
+    @Override
     public void onUninstallActivityReturned(boolean success) {
         mDeferDropAfterUninstall = false;
         mUninstallSuccessful = success;
@@ -905,7 +897,8 @@
         return true;
     }
 
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+    @Override
+    public void onFlingToDelete(DragObject d, PointF vec) {
         // Do nothing
     }
 
@@ -914,22 +907,13 @@
         // Do nothing
     }
 
-    private void updateItemLocationsInDatabase() {
-        ArrayList<View> list = getItemsInReadingOrder();
-        for (int i = 0; i < list.size(); i++) {
-            View v = list.get(i);
-            ItemInfo info = (ItemInfo) v.getTag();
-            LauncherModel.moveItemInDatabase(mLauncher, info, mInfo.id, 0,
-                    info.cellX, info.cellY);
-        }
-    }
-
     private void updateItemLocationsInDatabaseBatch() {
         ArrayList<View> list = getItemsInReadingOrder();
         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
         for (int i = 0; i < list.size(); i++) {
             View v = list.get(i);
             ItemInfo info = (ItemInfo) v.getTag();
+            info.rank = i;
             items.add(info);
         }
 
@@ -942,7 +926,7 @@
             View v = list.get(i);
             ItemInfo info = (ItemInfo) v.getTag();
             LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
-                        info.cellX, info.cellY, false);
+                    info.cellX, info.cellY);
         }
     }
 
@@ -956,37 +940,8 @@
         return true;
     }
 
-    private void setupContentDimensions(int count) {
-        ArrayList<View> list = getItemsInReadingOrder();
-
-        int countX = mContent.getCountX();
-        int countY = mContent.getCountY();
-        boolean done = false;
-
-        while (!done) {
-            int oldCountX = countX;
-            int oldCountY = countY;
-            if (countX * countY < count) {
-                // Current grid is too small, expand it
-                if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
-                    countX++;
-                } else if (countY < mMaxCountY) {
-                    countY++;
-                }
-                if (countY == 0) countY++;
-            } else if ((countY - 1) * countX >= count && countY >= countX) {
-                countY = Math.max(0, countY - 1);
-            } else if ((countX - 1) * countY >= count) {
-                countX = Math.max(0, countX - 1);
-            }
-            done = countX == oldCountX && countY == oldCountY;
-        }
-        mContent.setGridSize(countX, countY);
-        arrangeChildren(list);
-    }
-
     public boolean isFull() {
-        return getItemCount() >= mMaxNumItems;
+        return mContent.isFull();
     }
 
     private void centerAboutIcon() {
@@ -996,41 +951,30 @@
         int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
         int height = getFolderHeight();
 
-        float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, mTempRect);
+        float scale = parent.getDescendantRectRelativeToSelf(mFolderIcon, sTempRect);
 
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
-        int centerX = (int) (mTempRect.left + mTempRect.width() * scale / 2);
-        int centerY = (int) (mTempRect.top + mTempRect.height() * scale / 2);
+        int centerX = (int) (sTempRect.left + sTempRect.width() * scale / 2);
+        int centerY = (int) (sTempRect.top + sTempRect.height() * scale / 2);
         int centeredLeft = centerX - width / 2;
         int centeredTop = centerY - height / 2;
-        int currentPage = mLauncher.getWorkspace().getNextPage();
-        // In case the workspace is scrolling, we need to use the final scroll to compute
-        // the folders bounds.
-        mLauncher.getWorkspace().setFinalScrollForPageChange(currentPage);
-        // We first fetch the currently visible CellLayoutChildren
-        CellLayout currentLayout = (CellLayout) mLauncher.getWorkspace().getChildAt(currentPage);
-        ShortcutAndWidgetContainer boundingLayout = currentLayout.getShortcutsAndWidgets();
-        Rect bounds = new Rect();
-        parent.getDescendantRectRelativeToSelf(boundingLayout, bounds);
-        // We reset the workspaces scroll
-        mLauncher.getWorkspace().resetFinalScrollForPageChange(currentPage);
 
-        // We need to bound the folder to the currently visible CellLayoutChildren
-        int left = Math.min(Math.max(bounds.left, centeredLeft),
-                bounds.left + bounds.width() - width);
-        int top = Math.min(Math.max(bounds.top, centeredTop),
-                bounds.top + bounds.height() - height);
-        if (grid.isPhone() && (grid.availableWidthPx - width) < grid.iconSizePx) {
+        // We need to bound the folder to the currently visible workspace area
+        mLauncher.getWorkspace().getPageAreaRelativeToDragLayer(sTempRect);
+        int left = Math.min(Math.max(sTempRect.left, centeredLeft),
+                sTempRect.left + sTempRect.width() - width);
+        int top = Math.min(Math.max(sTempRect.top, centeredTop),
+                sTempRect.top + sTempRect.height() - height);
+        if (grid.isPhone && (grid.availableWidthPx - width) < grid.iconSizePx) {
             // Center the folder if it is full (on phones only)
             left = (grid.availableWidthPx - width) / 2;
-        } else if (width >= bounds.width()) {
+        } else if (width >= sTempRect.width()) {
             // If the folder doesn't fit within the bounds, center it about the desired bounds
-            left = bounds.left + (bounds.width() - width) / 2;
+            left = sTempRect.left + (sTempRect.width() - width) / 2;
         }
-        if (height >= bounds.height()) {
-            top = bounds.top + (bounds.height() - height) / 2;
+        if (height >= sTempRect.height()) {
+            top = sTempRect.top + (sTempRect.height() - height) / 2;
         }
 
         int folderPivotX = width / 2 + (centeredLeft - left);
@@ -1055,26 +999,12 @@
         return mFolderIconPivotY;
     }
 
-    private void setupContentForNumItems(int count) {
-        setupContentDimensions(count);
-
-        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
-        if (lp == null) {
-            lp = new DragLayer.LayoutParams(0, 0);
-            lp.customPosition = true;
-            setLayoutParams(lp);
-        }
-        centerAboutIcon();
-    }
-
     private int getContentAreaHeight() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        Rect workspacePadding = grid.getWorkspacePadding(grid.isLandscape ?
-                CellLayout.LANDSCAPE : CellLayout.PORTRAIT);
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        Rect workspacePadding = grid.getWorkspacePadding(mContent.mIsRtl);
         int maxContentAreaHeight = grid.availableHeightPx -
                 workspacePadding.top - workspacePadding.bottom -
-                mFolderNameHeight;
+                mFooterHeight;
         int height = Math.min(maxContentAreaHeight,
                 mContent.getDesiredHeight());
         return Math.max(height, MIN_CONTENT_DIMEN);
@@ -1085,67 +1015,67 @@
     }
 
     private int getFolderHeight() {
-        int height = getPaddingTop() + getPaddingBottom()
-                + getContentAreaHeight() + mFolderNameHeight;
-        return height;
+        return getFolderHeight(getContentAreaHeight());
+    }
+
+    private int getFolderHeight(int contentAreaHeight) {
+        return getPaddingTop() + getPaddingBottom() + contentAreaHeight + mFooterHeight;
     }
 
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
-        int height = getFolderHeight();
-        int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
-                MeasureSpec.EXACTLY);
-        int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
-                MeasureSpec.EXACTLY);
+        int contentWidth = getContentAreaWidth();
+        int contentHeight = getContentAreaHeight();
 
-        if (LauncherAppState.isDisableAllApps()) {
-            // Don't cap the height of the content to allow scrolling.
-            mContent.setFixedSize(getContentAreaWidth(), mContent.getDesiredHeight());
-        } else {
-            mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
+        int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth, MeasureSpec.EXACTLY);
+        int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(contentHeight, MeasureSpec.EXACTLY);
+
+        mContent.setFixedSize(contentWidth, contentHeight);
+        mContentWrapper.measure(contentAreaWidthSpec, contentAreaHeightSpec);
+
+        if (mContent.getChildCount() > 0) {
+            int cellIconGap = (mContent.getPageAt(0).getCellWidth()
+                    - mLauncher.getDeviceProfile().iconSizePx) / 2;
+            mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap,
+                    mFooter.getPaddingTop(),
+                    mContent.getPaddingRight() + cellIconGap,
+                    mFooter.getPaddingBottom());
         }
+        mFooter.measure(contentAreaWidthSpec,
+                MeasureSpec.makeMeasureSpec(mFooterHeight, MeasureSpec.EXACTLY));
 
-        mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
-        mFolderName.measure(contentAreaWidthSpec,
-                MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
-        setMeasuredDimension(width, height);
+        int folderWidth = getPaddingLeft() + getPaddingRight() + contentWidth;
+        int folderHeight = getFolderHeight(contentHeight);
+        setMeasuredDimension(folderWidth, folderHeight);
     }
 
-    private void arrangeChildren(ArrayList<View> list) {
-        int[] vacant = new int[2];
-        if (list == null) {
-            list = getItemsInReadingOrder();
-        }
-        mContent.removeAllViews();
+    /**
+     * Rearranges the children based on their rank.
+     */
+    public void rearrangeChildren() {
+        rearrangeChildren(-1);
+    }
 
-        for (int i = 0; i < list.size(); i++) {
-            View v = list.get(i);
-            mContent.getVacantCell(vacant, 1, 1);
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
-            lp.cellX = vacant[0];
-            lp.cellY = vacant[1];
-            ItemInfo info = (ItemInfo) v.getTag();
-            if (info.cellX != vacant[0] || info.cellY != vacant[1]) {
-                info.cellX = vacant[0];
-                info.cellY = vacant[1];
-                LauncherModel.addOrMoveItemInDatabase(mLauncher, info, mInfo.id, 0,
-                        info.cellX, info.cellY);
-            }
-            boolean insert = false;
-            mContent.addViewToCellLayout(v, insert ? 0 : -1, (int)info.id, lp, true);
-        }
+    /**
+     * Rearranges the children based on their rank.
+     * @param itemCount if greater than the total children count, empty spaces are left at the end,
+     * otherwise it is ignored.
+     */
+    public void rearrangeChildren(int itemCount) {
+        ArrayList<View> views = getItemsInReadingOrder();
+        mContent.arrangeChildren(views, Math.max(itemCount, views.size()));
         mItemsInvalidated = true;
     }
 
+    // TODO remove this once GSA code fix is submitted
+    public ViewGroup getContent() {
+        return (ViewGroup) mContent;
+    }
+
     public int getItemCount() {
-        return mContent.getShortcutsAndWidgets().getChildCount();
+        return mContent.getItemCount();
     }
 
-    public View getItemAt(int index) {
-        return mContent.getShortcutsAndWidgets().getChildAt(index);
-    }
-
-    private void onCloseComplete() {
+    @Thunk void onCloseComplete() {
         DragLayer parent = (DragLayer) getParent();
         if (parent != null) {
             parent.removeView(this);
@@ -1155,7 +1085,7 @@
         mFolderIcon.requestFocus();
 
         if (mRearrangeOnClose) {
-            setupContentForNumItems(getItemCount());
+            rearrangeChildren();
             mRearrangeOnClose = false;
         }
         if (getItemCount() <= 1) {
@@ -1166,9 +1096,10 @@
             }
         }
         mSuppressFolderDeletion = false;
+        clearDragInfo();
     }
 
-    private void replaceFolderWithFinalItem() {
+    @Thunk void replaceFolderWithFinalItem() {
         // Add the last remaining child to the workspace in place of the folder
         Runnable onCompleteRunnable = new Runnable() {
             @Override
@@ -1179,8 +1110,7 @@
                 // Move the item from the folder to the workspace, in the position of the folder
                 if (getItemCount() == 1) {
                     ShortcutInfo finalItem = mInfo.contents.get(0);
-                    child = mLauncher.createShortcut(R.layout.application, cellLayout,
-                            finalItem);
+                    child = mLauncher.createShortcut(cellLayout, finalItem);
                     LauncherModel.addOrMoveItemInDatabase(mLauncher, finalItem, mInfo.container,
                             mInfo.screenId, mInfo.cellX, mInfo.cellY);
                 }
@@ -1205,7 +1135,7 @@
                 }
             }
         };
-        View finalChild = getItemAt(0);
+        View finalChild = mContent.getLastItem();
         if (finalChild != null) {
             mFolderIcon.performDestroyAnimation(finalChild, onCompleteRunnable);
         } else {
@@ -1220,9 +1150,8 @@
 
     // This method keeps track of the last item in the folder for the purposes
     // of keyboard focus
-    private void updateTextViewFocus() {
-        View lastChild = getItemAt(getItemCount() - 1);
-        getItemAt(getItemCount() - 1);
+    public void updateTextViewFocus() {
+        View lastChild = mContent.getLastItem();
         if (lastChild != null) {
             mFolderName.setNextFocusDownId(lastChild.getId());
             mFolderName.setNextFocusRightId(lastChild.getId());
@@ -1247,12 +1176,24 @@
             };
         }
 
+        // If the icon was dropped while the page was being scrolled, we need to compute
+        // the target location again such that the icon is placed of the final page.
+        if (!mContent.rankOnCurrentPage(mEmptyCellRank)) {
+            // Reorder again.
+            mTargetRank = getTargetRank(d, null);
+
+            // Rearrange items immediately.
+            mReorderAlarmListener.onAlarm(mReorderAlarm);
+
+            mOnScrollHintAlarm.cancelAlarm();
+            mScrollPauseAlarm.cancelAlarm();
+        }
+        mContent.completePendingPageChanges();
+
         View currentDragView;
         ShortcutInfo si = mCurrentDragInfo;
         if (mIsExternalDrag) {
-            si.cellX = mEmptyCell[0];
-            si.cellY = mEmptyCell[1];
-
+            currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank);
             // Actually move the item in the database if it was an external drag. Call this
             // before creating the view, so that ShortcutInfo is updated appropriately.
             LauncherModel.addOrMoveItemInDatabase(
@@ -1263,14 +1204,9 @@
                 updateItemLocationsInDatabaseBatch();
             }
             mIsExternalDrag = false;
-
-            currentDragView = createAndAddShortcut(si);
         } else {
             currentDragView = mCurrentDragView;
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) currentDragView.getLayoutParams();
-            si.cellX = lp.cellX = mEmptyCell[0];
-            si.cellX = lp.cellY = mEmptyCell[1];
-            mContent.addViewToCellLayout(currentDragView, -1, (int) si.id, lp, true);
+            mContent.addViewForRank(currentDragView, si, mEmptyCellRank);
         }
 
         if (d.dragView.hasDrawn()) {
@@ -1289,7 +1225,7 @@
             currentDragView.setVisibility(VISIBLE);
         }
         mItemsInvalidated = true;
-        setupContentDimensions(getItemCount());
+        rearrangeChildren();
 
         // Temporarily suppress the listener, as we did all the work already here.
         mSuppressOnAdd = true;
@@ -1297,6 +1233,12 @@
         mSuppressOnAdd = false;
         // Clear the drag info, as it is no longer being dragged.
         mCurrentDragInfo = null;
+        mDragInProgress = false;
+
+        if (mContent.getPageCount() > 1) {
+            // The animation has already been shown while opening the folder.
+            mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher);
+        }
     }
 
     // This is used so the item doesn't immediately appear in the folder when added. In one case
@@ -1311,17 +1253,13 @@
         v.setVisibility(VISIBLE);
     }
 
+    @Override
     public void onAdd(ShortcutInfo item) {
-        mItemsInvalidated = true;
         // If the item was dropped onto this open folder, we have done the work associated
         // with adding the item to the folder, as indicated by mSuppressOnAdd being set
         if (mSuppressOnAdd) return;
-        if (!findAndSetEmptyCells(item)) {
-            // The current layout is full, can we expand it?
-            setupContentForNumItems(getItemCount() + 1);
-            findAndSetEmptyCells(item);
-        }
-        createAndAddShortcut(item);
+        mContent.createAndAddViewForRank(item, mContent.allocateRankForNewItem(item));
+        mItemsInvalidated = true;
         LauncherModel.addOrMoveItemInDatabase(
                 mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
     }
@@ -1332,27 +1270,25 @@
         // the work associated with removing the item, so we don't have to do anything here.
         if (item == mCurrentDragInfo) return;
         View v = getViewForInfo(item);
-        mContent.removeView(v);
+        mContent.removeItem(v);
         if (mState == STATE_ANIMATING) {
             mRearrangeOnClose = true;
         } else {
-            setupContentForNumItems(getItemCount());
+            rearrangeChildren();
         }
         if (getItemCount() <= 1) {
             replaceFolderWithFinalItem();
         }
     }
 
-    private View getViewForInfo(ShortcutInfo item) {
-        for (int j = 0; j < mContent.getCountY(); j++) {
-            for (int i = 0; i < mContent.getCountX(); i++) {
-                View v = mContent.getChildAt(i, j);
-                if (v.getTag() == item) {
-                    return v;
-                }
+    private View getViewForInfo(final ShortcutInfo item) {
+        return mContent.iterateOverItems(new ItemOperator() {
+
+            @Override
+            public boolean evaluate(ItemInfo info, View view, View parent) {
+                return info == item;
             }
-        }
-        return null;
+        });
     }
 
     public void onItemsChanged() {
@@ -1365,14 +1301,14 @@
     public ArrayList<View> getItemsInReadingOrder() {
         if (mItemsInvalidated) {
             mItemsInReadingOrder.clear();
-            for (int j = 0; j < mContent.getCountY(); j++) {
-                for (int i = 0; i < mContent.getCountX(); i++) {
-                    View v = mContent.getChildAt(i, j);
-                    if (v != null) {
-                        mItemsInReadingOrder.add(v);
-                    }
+            mContent.iterateOverItems(new ItemOperator() {
+
+                @Override
+                public boolean evaluate(ItemInfo info, View view, View parent) {
+                    mItemsInReadingOrder.add(view);
+                    return false;
                 }
-            }
+            });
             mItemsInvalidated = false;
         }
         return mItemsInReadingOrder;
@@ -1391,5 +1327,79 @@
     @Override
     public void getHitRectRelativeToDragLayer(Rect outRect) {
         getHitRect(outRect);
+        outRect.left -= mScrollAreaOffset;
+        outRect.right += mScrollAreaOffset;
     }
+
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        // Fill in from the folder icon's launch source provider first
+        Stats.LaunchSourceUtils.populateSourceDataFromAncestorProvider(mFolderIcon, sourceData);
+        sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER, Stats.SUB_CONTAINER_FOLDER);
+        sourceData.putInt(Stats.SOURCE_EXTRA_SUB_CONTAINER_PAGE, mContent.getCurrentPage());
+    }
+
+    private class OnScrollHintListener implements OnAlarmListener {
+
+        private final DragObject mDragObject;
+
+        OnScrollHintListener(DragObject object) {
+            mDragObject = object;
+        }
+
+        /**
+         * Scroll hint has been shown long enough. Now scroll to appropriate page.
+         */
+        @Override
+        public void onAlarm(Alarm alarm) {
+            if (mCurrentScrollDir == DragController.SCROLL_LEFT) {
+                mContent.scrollLeft();
+                mScrollHintDir = DragController.SCROLL_NONE;
+            } else if (mCurrentScrollDir == DragController.SCROLL_RIGHT) {
+                mContent.scrollRight();
+                mScrollHintDir = DragController.SCROLL_NONE;
+            } else {
+                // This should not happen
+                return;
+            }
+            mCurrentScrollDir = DragController.SCROLL_NONE;
+
+            // Pause drag event until the scrolling is finished
+            mScrollPauseAlarm.setOnAlarmListener(new OnScrollFinishedListener(mDragObject));
+            mScrollPauseAlarm.setAlarm(DragController.RESCROLL_DELAY);
+        }
+    }
+
+    private class OnScrollFinishedListener implements OnAlarmListener {
+
+        private final DragObject mDragObject;
+
+        OnScrollFinishedListener(DragObject object) {
+            mDragObject = object;
+        }
+
+        /**
+         * Page scroll is complete.
+         */
+        @Override
+        public void onAlarm(Alarm alarm) {
+            // Reorder immediately on page change.
+            onDragOver(mDragObject, 1);
+        }
+    }
+
+    // Compares item position based on rank and position giving priority to the rank.
+    private static final Comparator<ItemInfo> ITEM_POS_COMPARATOR = new Comparator<ItemInfo>() {
+
+        @Override
+        public int compare(ItemInfo lhs, ItemInfo rhs) {
+            if (lhs.rank != rhs.rank) {
+                return lhs.rank - rhs.rank;
+            } else if (lhs.cellY != rhs.cellY) {
+                return lhs.cellY - rhs.cellY;
+            } else {
+                return lhs.cellX - rhs.cellX;
+            }
+        }
+    };
 }
diff --git a/src/com/android/launcher3/FolderAutoScrollHelper.java b/src/com/android/launcher3/FolderAutoScrollHelper.java
deleted file mode 100644
index 40e8884..0000000
--- a/src/com/android/launcher3/FolderAutoScrollHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.support.v4.widget.AutoScrollHelper;
-import android.widget.ScrollView;
-
-/**
- * An implementation of {@link AutoScrollHelper} that knows how to scroll
- * through a {@link Folder}.
- */
-public class FolderAutoScrollHelper extends AutoScrollHelper {
-    private static final float MAX_SCROLL_VELOCITY = 1500f;
-
-    private final ScrollView mTarget;
-
-    public FolderAutoScrollHelper(ScrollView target) {
-        super(target);
-
-        mTarget = target;
-
-        setActivationDelay(0);
-        setEdgeType(EDGE_TYPE_INSIDE_EXTEND);
-        setExclusive(true);
-        setMaximumVelocity(MAX_SCROLL_VELOCITY, MAX_SCROLL_VELOCITY);
-        setRampDownDuration(0);
-        setRampUpDuration(0);
-    }
-
-    @Override
-    public void scrollTargetBy(int deltaX, int deltaY) {
-        mTarget.scrollBy(deltaX, deltaY);
-    }
-
-    @Override
-    public boolean canTargetScrollHorizontally(int direction) {
-        // List do not scroll horizontally.
-        return false;
-    }
-
-    @Override
-    public boolean canTargetScrollVertically(int direction) {
-        return mTarget.canScrollVertically(direction);
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/FolderIcon.java b/src/com/android/launcher3/FolderIcon.java
index a359f11..8d534d2 100644
--- a/src/com/android/launcher3/FolderIcon.java
+++ b/src/com/android/launcher3/FolderIcon.java
@@ -43,6 +43,7 @@
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.FolderInfo.FolderListener;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
@@ -50,15 +51,16 @@
  * An icon that can appear on in the workspace representing an {@link UserFolder}.
  */
 public class FolderIcon extends FrameLayout implements FolderListener {
-    private Launcher mLauncher;
-    private Folder mFolder;
+    @Thunk Launcher mLauncher;
+    @Thunk Folder mFolder;
     private FolderInfo mInfo;
-    private static boolean sStaticValuesDirty = true;
+    @Thunk static boolean sStaticValuesDirty = true;
 
     private CheckLongPressHelper mLongPressHelper;
+    private StylusEventHelper mStylusEventHelper;
 
     // The number of icons to display in the
-    private static final int NUM_ITEMS_IN_PREVIEW = 3;
+    public static final int NUM_ITEMS_IN_PREVIEW = 3;
     private static final int CONSUMPTION_ANIMATION_DURATION = 100;
     private static final int DROP_IN_ANIMATION_DURATION = 400;
     private static final int INITIAL_ITEM_ANIMATION_DURATION = 350;
@@ -88,8 +90,8 @@
 
     public static Drawable sSharedFolderLeaveBehind = null;
 
-    private ImageView mPreviewBackground;
-    private BubbleTextView mFolderName;
+    @Thunk ImageView mPreviewBackground;
+    @Thunk BubbleTextView mFolderName;
 
     FolderRingAnimator mFolderRingAnimator = null;
 
@@ -109,11 +111,11 @@
     private float mSlop;
 
     private PreviewItemDrawingParams mParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-    private PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
-    private ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
+    @Thunk PreviewItemDrawingParams mAnimParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+    @Thunk ArrayList<ShortcutInfo> mHiddenItems = new ArrayList<ShortcutInfo>();
 
     private Alarm mOpenAlarm = new Alarm();
-    private ItemInfo mDragInfo;
+    @Thunk ItemInfo mDragInfo;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -127,6 +129,8 @@
 
     private void init() {
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
+        setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
     }
 
     public boolean isDropEnabled() {
@@ -145,8 +149,8 @@
                     "INITIAL_ITEM_ANIMATION_DURATION, as sequencing of adding first two items " +
                     "is dependent on this");
         }
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+
+        DeviceProfile grid = launcher.getDeviceProfile();
 
         FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
         icon.setClipToPadding(false);
@@ -191,7 +195,7 @@
     public static class FolderRingAnimator {
         public int mCellX;
         public int mCellY;
-        private CellLayout mCellLayout;
+        @Thunk CellLayout mCellLayout;
         public float mOuterRingSize;
         public float mInnerRingSize;
         public FolderIcon mFolderIcon = null;
@@ -215,12 +219,11 @@
                             + Thread.currentThread());
                 }
 
-                LauncherAppState app = LauncherAppState.getInstance();
-                DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+                DeviceProfile grid = launcher.getDeviceProfile();
                 sPreviewSize = grid.folderIconSizePx;
                 sPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
-                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer_holo);
-                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip_holo);
+                sSharedOuterRingDrawable = res.getDrawable(R.drawable.portal_ring_outer);
+                sSharedInnerRingDrawable = res.getDrawable(R.drawable.portal_ring_inner_nolip);
                 sSharedFolderLeaveBehind = res.getDrawable(R.drawable.portal_ring_rest);
                 sStaticValuesDirty = false;
             }
@@ -488,8 +491,7 @@
 
     private void computePreviewDrawingParams(int drawableSize, int totalSize) {
         if (mIntrinsicIconSize != drawableSize || mTotalWidth != totalSize) {
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+            DeviceProfile grid = mLauncher.getDeviceProfile();
 
             mIntrinsicIconSize = drawableSize;
             mTotalWidth = totalSize;
@@ -643,9 +645,10 @@
             final Runnable onCompleteRunnable) {
         final PreviewItemDrawingParams finalParams = computePreviewItemDrawingParams(0, null);
 
-        final float scale0 = 1.0f;
-        final float transX0 = (mAvailableSpaceInPreview - d.getIntrinsicWidth()) / 2;
-        final float transY0 = (mAvailableSpaceInPreview - d.getIntrinsicHeight()) / 2 + getPaddingTop();
+        float iconSize = mLauncher.getDeviceProfile().iconSizePx;
+        final float scale0 = iconSize / d.getIntrinsicWidth() ;
+        final float transX0 = (mAvailableSpaceInPreview - iconSize) / 2;
+        final float transY0 = (mAvailableSpaceInPreview - iconSize) / 2 + getPaddingTop();
         mAnimParams.drawable = d;
 
         ValueAnimator va = LauncherAnimUtils.ofFloat(this, 0f, 1.0f);
@@ -708,7 +711,7 @@
     }
 
     public void onTitleChanged(CharSequence title) {
-        mFolderName.setText(title.toString());
+        mFolderName.setText(title);
         setContentDescription(String.format(getContext().getString(R.string.folder_name_format),
                 title));
     }
@@ -719,6 +722,12 @@
         // isPressed() on an ACTION_UP
         boolean result = super.onTouchEvent(event);
 
+        // Check for a stylus button press, if it occurs cancel any long press checks.
+        if (mStylusEventHelper.checkAndPerformStylusEvent(event)) {
+            mLongPressHelper.cancelLongPress();
+            return true;
+        }
+
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mLongPressHelper.postCheckForLongPress();
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 85a792f..aea21c9 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -29,19 +29,38 @@
  */
 public class FolderInfo extends ItemInfo {
 
+    public static final int NO_FLAGS = 0x00000000;
+
+    /**
+     * The folder is locked in sorted mode
+     */
+    public static final int FLAG_ITEMS_SORTED = 0x00000001;
+
+    /**
+     * It is a work folder
+     */
+    public static final int FLAG_WORK_FOLDER = 0x00000002;
+
+    /**
+     * The multi-page animation has run for this folder
+     */
+    public static final int FLAG_MULTI_PAGE_ANIMATION = 0x00000004;
+
     /**
      * Whether this folder has been opened
      */
     boolean opened;
 
+    public int options;
+
     /**
      * The apps and shortcuts
      */
-    ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
+    public ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
 
     ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
 
-    FolderInfo() {
+    public FolderInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
         user = UserHandleCompat.myUserHandle();
     }
@@ -83,6 +102,8 @@
     void onAddToDatabase(Context context, ContentValues values) {
         super.onAddToDatabase(context, values);
         values.put(LauncherSettings.Favorites.TITLE, title.toString());
+        values.put(LauncherSettings.Favorites.OPTIONS, options);
+
     }
 
     void addListener(FolderListener listener) {
@@ -121,4 +142,25 @@
                 + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
                 + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos) + ")";
     }
+
+    public boolean hasOption(int optionFlag) {
+        return (options & optionFlag) != 0;
+    }
+
+    /**
+     * @param option flag to set or clear
+     * @param isEnabled whether to set or clear the flag
+     * @param context if not null, save changes to the db.
+     */
+    public void setOption(int option, boolean isEnabled, Context context) {
+        int oldOptions = options;
+        if (isEnabled) {
+            options |= option;
+        } else {
+            options &= ~option;
+        }
+        if (context != null && oldOptions != options) {
+            LauncherModel.updateItemInDatabase(context, this);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
new file mode 100644
index 0000000..f2ec1b6
--- /dev/null
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -0,0 +1,678 @@
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
+
+import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
+import com.android.launcher3.PageIndicator.PageMarkerResources;
+import com.android.launcher3.Workspace.ItemOperator;
+import com.android.launcher3.util.Thunk;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class FolderPagedView extends PagedView {
+
+    private static final String TAG = "FolderPagedView";
+
+    private static final boolean ALLOW_FOLDER_SCROLL = true;
+
+    private static final int REORDER_ANIMATION_DURATION = 230;
+    private static final int START_VIEW_REORDER_DELAY = 30;
+    private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
+
+    private static final int PAGE_INDICATOR_ANIMATION_START_DELAY = 300;
+    private static final int PAGE_INDICATOR_ANIMATION_STAGGERED_DELAY = 150;
+    private static final int PAGE_INDICATOR_ANIMATION_DURATION = 400;
+
+    // This value approximately overshoots to 1.5 times the original size.
+    private static final float PAGE_INDICATOR_OVERSHOOT_TENSION = 4.9f;
+
+    /**
+     * Fraction of the width to scroll when showing the next page hint.
+     */
+    private static final float SCROLL_HINT_FRACTION = 0.07f;
+
+    private static final int[] sTempPosArray = new int[2];
+
+    public final boolean mIsRtl;
+
+    private final LayoutInflater mInflater;
+    private final IconCache mIconCache;
+
+    @Thunk final HashMap<View, Runnable> mPendingAnimations = new HashMap<>();
+
+    private final int mMaxCountX;
+    private final int mMaxCountY;
+    private final int mMaxItemsPerPage;
+
+    private int mAllocatedContentSize;
+    private int mGridCountX;
+    private int mGridCountY;
+
+    private Folder mFolder;
+    private FocusIndicatorView mFocusIndicatorView;
+    private PagedFolderKeyEventListener mKeyListener;
+
+    private PageIndicator mPageIndicator;
+
+    public FolderPagedView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        LauncherAppState app = LauncherAppState.getInstance();
+
+        InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+        mMaxCountX = profile.numFolderColumns;
+        mMaxCountY = profile.numFolderRows;
+
+        mMaxItemsPerPage = mMaxCountX * mMaxCountY;
+
+        mInflater = LayoutInflater.from(context);
+        mIconCache = app.getIconCache();
+
+        mIsRtl = Utilities.isRtl(getResources());
+        setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        setEdgeGlowColor(getResources().getColor(R.color.folder_edge_effect_color));
+    }
+
+    public void setFolder(Folder folder) {
+        mFolder = folder;
+        mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
+        mKeyListener = new PagedFolderKeyEventListener(folder);
+        mPageIndicator = (PageIndicator) folder.findViewById(R.id.folder_page_indicator);
+    }
+
+    /**
+     * Sets up the grid size such that {@param count} items can fit in the grid.
+     * The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
+     * maintaining the restrictions of {@link #mMaxCountX} &amp; {@link #mMaxCountY}.
+     */
+    private void setupContentDimensions(int count) {
+        mAllocatedContentSize = count;
+        boolean done;
+        if (count >= mMaxItemsPerPage) {
+            mGridCountX = mMaxCountX;
+            mGridCountY = mMaxCountY;
+            done = true;
+        } else {
+            done = false;
+        }
+
+        while (!done) {
+            int oldCountX = mGridCountX;
+            int oldCountY = mGridCountY;
+            if (mGridCountX * mGridCountY < count) {
+                // Current grid is too small, expand it
+                if ((mGridCountX <= mGridCountY || mGridCountY == mMaxCountY) && mGridCountX < mMaxCountX) {
+                    mGridCountX++;
+                } else if (mGridCountY < mMaxCountY) {
+                    mGridCountY++;
+                }
+                if (mGridCountY == 0) mGridCountY++;
+            } else if ((mGridCountY - 1) * mGridCountX >= count && mGridCountY >= mGridCountX) {
+                mGridCountY = Math.max(0, mGridCountY - 1);
+            } else if ((mGridCountX - 1) * mGridCountY >= count) {
+                mGridCountX = Math.max(0, mGridCountX - 1);
+            }
+            done = mGridCountX == oldCountX && mGridCountY == oldCountY;
+        }
+
+        // Update grid size
+        for (int i = getPageCount() - 1; i >= 0; i--) {
+            getPageAt(i).setGridSize(mGridCountX, mGridCountY);
+        }
+    }
+
+    /**
+     * Binds items to the layout.
+     * @return list of items that could not be bound, probably because we hit the max size limit.
+     */
+    public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
+        ArrayList<View> icons = new ArrayList<View>();
+        ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
+
+        for (ShortcutInfo item : items) {
+            if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
+                extra.add(item);
+            } else {
+                icons.add(createNewView(item));
+            }
+        }
+        arrangeChildren(icons, icons.size(), false);
+        return extra;
+    }
+
+    /**
+     * Create space for a new item at the end, and returns the rank for that item.
+     * Also sets the current page to the last page.
+     */
+    public int allocateRankForNewItem(ShortcutInfo info) {
+        int rank = getItemCount();
+        ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
+        views.add(rank, null);
+        arrangeChildren(views, views.size(), false);
+        setCurrentPage(rank / mMaxItemsPerPage);
+        return rank;
+    }
+
+    public View createAndAddViewForRank(ShortcutInfo item, int rank) {
+        View icon = createNewView(item);
+        addViewForRank(icon, item, rank);
+        return icon;
+    }
+
+    /**
+     * Adds the {@param view} to the layout based on {@param rank} and updated the position
+     * related attributes. It assumes that {@param item} is already attached to the view.
+     */
+    public void addViewForRank(View view, ShortcutInfo item, int rank) {
+        int pagePos = rank % mMaxItemsPerPage;
+        int pageNo = rank / mMaxItemsPerPage;
+
+        item.rank = rank;
+        item.cellX = pagePos % mGridCountX;
+        item.cellY = pagePos / mGridCountX;
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+        lp.cellX = item.cellX;
+        lp.cellY = item.cellY;
+        getPageAt(pageNo).addViewToCellLayout(
+                view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
+    }
+
+    @SuppressLint("InflateParams")
+    public View createNewView(ShortcutInfo item) {
+        final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
+                R.layout.folder_application, null, false);
+        textView.applyFromShortcutInfo(item, mIconCache);
+        textView.setOnClickListener(mFolder);
+        textView.setOnLongClickListener(mFolder);
+        textView.setOnFocusChangeListener(mFocusIndicatorView);
+        textView.setOnKeyListener(mKeyListener);
+
+        textView.setLayoutParams(new CellLayout.LayoutParams(
+                item.cellX, item.cellY, item.spanX, item.spanY));
+        return textView;
+    }
+
+    @Override
+    public CellLayout getPageAt(int index) {
+        return (CellLayout) getChildAt(index);
+    }
+
+    public void removeCellLayoutView(View view) {
+        for (int i = getChildCount() - 1; i >= 0; i --) {
+            getPageAt(i).removeView(view);
+        }
+    }
+
+    public CellLayout getCurrentCellLayout() {
+        return getPageAt(getNextPage());
+    }
+
+    private CellLayout createAndAddNewPage() {
+        DeviceProfile grid = ((Launcher) getContext()).getDeviceProfile();
+        CellLayout page = new CellLayout(getContext());
+        page.setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
+        page.getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
+        page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+        page.setInvertIfRtl(true);
+        page.setGridSize(mGridCountX, mGridCountY);
+
+        addView(page, -1, generateDefaultLayoutParams());
+        return page;
+    }
+
+    @Override
+    protected int getChildGap() {
+        return getPaddingLeft() + getPaddingRight();
+    }
+
+    public void setFixedSize(int width, int height) {
+        width -= (getPaddingLeft() + getPaddingRight());
+        height -= (getPaddingTop() + getPaddingBottom());
+        for (int i = getChildCount() - 1; i >= 0; i --) {
+            ((CellLayout) getChildAt(i)).setFixedSize(width, height);
+        }
+    }
+
+    public void removeItem(View v) {
+        for (int i = getChildCount() - 1; i >= 0; i --) {
+            getPageAt(i).removeView(v);
+        }
+    }
+
+    /**
+     * Updates position and rank of all the children in the view.
+     * It essentially removes all views from all the pages and then adds them again in appropriate
+     * page.
+     *
+     * @param list the ordered list of children.
+     * @param itemCount if greater than the total children count, empty spaces are left
+     * at the end, otherwise it is ignored.
+     *
+     */
+    public void arrangeChildren(ArrayList<View> list, int itemCount) {
+        arrangeChildren(list, itemCount, true);
+    }
+
+    @SuppressLint("RtlHardcoded")
+    private void arrangeChildren(ArrayList<View> list, int itemCount, boolean saveChanges) {
+        ArrayList<CellLayout> pages = new ArrayList<CellLayout>();
+        for (int i = 0; i < getChildCount(); i++) {
+            CellLayout page = (CellLayout) getChildAt(i);
+            page.removeAllViews();
+            pages.add(page);
+        }
+        setupContentDimensions(itemCount);
+
+        Iterator<CellLayout> pageItr = pages.iterator();
+        CellLayout currentPage = null;
+
+        int position = 0;
+        int newX, newY, rank;
+
+        rank = 0;
+        for (int i = 0; i < itemCount; i++) {
+            View v = list.size() > i ? list.get(i) : null;
+            if (currentPage == null || position >= mMaxItemsPerPage) {
+                // Next page
+                if (pageItr.hasNext()) {
+                    currentPage = pageItr.next();
+                } else {
+                    currentPage = createAndAddNewPage();
+                }
+                position = 0;
+            }
+
+            if (v != null) {
+                CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
+                newX = position % mGridCountX;
+                newY = position / mGridCountX;
+                ItemInfo info = (ItemInfo) v.getTag();
+                if (info.cellX != newX || info.cellY != newY || info.rank != rank) {
+                    info.cellX = newX;
+                    info.cellY = newY;
+                    info.rank = rank;
+                    if (saveChanges) {
+                        LauncherModel.addOrMoveItemInDatabase(getContext(), info,
+                                mFolder.mInfo.id, 0, info.cellX, info.cellY);
+                    }
+                }
+                lp.cellX = info.cellX;
+                lp.cellY = info.cellY;
+                currentPage.addViewToCellLayout(
+                        v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
+            }
+
+            rank ++;
+            position++;
+        }
+
+        // Remove extra views.
+        boolean removed = false;
+        while (pageItr.hasNext()) {
+            removeView(pageItr.next());
+            removed = true;
+        }
+        if (removed) {
+            setCurrentPage(0);
+        }
+
+        setEnableOverscroll(getPageCount() > 1);
+
+        // Update footer
+        mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+        // Set the gravity as LEFT or RIGHT instead of START, as START depends on the actual text.
+        mFolder.mFolderName.setGravity(getPageCount() > 1 ?
+                (mIsRtl ? Gravity.RIGHT : Gravity.LEFT) : Gravity.CENTER_HORIZONTAL);
+    }
+
+    public int getDesiredWidth() {
+        return getPageCount() > 0 ?
+                (getPageAt(0).getDesiredWidth() + getPaddingLeft() + getPaddingRight()) : 0;
+    }
+
+    public int getDesiredHeight()  {
+        return  getPageCount() > 0 ?
+                (getPageAt(0).getDesiredHeight() + getPaddingTop() + getPaddingBottom()) : 0;
+    }
+
+    public int getItemCount() {
+        int lastPageIndex = getChildCount() - 1;
+        if (lastPageIndex < 0) {
+            // If there are no pages, nothing has yet been added to the folder.
+            return 0;
+        }
+        return getPageAt(lastPageIndex).getShortcutsAndWidgets().getChildCount()
+                + lastPageIndex * mMaxItemsPerPage;
+    }
+
+    /**
+     * @return the rank of the cell nearest to the provided pixel position.
+     */
+    public int findNearestArea(int pixelX, int pixelY) {
+        int pageIndex = getNextPage();
+        CellLayout page = getPageAt(pageIndex);
+        page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
+        if (mFolder.isLayoutRtl()) {
+            sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
+        }
+        return Math.min(mAllocatedContentSize - 1,
+                pageIndex * mMaxItemsPerPage + sTempPosArray[1] * mGridCountX + sTempPosArray[0]);
+    }
+
+    @Override
+    protected PageMarkerResources getPageIndicatorMarker(int pageIndex) {
+        return new PageMarkerResources(R.drawable.ic_pageindicator_current_folder,
+                R.drawable.ic_pageindicator_default_folder);
+    }
+
+    public boolean isFull() {
+        return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
+    }
+
+    public View getLastItem() {
+        if (getChildCount() < 1) {
+            return null;
+        }
+        ShortcutAndWidgetContainer lastContainer = getCurrentCellLayout().getShortcutsAndWidgets();
+        int lastRank = lastContainer.getChildCount() - 1;
+        if (mGridCountX > 0) {
+            return lastContainer.getChildAt(lastRank % mGridCountX, lastRank / mGridCountX);
+        } else {
+            return lastContainer.getChildAt(lastRank);
+        }
+    }
+
+    /**
+     * Iterates over all its items in a reading order.
+     * @return the view for which the operator returned true.
+     */
+    public View iterateOverItems(ItemOperator op) {
+        for (int k = 0 ; k < getChildCount(); k++) {
+            CellLayout page = getPageAt(k);
+            for (int j = 0; j < page.getCountY(); j++) {
+                for (int i = 0; i < page.getCountX(); i++) {
+                    View v = page.getChildAt(i, j);
+                    if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v, this)) {
+                        return v;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public String getAccessibilityDescription() {
+        return String.format(getContext().getString(R.string.folder_opened),
+                mGridCountX, mGridCountY);
+    }
+
+    /**
+     * Sets the focus on the first visible child.
+     */
+    public void setFocusOnFirstChild() {
+        View firstChild = getCurrentCellLayout().getChildAt(0, 0);
+        if (firstChild != null) {
+            firstChild.requestFocus();
+        }
+    }
+
+    @Override
+    protected void notifyPageSwitchListener() {
+        super.notifyPageSwitchListener();
+        if (mFolder != null) {
+            mFolder.updateTextViewFocus();
+        }
+    }
+
+    /**
+     * Scrolls the current view by a fraction
+     */
+    public void showScrollHint(int direction) {
+        float fraction = (direction == DragController.SCROLL_LEFT) ^ mIsRtl
+                ? -SCROLL_HINT_FRACTION : SCROLL_HINT_FRACTION;
+        int hint = (int) (fraction * getWidth());
+        int scroll = getScrollForPage(getNextPage()) + hint;
+        int delta = scroll - getScrollX();
+        if (delta != 0) {
+            mScroller.setInterpolator(new DecelerateInterpolator());
+            mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION);
+            invalidate();
+        }
+    }
+
+    public void clearScrollHint() {
+        if (getScrollX() != getScrollForPage(getNextPage())) {
+            snapToPage(getNextPage());
+        }
+    }
+
+    /**
+     * Finish animation all the views which are animating across pages
+     */
+    public void completePendingPageChanges() {
+        if (!mPendingAnimations.isEmpty()) {
+            HashMap<View, Runnable> pendingViews = new HashMap<>(mPendingAnimations);
+            for (Map.Entry<View, Runnable> e : pendingViews.entrySet()) {
+                e.getKey().animate().cancel();
+                e.getValue().run();
+            }
+        }
+    }
+
+    public boolean rankOnCurrentPage(int rank) {
+        int p = rank / mMaxItemsPerPage;
+        return p == getNextPage();
+    }
+
+    @Override
+    protected void onPageBeginMoving() {
+        super.onPageBeginMoving();
+        getVisiblePages(sTempPosArray);
+        for (int i = sTempPosArray[0]; i <= sTempPosArray[1]; i++) {
+            verifyVisibleHighResIcons(i);
+        }
+    }
+
+    /**
+     * Ensures that all the icons on the given page are of high-res
+     */
+    public void verifyVisibleHighResIcons(int pageNo) {
+        CellLayout page = getPageAt(pageNo);
+        if (page != null) {
+            ShortcutAndWidgetContainer parent = page.getShortcutsAndWidgets();
+            for (int i = parent.getChildCount() - 1; i >= 0; i--) {
+                ((BubbleTextView) parent.getChildAt(i)).verifyHighRes();
+            }
+        }
+    }
+
+    public int getAllocatedContentSize() {
+        return mAllocatedContentSize;
+    }
+
+    /**
+     * Reorders the items such that the {@param empty} spot moves to {@param target}
+     */
+    public void realTimeReorder(int empty, int target) {
+        completePendingPageChanges();
+        int delay = 0;
+        float delayAmount = START_VIEW_REORDER_DELAY;
+
+        // Animation only happens on the current page.
+        int pageToAnimate = getNextPage();
+
+        int pageT = target / mMaxItemsPerPage;
+        int pagePosT = target % mMaxItemsPerPage;
+
+        if (pageT != pageToAnimate) {
+            Log.e(TAG, "Cannot animate when the target cell is invisible");
+        }
+        int pagePosE = empty % mMaxItemsPerPage;
+        int pageE = empty / mMaxItemsPerPage;
+
+        int startPos, endPos;
+        int moveStart, moveEnd;
+        int direction;
+
+        if (target == empty) {
+            // No animation
+            return;
+        } else if (target > empty) {
+            // Items will move backwards to make room for the empty cell.
+            direction = 1;
+
+            // If empty cell is in a different page, move them instantly.
+            if (pageE < pageToAnimate) {
+                moveStart = empty;
+                // Instantly move the first item in the current page.
+                moveEnd = pageToAnimate * mMaxItemsPerPage;
+                // Animate the 2nd item in the current page, as the first item was already moved to
+                // the last page.
+                startPos = 0;
+            } else {
+                moveStart = moveEnd = -1;
+                startPos = pagePosE;
+            }
+
+            endPos = pagePosT;
+        } else {
+            // The items will move forward.
+            direction = -1;
+
+            if (pageE > pageToAnimate) {
+                // Move the items immediately.
+                moveStart = empty;
+                // Instantly move the last item in the current page.
+                moveEnd = (pageToAnimate + 1) * mMaxItemsPerPage - 1;
+
+                // Animations start with the second last item in the page
+                startPos = mMaxItemsPerPage - 1;
+            } else {
+                moveStart = moveEnd = -1;
+                startPos = pagePosE;
+            }
+
+            endPos = pagePosT;
+        }
+
+        // Instant moving views.
+        while (moveStart != moveEnd) {
+            int rankToMove = moveStart + direction;
+            int p = rankToMove / mMaxItemsPerPage;
+            int pagePos = rankToMove % mMaxItemsPerPage;
+            int x = pagePos % mGridCountX;
+            int y = pagePos / mGridCountX;
+
+            final CellLayout page = getPageAt(p);
+            final View v = page.getChildAt(x, y);
+            if (v != null) {
+                if (pageToAnimate != p) {
+                    page.removeView(v);
+                    addViewForRank(v, (ShortcutInfo) v.getTag(), moveStart);
+                } else {
+                    // Do a fake animation before removing it.
+                    final int newRank = moveStart;
+                    final float oldTranslateX = v.getTranslationX();
+
+                    Runnable endAction = new Runnable() {
+
+                        @Override
+                        public void run() {
+                            mPendingAnimations.remove(v);
+                            v.setTranslationX(oldTranslateX);
+                            ((CellLayout) v.getParent().getParent()).removeView(v);
+                            addViewForRank(v, (ShortcutInfo) v.getTag(), newRank);
+                        }
+                    };
+                    v.animate()
+                        .translationXBy((direction > 0 ^ mIsRtl) ? -v.getWidth() : v.getWidth())
+                        .setDuration(REORDER_ANIMATION_DURATION)
+                        .setStartDelay(0)
+                        .withEndAction(endAction);
+                    mPendingAnimations.put(v, endAction);
+                }
+            }
+            moveStart = rankToMove;
+        }
+
+        if ((endPos - startPos) * direction <= 0) {
+            // No animation
+            return;
+        }
+
+        CellLayout page = getPageAt(pageToAnimate);
+        for (int i = startPos; i != endPos; i += direction) {
+            int nextPos = i + direction;
+            View v = page.getChildAt(nextPos % mGridCountX, nextPos / mGridCountX);
+            if (v != null) {
+                ((ItemInfo) v.getTag()).rank -= direction;
+            }
+            if (page.animateChildToPosition(v, i % mGridCountX, i / mGridCountX,
+                    REORDER_ANIMATION_DURATION, delay, true, true)) {
+                delay += delayAmount;
+                delayAmount *= VIEW_REORDER_DELAY_FACTOR;
+            }
+        }
+    }
+
+    public void setMarkerScale(float scale) {
+        int count  = mPageIndicator.getChildCount();
+        for (int i = 0; i < count; i++) {
+            View marker = mPageIndicator.getChildAt(i);
+            marker.animate().cancel();
+            marker.setScaleX(scale);
+            marker.setScaleY(scale);
+        }
+    }
+
+    public void animateMarkers() {
+        int count  = mPageIndicator.getChildCount();
+        Interpolator interpolator = new OvershootInterpolator(PAGE_INDICATOR_OVERSHOOT_TENSION);
+        for (int i = 0; i < count; i++) {
+            mPageIndicator.getChildAt(i).animate().scaleX(1).scaleY(1)
+                .setInterpolator(interpolator)
+                .setDuration(PAGE_INDICATOR_ANIMATION_DURATION)
+                .setStartDelay(PAGE_INDICATOR_ANIMATION_STAGGERED_DELAY * i
+                        + PAGE_INDICATOR_ANIMATION_START_DELAY);
+        }
+    }
+
+    public int itemsPerPage() {
+        return mMaxItemsPerPage;
+    }
+
+    @Override
+    protected void getEdgeVerticalPostion(int[] pos) {
+        pos[0] = 0;
+        pos[1] = getViewportHeight();
+    }
+}
diff --git a/src/com/android/launcher3/HolographicOutlineHelper.java b/src/com/android/launcher3/HolographicOutlineHelper.java
index b1e0e68..5ff85d6 100644
--- a/src/com/android/launcher3/HolographicOutlineHelper.java
+++ b/src/com/android/launcher3/HolographicOutlineHelper.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BlurMaskFilter;
 import android.graphics.Canvas;
@@ -25,11 +26,16 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
-import android.graphics.Region.Op;
+import android.graphics.drawable.Drawable;
+import android.util.SparseArray;
 
+/**
+ * Utility class to generate shadow and outline effect, which are used for click feedback
+ * and drag-n-drop respectively.
+ */
 public class HolographicOutlineHelper {
 
-    private static final Rect sTempRect = new Rect();
+    private static HolographicOutlineHelper sInstance;
 
     private final Canvas mCanvas = new Canvas();
     private final Paint mDrawPaint = new Paint();
@@ -40,26 +46,23 @@
     private final BlurMaskFilter mThinOuterBlurMaskFilter;
     private final BlurMaskFilter mMediumInnerBlurMaskFilter;
 
-    private final BlurMaskFilter mShaowBlurMaskFilter;
-    private final int mShadowOffset;
+    private final BlurMaskFilter mShadowBlurMaskFilter;
 
-    /**
-     * Padding used when creating shadow bitmap;
-     */
-    final int shadowBitmapPadding;
-
-    static HolographicOutlineHelper INSTANCE;
+    // We have 4 different icon sizes: homescreen, hotseat, folder & all-apps
+    private final SparseArray<Bitmap> mBitmapCache = new SparseArray<>(4);
 
     private HolographicOutlineHelper(Context context) {
-        final float scale = LauncherAppState.getInstance().getScreenDensity();
+        Resources res = context.getResources();
 
-        mMediumOuterBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.OUTER);
-        mThinOuterBlurMaskFilter = new BlurMaskFilter(scale * 1.0f, BlurMaskFilter.Blur.OUTER);
-        mMediumInnerBlurMaskFilter = new BlurMaskFilter(scale * 2.0f, BlurMaskFilter.Blur.NORMAL);
+        float mediumBlur = res.getDimension(R.dimen.blur_size_medium_outline);
+        mMediumOuterBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.OUTER);
+        mMediumInnerBlurMaskFilter = new BlurMaskFilter(mediumBlur, BlurMaskFilter.Blur.NORMAL);
 
-        mShaowBlurMaskFilter = new BlurMaskFilter(scale * 4.0f, BlurMaskFilter.Blur.NORMAL);
-        mShadowOffset = (int) (scale * 2.0f);
-        shadowBitmapPadding = (int) (scale * 4.0f);
+        mThinOuterBlurMaskFilter = new BlurMaskFilter(
+                res.getDimension(R.dimen.blur_size_thin_outline), BlurMaskFilter.Blur.OUTER);
+
+        mShadowBlurMaskFilter = new BlurMaskFilter(
+                res.getDimension(R.dimen.blur_size_click_shadow), BlurMaskFilter.Blur.NORMAL);
 
         mDrawPaint.setFilterBitmap(true);
         mDrawPaint.setAntiAlias(true);
@@ -71,10 +74,10 @@
     }
 
     public static HolographicOutlineHelper obtain(Context context) {
-        if (INSTANCE == null) {
-            INSTANCE = new HolographicOutlineHelper(context);
+        if (sInstance == null) {
+            sInstance = new HolographicOutlineHelper(context);
         }
-        return INSTANCE;
+        return sInstance;
     }
 
     /**
@@ -153,51 +156,34 @@
     }
 
     Bitmap createMediumDropShadow(BubbleTextView view) {
-        final Bitmap result = Bitmap.createBitmap(
-                view.getWidth() + shadowBitmapPadding + shadowBitmapPadding,
-                view.getHeight() + shadowBitmapPadding + shadowBitmapPadding + mShadowOffset,
-                Bitmap.Config.ARGB_8888);
+        Drawable icon = view.getIcon();
+        if (icon == null) {
+            return null;
+        }
+        Rect rect = icon.getBounds();
 
-        mCanvas.setBitmap(result);
+        int bitmapWidth = (int) (rect.width() * view.getScaleX());
+        int bitmapHeight = (int) (rect.height() * view.getScaleY());
 
-        final Rect clipRect = sTempRect;
-        view.getDrawingRect(sTempRect);
-        // adjust the clip rect so that we don't include the text label
-        clipRect.bottom = view.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V
-                + view.getLayout().getLineTop(0);
+        int key = (bitmapWidth << 16) | bitmapHeight;
+        Bitmap cache = mBitmapCache.get(key);
+        if (cache == null) {
+            cache = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+            mCanvas.setBitmap(cache);
+            mBitmapCache.put(key, cache);
+        } else {
+            mCanvas.setBitmap(cache);
+            mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
+        }
 
-        // Draw the View into the bitmap.
-        // The translate of scrollX and scrollY is necessary when drawing TextViews, because
-        // they set scrollX and scrollY to large values to achieve centered text
-        mCanvas.save();
-        mCanvas.scale(view.getScaleX(), view.getScaleY(),
-                view.getWidth() / 2 + shadowBitmapPadding,
-                view.getHeight() / 2 + shadowBitmapPadding);
-        mCanvas.translate(-view.getScrollX() + shadowBitmapPadding,
-                -view.getScrollY() + shadowBitmapPadding);
-        mCanvas.clipRect(clipRect, Op.REPLACE);
-        view.draw(mCanvas);
+        mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+        mCanvas.scale(view.getScaleX(), view.getScaleY());
+        mCanvas.translate(-rect.left, -rect.top);
+        icon.draw(mCanvas);
         mCanvas.restore();
-
-        int[] blurOffst = new int[2];
-        mBlurPaint.setMaskFilter(mShaowBlurMaskFilter);
-        Bitmap blurBitmap = result.extractAlpha(mBlurPaint, blurOffst);
-
-        mCanvas.save();
-        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
-        mCanvas.translate(blurOffst[0], blurOffst[1]);
-
-        mDrawPaint.setColor(Color.BLACK);
-        mDrawPaint.setAlpha(30);
-        mCanvas.drawBitmap(blurBitmap, 0, 0, mDrawPaint);
-
-        mDrawPaint.setAlpha(60);
-        mCanvas.drawBitmap(blurBitmap, 0, mShadowOffset, mDrawPaint);
-        mCanvas.restore();
-
         mCanvas.setBitmap(null);
-        blurBitmap.recycle();
 
-        return result;
+        mBlurPaint.setMaskFilter(mShadowBlurMaskFilter);
+        return cache.extractAlpha(mBlurPaint, null);
     }
 }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b08272f..17fdeb1 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,24 +16,19 @@
 
 package com.android.launcher3;
 
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-
-public class Hotseat extends FrameLayout {
-    private static final String TAG = "Hotseat";
+public class Hotseat extends FrameLayout
+        implements Stats.LaunchSourceProvider{
 
     private CellLayout mContent;
 
@@ -41,8 +36,7 @@
 
     private int mAllAppsButtonRank;
 
-    private boolean mTransposeLayoutWithOrientation;
-    private boolean mIsLandscape;
+    private final boolean mHasVerticalHotseat;
 
     public Hotseat(Context context) {
         this(context, null);
@@ -54,16 +48,8 @@
 
     public Hotseat(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
-        Resources r = context.getResources();
-        mTransposeLayoutWithOrientation = 
-                r.getBoolean(R.bool.hotseat_transpose_layout_with_orientation);
-        mIsLandscape = context.getResources().getConfiguration().orientation ==
-            Configuration.ORIENTATION_LANDSCAPE;
-    }
-
-    public void setup(Launcher launcher) {
-        mLauncher = launcher;
+        mLauncher = (Launcher) context;
+        mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
     }
 
     CellLayout getLayout() {
@@ -71,6 +57,13 @@
     }
 
     /**
+     * Returns whether there are other icons than the all apps button in the hotseat.
+     */
+    public boolean hasIcons() {
+        return mContent.getShortcutsAndWidgets().getChildCount() > 1;
+    }
+
+    /**
      * Registers the specified listener on the cell layout of the hotseat.
      */
     @Override
@@ -78,60 +71,35 @@
         mContent.setOnLongClickListener(l);
     }
   
-    private boolean hasVerticalHotseat() {
-        return (mIsLandscape && mTransposeLayoutWithOrientation);
-    }
-
     /* Get the orientation invariant order of the item in the hotseat for persistence. */
     int getOrderInHotseat(int x, int y) {
-        return hasVerticalHotseat() ? (mContent.getCountY() - y - 1) : x;
+        return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x;
     }
+
     /* Get the orientation specific coordinates given an invariant order in the hotseat. */
     int getCellXFromOrder(int rank) {
-        return hasVerticalHotseat() ? 0 : rank;
+        return mHasVerticalHotseat ? 0 : rank;
     }
+
     int getCellYFromOrder(int rank) {
-        return hasVerticalHotseat() ? (mContent.getCountY() - (rank + 1)) : 0;
+        return mHasVerticalHotseat ? (mContent.getCountY() - (rank + 1)) : 0;
     }
+
     public boolean isAllAppsButtonRank(int rank) {
-        if (LauncherAppState.isDisableAllApps()) {
-            return false;
-        } else {
-            return rank == mAllAppsButtonRank;
-        }
-    }
-
-    /** This returns the coordinates of an app in a given cell, relative to the DragLayer */
-    Rect getCellCoordinates(int cellX, int cellY) {
-        Rect coords = new Rect();
-        mContent.cellToRect(cellX, cellY, 1, 1, coords);
-        int[] hotseatInParent = new int[2];
-        Utilities.getDescendantCoordRelativeToParent(this, mLauncher.getDragLayer(),
-                hotseatInParent, false);
-        coords.offset(hotseatInParent[0], hotseatInParent[1]);
-
-        // Center the icon
-        int cWidth = mContent.getShortcutsAndWidgets().getCellContentWidth();
-        int cHeight = mContent.getShortcutsAndWidgets().getCellContentHeight();
-        int cellPaddingX = (int) Math.max(0, ((coords.width() - cWidth) / 2f));
-        int cellPaddingY = (int) Math.max(0, ((coords.height() - cHeight) / 2f));
-        coords.offset(cellPaddingX, cellPaddingY);
-
-        return coords;
+        return rank == mAllAppsButtonRank;
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
 
-        mAllAppsButtonRank = grid.hotseatAllAppsRank;
+        mAllAppsButtonRank = grid.inv.hotseatAllAppsRank;
         mContent = (CellLayout) findViewById(R.id.layout);
-        if (grid.isLandscape && !grid.isLargeTablet()) {
-            mContent.setGridSize(1, (int) grid.numHotseatIcons);
+        if (grid.isLandscape && !grid.isLargeTablet) {
+            mContent.setGridSize(1, (int) grid.inv.numHotseatIcons);
         } else {
-            mContent.setGridSize((int) grid.numHotseatIcons, 1);
+            mContent.setGridSize((int) grid.inv.numHotseatIcons, 1);
         }
         mContent.setIsHotseat(true);
 
@@ -141,35 +109,34 @@
     void resetLayout() {
         mContent.removeAllViewsInLayout();
 
-        if (!LauncherAppState.isDisableAllApps()) {
-            // Add the Apps button
-            Context context = getContext();
+        // Add the Apps button
+        Context context = getContext();
 
-            LayoutInflater inflater = LayoutInflater.from(context);
-            TextView allAppsButton = (TextView)
-                    inflater.inflate(R.layout.all_apps_button, mContent, false);
-            Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
+        LayoutInflater inflater = LayoutInflater.from(context);
+        TextView allAppsButton = (TextView)
+                inflater.inflate(R.layout.all_apps_button, mContent, false);
+        Drawable d = context.getResources().getDrawable(R.drawable.all_apps_button_icon);
 
-            Utilities.resizeIconDrawable(d);
-            allAppsButton.setCompoundDrawables(null, d, null, null);
+        mLauncher.resizeIconDrawable(d);
+        allAppsButton.setCompoundDrawables(null, d, null, null);
 
-            allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
-            allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
-            if (mLauncher != null) {
-                allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
-                mLauncher.setAllAppsButton(allAppsButton);
-                allAppsButton.setOnClickListener(mLauncher);
-                allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
-            }
-
-            // Note: We do this to ensure that the hotseat is always laid out in the orientation of
-            // the hotseat in order regardless of which orientation they were added
-            int x = getCellXFromOrder(mAllAppsButtonRank);
-            int y = getCellYFromOrder(mAllAppsButtonRank);
-            CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
-            lp.canReorder = false;
-            mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
+        allAppsButton.setContentDescription(context.getString(R.string.all_apps_button_label));
+        allAppsButton.setOnKeyListener(new HotseatIconKeyEventListener());
+        if (mLauncher != null) {
+            mLauncher.setAllAppsButton(allAppsButton);
+            allAppsButton.setOnTouchListener(mLauncher.getHapticFeedbackTouchListener());
+            allAppsButton.setOnClickListener(mLauncher);
+            allAppsButton.setOnLongClickListener(mLauncher);
+            allAppsButton.setOnFocusChangeListener(mLauncher.mFocusHandler);
         }
+
+        // Note: We do this to ensure that the hotseat is always laid out in the orientation of
+        // the hotseat in order regardless of which orientation they were added
+        int x = getCellXFromOrder(mAllAppsButtonRank);
+        int y = getCellYFromOrder(mAllAppsButtonRank);
+        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(x,y,1,1);
+        lp.canReorder = false;
+        mContent.addViewToCellLayout(allAppsButton, -1, allAppsButton.getId(), lp, true);
     }
 
     @Override
@@ -182,54 +149,8 @@
         return false;
     }
 
-    void addAllAppsFolder(IconCache iconCache,
-            ArrayList<AppInfo> allApps, ArrayList<ComponentName> onWorkspace,
-            Launcher launcher, Workspace workspace) {
-        if (LauncherAppState.isDisableAllApps()) {
-            FolderInfo fi = new FolderInfo();
-
-            fi.cellX = getCellXFromOrder(mAllAppsButtonRank);
-            fi.cellY = getCellYFromOrder(mAllAppsButtonRank);
-            fi.spanX = 1;
-            fi.spanY = 1;
-            fi.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
-            fi.screenId = mAllAppsButtonRank;
-            fi.itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-            fi.title = "More Apps";
-            LauncherModel.addItemToDatabase(launcher, fi, fi.container, fi.screenId, fi.cellX,
-                    fi.cellY, false);
-            FolderIcon folder = FolderIcon.fromXml(R.layout.folder_icon, launcher,
-                    getLayout(), fi, iconCache);
-            workspace.addInScreen(folder, fi.container, fi.screenId, fi.cellX, fi.cellY,
-                    fi.spanX, fi.spanY);
-
-            for (AppInfo info: allApps) {
-                ComponentName cn = info.intent.getComponent();
-                if (!onWorkspace.contains(cn)) {
-                    Log.d(TAG, "Adding to 'more apps': " + info.intent);
-                    ShortcutInfo si = info.makeShortcut();
-                    fi.add(si);
-                }
-            }
-        }
-    }
-
-    void addAppsToAllAppsFolder(ArrayList<AppInfo> apps) {
-        if (LauncherAppState.isDisableAllApps()) {
-            View v = mContent.getChildAt(getCellXFromOrder(mAllAppsButtonRank), getCellYFromOrder(mAllAppsButtonRank));
-            FolderIcon fi = null;
-
-            if (v instanceof FolderIcon) {
-                fi = (FolderIcon) v;
-            } else {
-                return;
-            }
-
-            FolderInfo info = fi.getFolderInfo();
-            for (AppInfo a: apps) {
-                ShortcutInfo si = a.makeShortcut();
-                info.add(si);
-            }
-        }
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOTSEAT);
     }
 }
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 5a0875b..916418f 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -16,19 +16,28 @@
 
 package com.android.launcher3;
 
-import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -36,17 +45,17 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Thunk;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map.Entry;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.Stack;
 
 /**
  * Cache of application icons.  Icons can be made from any thread.
@@ -56,66 +65,71 @@
     private static final String TAG = "Launcher.IconCache";
 
     private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
-    private static final String RESOURCE_FILE_PREFIX = "icon_";
 
     // Empty class name is used for storing package default entry.
     private static final String EMPTY_CLASS_NAME = ".";
 
     private static final boolean DEBUG = false;
 
-    private static class CacheEntry {
+    private static final int LOW_RES_SCALE_FACTOR = 5;
+
+    @Thunk static final Object ICON_UPDATE_TOKEN = new Object();
+
+    @Thunk static class CacheEntry {
         public Bitmap icon;
-        public CharSequence title;
-        public CharSequence contentDescription;
+        public CharSequence title = "";
+        public CharSequence contentDescription = "";
+        public boolean isLowResIcon;
     }
 
-    private static class CacheKey {
-        public ComponentName componentName;
-        public UserHandleCompat user;
+    private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons = new HashMap<>();
+    @Thunk final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
 
-        CacheKey(ComponentName componentName, UserHandleCompat user) {
-            this.componentName = componentName;
-            this.user = user;
-        }
-
-        @Override
-        public int hashCode() {
-            return componentName.hashCode() + user.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            CacheKey other = (CacheKey) o;
-            return other.componentName.equals(componentName) && other.user.equals(user);
-        }
-    }
-
-    private final HashMap<UserHandleCompat, Bitmap> mDefaultIcons =
-            new HashMap<UserHandleCompat, Bitmap>();
     private final Context mContext;
     private final PackageManager mPackageManager;
-    private final UserManagerCompat mUserManager;
+    @Thunk final UserManagerCompat mUserManager;
     private final LauncherAppsCompat mLauncherApps;
-    private final HashMap<CacheKey, CacheEntry> mCache =
-            new HashMap<CacheKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
-    private int mIconDpi;
+    private final HashMap<ComponentKey, CacheEntry> mCache =
+            new HashMap<ComponentKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
+    private final int mIconDpi;
+    @Thunk final IconDB mIconDb;
 
-    public IconCache(Context context) {
-        ActivityManager activityManager =
-                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+    @Thunk final Handler mWorkerHandler;
 
+    // The background color used for activity icons. Since these icons are displayed in all-apps
+    // and folders, this would be same as the light quantum panel background. This color
+    // is used to convert icons to RGB_565.
+    private final int mActivityBgColor;
+    // The background color used for package icons. These are displayed in widget tray, which
+    // has a dark quantum panel background.
+    private final int mPackageBgColor;
+    private final BitmapFactory.Options mLowResOptions;
+
+    private String mSystemState;
+    private Bitmap mLowResBitmap;
+    private Canvas mLowResCanvas;
+    private Paint mLowResPaint;
+
+    public IconCache(Context context, InvariantDeviceProfile inv) {
         mContext = context;
         mPackageManager = context.getPackageManager();
         mUserManager = UserManagerCompat.getInstance(mContext);
         mLauncherApps = LauncherAppsCompat.getInstance(mContext);
-        mIconDpi = activityManager.getLauncherLargeIconDensity();
+        mIconDpi = inv.fillResIconDpi;
+        mIconDb = new IconDB(context);
 
-        // need to set mIconDpi before getting default icon
-        UserHandleCompat myUser = UserHandleCompat.myUserHandle();
-        mDefaultIcons.put(myUser, makeDefaultIcon(myUser));
+        mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
+
+        mActivityBgColor = context.getResources().getColor(R.color.quantum_panel_bg_color);
+        mPackageBgColor = context.getResources().getColor(R.color.quantum_panel_bg_color_dark);
+        mLowResOptions = new BitmapFactory.Options();
+        // Always prefer RGB_565 config for low res. If the bitmap has transparency, it will
+        // automatically be loaded as ALPHA_8888.
+        mLowResOptions.inPreferredConfig = Bitmap.Config.RGB_565;
+        updateSystemStateString();
     }
 
-    public Drawable getFullResDefaultActivityIcon() {
+    private Drawable getFullResDefaultActivityIcon() {
         return getFullResIcon(Resources.getSystem(), android.R.mipmap.sym_def_app_icon);
     }
 
@@ -145,10 +159,6 @@
         return getFullResDefaultActivityIcon();
     }
 
-    public int getFullResIconDpi() {
-        return mIconDpi;
-    }
-
     public Drawable getFullResIcon(ActivityInfo info) {
         Resources resources;
         try {
@@ -184,59 +194,269 @@
      * Remove any records for the supplied ComponentName.
      */
     public synchronized void remove(ComponentName componentName, UserHandleCompat user) {
-        mCache.remove(new CacheKey(componentName, user));
+        mCache.remove(new ComponentKey(componentName, user));
     }
 
     /**
-     * Remove any records for the supplied package name.
+     * Remove any records for the supplied package name from memory.
      */
-    public synchronized void remove(String packageName, UserHandleCompat user) {
-        HashSet<CacheKey> forDeletion = new HashSet<CacheKey>();
-        for (CacheKey key: mCache.keySet()) {
+    private void removeFromMemCacheLocked(String packageName, UserHandleCompat user) {
+        HashSet<ComponentKey> forDeletion = new HashSet<ComponentKey>();
+        for (ComponentKey key: mCache.keySet()) {
             if (key.componentName.getPackageName().equals(packageName)
                     && key.user.equals(user)) {
                 forDeletion.add(key);
             }
         }
-        for (CacheKey condemned: forDeletion) {
+        for (ComponentKey condemned: forDeletion) {
             mCache.remove(condemned);
         }
     }
 
     /**
-     * Empty out the cache.
+     * Updates the entries related to the given package in memory and persistent DB.
      */
-    public synchronized void flush() {
-        mCache.clear();
+    public synchronized void updateIconsForPkg(String packageName, UserHandleCompat user) {
+        removeIconsForPkg(packageName, user);
+        try {
+            PackageInfo info = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_UNINSTALLED_PACKAGES);
+            long userSerial = mUserManager.getSerialNumberForUser(user);
+            for (LauncherActivityInfoCompat app : mLauncherApps.getActivityList(packageName, user)) {
+                addIconToDBAndMemCache(app, info, userSerial);
+            }
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, "Package not found", e);
+            return;
+        }
     }
 
     /**
-     * Empty out the cache that aren't of the correct grid size
+     * Removes the entries related to the given package in memory and persistent DB.
      */
-    public synchronized void flushInvalidIcons(DeviceProfile grid) {
-        Iterator<Entry<CacheKey, CacheEntry>> it = mCache.entrySet().iterator();
-        while (it.hasNext()) {
-            final CacheEntry e = it.next().getValue();
-            if ((e.icon != null) && (e.icon.getWidth() < grid.iconSizePx
-                    || e.icon.getHeight() < grid.iconSizePx)) {
-                it.remove();
+    public synchronized void removeIconsForPkg(String packageName, UserHandleCompat user) {
+        removeFromMemCacheLocked(packageName, user);
+        long userSerial = mUserManager.getSerialNumberForUser(user);
+        mIconDb.getWritableDatabase().delete(IconDB.TABLE_NAME,
+                IconDB.COLUMN_COMPONENT + " LIKE ? AND " + IconDB.COLUMN_USER + " = ?",
+                new String[] {packageName + "/%", Long.toString(userSerial)});
+    }
+
+    public void updateDbIcons(Set<String> ignorePackagesForMainUser) {
+        // Remove all active icon update tasks.
+        mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
+
+        updateSystemStateString();
+        for (UserHandleCompat user : mUserManager.getUserProfiles()) {
+            // Query for the set of apps
+            final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+            // Fail if we don't have any apps
+            // TODO: Fix this. Only fail for the current user.
+            if (apps == null || apps.isEmpty()) {
+                return;
+            }
+
+            // Update icon cache. This happens in segments and {@link #onPackageIconsUpdated}
+            // is called by the icon cache when the job is complete.
+            updateDBIcons(user, apps, UserHandleCompat.myUserHandle().equals(user)
+                    ? ignorePackagesForMainUser : Collections.<String>emptySet());
+        }
+    }
+
+    /**
+     * Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
+     * the DB and are updated.
+     * @return The set of packages for which icons have updated.
+     */
+    private void updateDBIcons(UserHandleCompat user, List<LauncherActivityInfoCompat> apps,
+            Set<String> ignorePackages) {
+        long userSerial = mUserManager.getSerialNumberForUser(user);
+        PackageManager pm = mContext.getPackageManager();
+        HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
+        for (PackageInfo info : pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
+            pkgInfoMap.put(info.packageName, info);
+        }
+
+        HashMap<ComponentName, LauncherActivityInfoCompat> componentMap = new HashMap<>();
+        for (LauncherActivityInfoCompat app : apps) {
+            componentMap.put(app.getComponentName(), app);
+        }
+
+        Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME,
+                new String[] {IconDB.COLUMN_ROWID, IconDB.COLUMN_COMPONENT,
+                    IconDB.COLUMN_LAST_UPDATED, IconDB.COLUMN_VERSION,
+                    IconDB.COLUMN_SYSTEM_STATE},
+                IconDB.COLUMN_USER + " = ? ",
+                new String[] {Long.toString(userSerial)},
+                null, null, null);
+
+        final int indexComponent = c.getColumnIndex(IconDB.COLUMN_COMPONENT);
+        final int indexLastUpdate = c.getColumnIndex(IconDB.COLUMN_LAST_UPDATED);
+        final int indexVersion = c.getColumnIndex(IconDB.COLUMN_VERSION);
+        final int rowIndex = c.getColumnIndex(IconDB.COLUMN_ROWID);
+        final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
+
+        HashSet<Integer> itemsToRemove = new HashSet<Integer>();
+        Stack<LauncherActivityInfoCompat> appsToUpdate = new Stack<>();
+
+        while (c.moveToNext()) {
+            String cn = c.getString(indexComponent);
+            ComponentName component = ComponentName.unflattenFromString(cn);
+            PackageInfo info = pkgInfoMap.get(component.getPackageName());
+            if (info == null) {
+                if (!ignorePackages.contains(component.getPackageName())) {
+                    remove(component, user);
+                    itemsToRemove.add(c.getInt(rowIndex));
+                }
+                continue;
+            }
+            if ((info.applicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0) {
+                // Application is not present
+                continue;
+            }
+
+            long updateTime = c.getLong(indexLastUpdate);
+            int version = c.getInt(indexVersion);
+            LauncherActivityInfoCompat app = componentMap.remove(component);
+            if (version == info.versionCode && updateTime == info.lastUpdateTime &&
+                    TextUtils.equals(mSystemState, c.getString(systemStateIndex))) {
+                continue;
+            }
+            if (app == null) {
+                remove(component, user);
+                itemsToRemove.add(c.getInt(rowIndex));
+            } else {
+                appsToUpdate.add(app);
             }
         }
+        c.close();
+        if (!itemsToRemove.isEmpty()) {
+            mIconDb.getWritableDatabase().delete(IconDB.TABLE_NAME,
+                    Utilities.createDbSelectionQuery(IconDB.COLUMN_ROWID, itemsToRemove),
+                    null);
+        }
+
+        // Insert remaining apps.
+        if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
+            Stack<LauncherActivityInfoCompat> appsToAdd = new Stack<>();
+            appsToAdd.addAll(componentMap.values());
+            new SerializedIconUpdateTask(userSerial, pkgInfoMap,
+                    appsToAdd, appsToUpdate).scheduleNext();
+        }
+    }
+
+    @Thunk void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
+            long userSerial) {
+        // Reuse the existing entry if it already exists in the DB. This ensures that we do not
+        // create bitmap if it was already created during loader.
+        ContentValues values = updateCacheAndGetContentValues(app, false);
+        addIconToDB(values, app.getComponentName(), info, userSerial);
+    }
+
+    /**
+     * Updates {@param values} to contain versoning information and adds it to the DB.
+     * @param values {@link ContentValues} containing icon & title
+     */
+    private void addIconToDB(ContentValues values, ComponentName key,
+            PackageInfo info, long userSerial) {
+        values.put(IconDB.COLUMN_COMPONENT, key.flattenToString());
+        values.put(IconDB.COLUMN_USER, userSerial);
+        values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime);
+        values.put(IconDB.COLUMN_VERSION, info.versionCode);
+        mIconDb.getWritableDatabase().insertWithOnConflict(IconDB.TABLE_NAME, null, values,
+                SQLiteDatabase.CONFLICT_REPLACE);
+    }
+
+    @Thunk ContentValues updateCacheAndGetContentValues(LauncherActivityInfoCompat app,
+            boolean replaceExisting) {
+        final ComponentKey key = new ComponentKey(app.getComponentName(), app.getUser());
+        CacheEntry entry = null;
+        if (!replaceExisting) {
+            entry = mCache.get(key);
+            // We can't reuse the entry if the high-res icon is not present.
+            if (entry == null || entry.isLowResIcon || entry.icon == null) {
+                entry = null;
+            }
+        }
+        if (entry == null) {
+            entry = new CacheEntry();
+            entry.icon = Utilities.createIconBitmap(app.getBadgedIcon(mIconDpi), mContext);
+        }
+        entry.title = app.getLabel();
+        entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, app.getUser());
+        mCache.put(new ComponentKey(app.getComponentName(), app.getUser()), entry);
+
+        return newContentValues(entry.icon, entry.title.toString(), mActivityBgColor);
+    }
+
+    /**
+     * Fetches high-res icon for the provided ItemInfo and updates the caller when done.
+     * @return a request ID that can be used to cancel the request.
+     */
+    public IconLoadRequest updateIconInBackground(final BubbleTextView caller, final ItemInfo info) {
+        Runnable request = new Runnable() {
+
+            @Override
+            public void run() {
+                if (info instanceof AppInfo) {
+                    getTitleAndIcon((AppInfo) info, null, false);
+                } else if (info instanceof ShortcutInfo) {
+                    ShortcutInfo st = (ShortcutInfo) info;
+                    getTitleAndIcon(st,
+                            st.promisedIntent != null ? st.promisedIntent : st.intent,
+                            st.user, false);
+                } else if (info instanceof PackageItemInfo) {
+                    PackageItemInfo pti = (PackageItemInfo) info;
+                    getTitleAndIconForApp(pti.packageName, pti.user, false, pti);
+                }
+                mMainThreadExecutor.execute(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        caller.reapplyItemInfo(info);
+                    }
+                });
+            }
+        };
+        mWorkerHandler.post(request);
+        return new IconLoadRequest(request, mWorkerHandler);
+    }
+
+    private Bitmap getNonNullIcon(CacheEntry entry, UserHandleCompat user) {
+        return entry.icon == null ? getDefaultIcon(user) : entry.icon;
     }
 
     /**
      * Fill in "application" with the icon and label for "info."
      */
-    public synchronized void getTitleAndIcon(AppInfo application, LauncherActivityInfoCompat info,
-            HashMap<Object, CharSequence> labelCache) {
-        CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
-                info.getUser(), false);
-
-        application.title = entry.title;
-        application.iconBitmap = entry.icon;
+    public synchronized void getTitleAndIcon(AppInfo application,
+            LauncherActivityInfoCompat info, boolean useLowResIcon) {
+        UserHandleCompat user = info == null ? application.user : info.getUser();
+        CacheEntry entry = cacheLocked(application.componentName, info, user,
+                false, useLowResIcon);
+        application.title = Utilities.trim(entry.title);
+        application.iconBitmap = getNonNullIcon(entry, user);
         application.contentDescription = entry.contentDescription;
+        application.usingLowResIcon = entry.isLowResIcon;
     }
 
+    /**
+     * Updates {@param application} only if a valid entry is found.
+     */
+    public synchronized void updateTitleAndIcon(AppInfo application) {
+        CacheEntry entry = cacheLocked(application.componentName, null, application.user,
+                false, application.usingLowResIcon);
+        if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
+            application.title = Utilities.trim(entry.title);
+            application.iconBitmap = entry.icon;
+            application.contentDescription = entry.contentDescription;
+            application.usingLowResIcon = entry.isLowResIcon;
+        }
+    }
+
+    /**
+     * Returns a high res icon for the given intent and user
+     */
     public synchronized Bitmap getIcon(Intent intent, UserHandleCompat user) {
         ComponentName component = intent.getComponent();
         // null info means not installed, but if we have a component from the intent then
@@ -246,15 +466,16 @@
         }
 
         LauncherActivityInfoCompat launcherActInfo = mLauncherApps.resolveActivity(intent, user);
-        CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, true);
+        CacheEntry entry = cacheLocked(component, launcherActInfo, user, true, false /* useLowRes */);
         return entry.icon;
     }
 
     /**
-     * Fill in "shortcutInfo" with the icon and label for "info."
+     * Fill in {@param shortcutInfo} with the icon and label for {@param intent}. If the
+     * corresponding activity is not found, it reverts to the package icon.
      */
     public synchronized void getTitleAndIcon(ShortcutInfo shortcutInfo, Intent intent,
-            UserHandleCompat user, boolean usePkgIcon) {
+            UserHandleCompat user, boolean useLowResIcon) {
         ComponentName component = intent.getComponent();
         // null info means not installed, but if we have a component from the intent then
         // we should still look in the cache for restored app icons.
@@ -262,17 +483,38 @@
             shortcutInfo.setIcon(getDefaultIcon(user));
             shortcutInfo.title = "";
             shortcutInfo.usingFallbackIcon = true;
+            shortcutInfo.usingLowResIcon = false;
         } else {
-            LauncherActivityInfoCompat launcherActInfo =
-                    mLauncherApps.resolveActivity(intent, user);
-            CacheEntry entry = cacheLocked(component, launcherActInfo, null, user, usePkgIcon);
-
-            shortcutInfo.setIcon(entry.icon);
-            shortcutInfo.title = entry.title;
-            shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
+            LauncherActivityInfoCompat info = mLauncherApps.resolveActivity(intent, user);
+            getTitleAndIcon(shortcutInfo, component, info, user, true, useLowResIcon);
         }
     }
 
+    /**
+     * Fill in {@param shortcutInfo} with the icon and label for {@param info}
+     */
+    public synchronized void getTitleAndIcon(
+            ShortcutInfo shortcutInfo, ComponentName component, LauncherActivityInfoCompat info,
+            UserHandleCompat user, boolean usePkgIcon, boolean useLowResIcon) {
+        CacheEntry entry = cacheLocked(component, info, user, usePkgIcon, useLowResIcon);
+        shortcutInfo.setIcon(getNonNullIcon(entry, user));
+        shortcutInfo.title = Utilities.trim(entry.title);
+        shortcutInfo.usingFallbackIcon = isDefaultIcon(entry.icon, user);
+        shortcutInfo.usingLowResIcon = entry.isLowResIcon;
+    }
+
+    /**
+     * Fill in {@param appInfo} with the icon and label for {@param packageName}
+     */
+    public synchronized void getTitleAndIconForApp(
+            String packageName, UserHandleCompat user, boolean useLowResIcon,
+            PackageItemInfo infoOut) {
+        CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon);
+        infoOut.iconBitmap = getNonNullIcon(entry, user);
+        infoOut.title = Utilities.trim(entry.title);
+        infoOut.usingLowResIcon = entry.isLowResIcon;
+        infoOut.contentDescription = entry.contentDescription;
+    }
 
     public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
         if (!mDefaultIcons.containsKey(user)) {
@@ -281,16 +523,6 @@
         return mDefaultIcons.get(user);
     }
 
-    public synchronized Bitmap getIcon(ComponentName component, LauncherActivityInfoCompat info,
-            HashMap<Object, CharSequence> labelCache) {
-        if (info == null || component == null) {
-            return null;
-        }
-
-        CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser(), false);
-        return entry.icon;
-    }
-
     public boolean isDefaultIcon(Bitmap icon, UserHandleCompat user) {
         return mDefaultIcons.get(user) == icon;
     }
@@ -300,44 +532,27 @@
      * This method is not thread safe, it must be called from a synchronized method.
      */
     private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfoCompat info,
-            HashMap<Object, CharSequence> labelCache, UserHandleCompat user, boolean usePackageIcon) {
-        CacheKey cacheKey = new CacheKey(componentName, user);
+            UserHandleCompat user, boolean usePackageIcon, boolean useLowResIcon) {
+        ComponentKey cacheKey = new ComponentKey(componentName, user);
         CacheEntry entry = mCache.get(cacheKey);
-        if (entry == null) {
+        if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
             entry = new CacheEntry();
-
             mCache.put(cacheKey, entry);
 
-            if (info != null) {
-                ComponentName labelKey = info.getComponentName();
-                if (labelCache != null && labelCache.containsKey(labelKey)) {
-                    entry.title = labelCache.get(labelKey).toString();
-                } else {
-                    entry.title = info.getLabel().toString();
-                    if (labelCache != null) {
-                        labelCache.put(labelKey, entry.title);
-                    }
-                }
-
-                entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
-                entry.icon = Utilities.createIconBitmap(
-                        info.getBadgedIcon(mIconDpi), mContext);
-            } else {
-                entry.title = "";
-                Bitmap preloaded = getPreloadedIcon(componentName, user);
-                if (preloaded != null) {
-                    if (DEBUG) Log.d(TAG, "using preloaded icon for " +
-                            componentName.toShortString());
-                    entry.icon = preloaded;
+            // Check the DB first.
+            if (!getEntryFromDB(componentName, user, entry, useLowResIcon)) {
+                if (info != null) {
+                    entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
                 } else {
                     if (usePackageIcon) {
-                        CacheEntry packageEntry = getEntryForPackage(
-                                componentName.getPackageName(), user);
+                        CacheEntry packageEntry = getEntryForPackageLocked(
+                                componentName.getPackageName(), user, false);
                         if (packageEntry != null) {
                             if (DEBUG) Log.d(TAG, "using package default icon for " +
                                     componentName.toShortString());
                             entry.icon = packageEntry.icon;
                             entry.title = packageEntry.title;
+                            entry.contentDescription = packageEntry.contentDescription;
                         }
                     }
                     if (entry.icon == null) {
@@ -347,6 +562,11 @@
                     }
                 }
             }
+
+            if (TextUtils.isEmpty(entry.title) && info != null) {
+                entry.title = info.getLabel();
+                entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
+            }
         }
         return entry;
     }
@@ -357,9 +577,9 @@
      */
     public synchronized void cachePackageInstallInfo(String packageName, UserHandleCompat user,
             Bitmap icon, CharSequence title) {
-        remove(packageName, user);
+        removeFromMemCacheLocked(packageName, user);
 
-        CacheEntry entry = getEntryForPackage(packageName, user);
+        CacheEntry entry = getEntryForPackageLocked(packageName, user, false);
         if (!TextUtils.isEmpty(title)) {
             entry.title = title;
         }
@@ -371,56 +591,68 @@
     /**
      * Gets an entry for the package, which can be used as a fallback entry for various components.
      * This method is not thread safe, it must be called from a synchronized method.
+     *
      */
-    private CacheEntry getEntryForPackage(String packageName, UserHandleCompat user) {
-        ComponentName cn = new ComponentName(packageName, EMPTY_CLASS_NAME);;
-        CacheKey cacheKey = new CacheKey(cn, user);
+    private CacheEntry getEntryForPackageLocked(String packageName, UserHandleCompat user,
+            boolean useLowResIcon) {
+        ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME);
+        ComponentKey cacheKey = new ComponentKey(cn, user);
         CacheEntry entry = mCache.get(cacheKey);
-        if (entry == null) {
-            entry = new CacheEntry();
-            entry.title = "";
-            mCache.put(cacheKey, entry);
 
-            try {
-                ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, 0);
-                entry.title = info.loadLabel(mPackageManager);
-                entry.icon = Utilities.createIconBitmap(info.loadIcon(mPackageManager), mContext);
-            } catch (NameNotFoundException e) {
-                if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+        if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
+            entry = new CacheEntry();
+            boolean entryUpdated = true;
+
+            // Check the DB first.
+            if (!getEntryFromDB(cn, user, entry, useLowResIcon)) {
+                try {
+                    PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
+                    ApplicationInfo appInfo = info.applicationInfo;
+                    if (appInfo == null) {
+                        throw new NameNotFoundException("ApplicationInfo is null");
+                    }
+                    Drawable drawable = mUserManager.getBadgedDrawableForUser(
+                            appInfo.loadIcon(mPackageManager), user);
+                    entry.icon = Utilities.createIconBitmap(drawable, mContext);
+                    entry.title = appInfo.loadLabel(mPackageManager);
+                    entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
+                    entry.isLowResIcon = false;
+
+                    // Add the icon in the DB here, since these do not get written during
+                    // package updates.
+                    ContentValues values =
+                            newContentValues(entry.icon, entry.title.toString(), mPackageBgColor);
+                    addIconToDB(values, cn, info, mUserManager.getSerialNumberForUser(user));
+
+                } catch (NameNotFoundException e) {
+                    if (DEBUG) Log.d(TAG, "Application not installed " + packageName);
+                    entryUpdated = false;
+                }
             }
 
-            if (entry.icon == null) {
-                entry.icon = getPreloadedIcon(cn, user);
+            // Only add a filled-out entry to the cache
+            if (entryUpdated) {
+                mCache.put(cacheKey, entry);
             }
         }
         return entry;
     }
 
-    public synchronized HashMap<ComponentName,Bitmap> getAllIcons() {
-        HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
-        for (CacheKey ck : mCache.keySet()) {
-            final CacheEntry e = mCache.get(ck);
-            set.put(ck.componentName, e.icon);
-        }
-        return set;
-    }
-
     /**
      * Pre-load an icon into the persistent cache.
      *
      * <P>Queries for a component that does not exist in the package manager
      * will be answered by the persistent cache.
      *
-     * @param context application context
      * @param componentName the icon should be returned for this component
      * @param icon the icon to be persisted
      * @param dpi the native density of the icon
      */
-    public static void preloadIcon(Context context, ComponentName componentName, Bitmap icon,
-            int dpi) {
+    public void preloadIcon(ComponentName componentName, Bitmap icon, int dpi, String label,
+            long userSerial) {
         // TODO rescale to the correct native DPI
         try {
-            PackageManager packageManager = context.getPackageManager();
+            PackageManager packageManager = mContext.getPackageManager();
             packageManager.getActivityIcon(componentName);
             // component is present on the system already, do nothing
             return;
@@ -428,100 +660,208 @@
             // pass
         }
 
-        final String key = componentName.flattenToString();
-        FileOutputStream resourceFile = null;
+        ContentValues values = newContentValues(icon, label, Color.TRANSPARENT);
+        values.put(IconDB.COLUMN_COMPONENT, componentName.flattenToString());
+        values.put(IconDB.COLUMN_USER, userSerial);
+        mIconDb.getWritableDatabase().insertWithOnConflict(IconDB.TABLE_NAME, null, values,
+                SQLiteDatabase.CONFLICT_REPLACE);
+    }
+
+    private boolean getEntryFromDB(ComponentName component, UserHandleCompat user,
+            CacheEntry entry, boolean lowRes) {
+        Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME,
+                new String[] {lowRes ? IconDB.COLUMN_ICON_LOW_RES : IconDB.COLUMN_ICON,
+                        IconDB.COLUMN_LABEL},
+                IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+                new String[] {component.flattenToString(),
+                    Long.toString(mUserManager.getSerialNumberForUser(user))},
+                null, null, null);
         try {
-            resourceFile = context.openFileOutput(getResourceFilename(componentName),
-                    Context.MODE_PRIVATE);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            if (icon.compress(android.graphics.Bitmap.CompressFormat.PNG, 75, os)) {
-                byte[] buffer = os.toByteArray();
-                resourceFile.write(buffer, 0, buffer.length);
-            } else {
-                Log.w(TAG, "failed to encode cache for " + key);
-                return;
-            }
-        } catch (FileNotFoundException e) {
-            Log.w(TAG, "failed to pre-load cache for " + key, e);
-        } catch (IOException e) {
-            Log.w(TAG, "failed to pre-load cache for " + key, e);
-        } finally {
-            if (resourceFile != null) {
-                try {
-                    resourceFile.close();
-                } catch (IOException e) {
-                    Log.d(TAG, "failed to save restored icon for: " + key, e);
+            if (c.moveToNext()) {
+                entry.icon = loadIconNoResize(c, 0, lowRes ? mLowResOptions : null);
+                entry.isLowResIcon = lowRes;
+                entry.title = c.getString(1);
+                if (entry.title == null) {
+                    entry.title = "";
+                    entry.contentDescription = "";
+                } else {
+                    entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user);
                 }
+                return true;
             }
+        } finally {
+            c.close();
+        }
+        return false;
+    }
+
+    public static class IconLoadRequest {
+        private final Runnable mRunnable;
+        private final Handler mHandler;
+
+        IconLoadRequest(Runnable runnable, Handler handler) {
+            mRunnable = runnable;
+            mHandler = handler;
+        }
+
+        public void cancel() {
+            mHandler.removeCallbacks(mRunnable);
         }
     }
 
     /**
-     * Read a pre-loaded icon from the persistent icon cache.
-     *
-     * @param componentName the component that should own the icon
-     * @returns a bitmap if one is cached, or null.
+     * A runnable that updates invalid icons and adds missing icons in the DB for the provided
+     * LauncherActivityInfoCompat list. Items are updated/added one at a time, so that the
+     * worker thread doesn't get blocked.
      */
-    private Bitmap getPreloadedIcon(ComponentName componentName, UserHandleCompat user) {
-        final String key = componentName.flattenToShortString();
+    @Thunk class SerializedIconUpdateTask implements Runnable {
+        private final long mUserSerial;
+        private final HashMap<String, PackageInfo> mPkgInfoMap;
+        private final Stack<LauncherActivityInfoCompat> mAppsToAdd;
+        private final Stack<LauncherActivityInfoCompat> mAppsToUpdate;
+        private final HashSet<String> mUpdatedPackages = new HashSet<String>();
 
-        // We don't keep icons for other profiles in persistent cache.
-        if (!user.equals(UserHandleCompat.myUserHandle())) {
+        @Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
+                Stack<LauncherActivityInfoCompat> appsToAdd,
+                Stack<LauncherActivityInfoCompat> appsToUpdate) {
+            mUserSerial = userSerial;
+            mPkgInfoMap = pkgInfoMap;
+            mAppsToAdd = appsToAdd;
+            mAppsToUpdate = appsToUpdate;
+        }
+
+        @Override
+        public void run() {
+            if (!mAppsToUpdate.isEmpty()) {
+                LauncherActivityInfoCompat app = mAppsToUpdate.pop();
+                String cn = app.getComponentName().flattenToString();
+                ContentValues values = updateCacheAndGetContentValues(app, true);
+                mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
+                        IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+                        new String[] {cn, Long.toString(mUserSerial)});
+                mUpdatedPackages.add(app.getComponentName().getPackageName());
+
+                if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
+                    // No more app to update. Notify model.
+                    LauncherAppState.getInstance().getModel().onPackageIconsUpdated(
+                            mUpdatedPackages, mUserManager.getUserForSerialNumber(mUserSerial));
+                }
+
+                // Let it run one more time.
+                scheduleNext();
+            } else if (!mAppsToAdd.isEmpty()) {
+                LauncherActivityInfoCompat app = mAppsToAdd.pop();
+                PackageInfo info = mPkgInfoMap.get(app.getComponentName().getPackageName());
+                if (info != null) {
+                    synchronized (IconCache.this) {
+                        addIconToDBAndMemCache(app, info, mUserSerial);
+                    }
+                }
+
+                if (!mAppsToAdd.isEmpty()) {
+                    scheduleNext();
+                }
+            }
+        }
+
+        public void scheduleNext() {
+            mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN, SystemClock.uptimeMillis() + 1);
+        }
+    }
+
+    private void updateSystemStateString() {
+        mSystemState = Locale.getDefault().toString();
+    }
+
+    private static final class IconDB extends SQLiteOpenHelper {
+        private final static int DB_VERSION = 6;
+
+        private final static String TABLE_NAME = "icons";
+        private final static String COLUMN_ROWID = "rowid";
+        private final static String COLUMN_COMPONENT = "componentName";
+        private final static String COLUMN_USER = "profileId";
+        private final static String COLUMN_LAST_UPDATED = "lastUpdated";
+        private final static String COLUMN_VERSION = "version";
+        private final static String COLUMN_ICON = "icon";
+        private final static String COLUMN_ICON_LOW_RES = "icon_low_res";
+        private final static String COLUMN_LABEL = "label";
+        private final static String COLUMN_SYSTEM_STATE = "system_state";
+
+        public IconDB(Context context) {
+            super(context, LauncherFiles.APP_ICONS_DB, null, DB_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
+                    COLUMN_COMPONENT + " TEXT NOT NULL, " +
+                    COLUMN_USER + " INTEGER NOT NULL, " +
+                    COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " +
+                    COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " +
+                    COLUMN_ICON + " BLOB, " +
+                    COLUMN_ICON_LOW_RES + " BLOB, " +
+                    COLUMN_LABEL + " TEXT, " +
+                    COLUMN_SYSTEM_STATE + " TEXT, " +
+                    "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " +
+                    ");");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            if (oldVersion != newVersion) {
+                clearDB(db);
+            }
+        }
+
+        @Override
+        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            if (oldVersion != newVersion) {
+                clearDB(db);
+            }
+        }
+
+        private void clearDB(SQLiteDatabase db) {
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
+            onCreate(db);
+        }
+    }
+
+    private ContentValues newContentValues(Bitmap icon, String label, int lowResBackgroundColor) {
+        ContentValues values = new ContentValues();
+        values.put(IconDB.COLUMN_ICON, Utilities.flattenBitmap(icon));
+
+        values.put(IconDB.COLUMN_LABEL, label);
+        values.put(IconDB.COLUMN_SYSTEM_STATE, mSystemState);
+
+        if (lowResBackgroundColor == Color.TRANSPARENT) {
+          values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(
+          Bitmap.createScaledBitmap(icon,
+                  icon.getWidth() / LOW_RES_SCALE_FACTOR,
+                  icon.getHeight() / LOW_RES_SCALE_FACTOR, true)));
+        } else {
+            synchronized (this) {
+                if (mLowResBitmap == null) {
+                    mLowResBitmap = Bitmap.createBitmap(icon.getWidth() / LOW_RES_SCALE_FACTOR,
+                            icon.getHeight() / LOW_RES_SCALE_FACTOR, Bitmap.Config.RGB_565);
+                    mLowResCanvas = new Canvas(mLowResBitmap);
+                    mLowResPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
+                }
+                mLowResCanvas.drawColor(lowResBackgroundColor);
+                mLowResCanvas.drawBitmap(icon, new Rect(0, 0, icon.getWidth(), icon.getHeight()),
+                        new Rect(0, 0, mLowResBitmap.getWidth(), mLowResBitmap.getHeight()),
+                        mLowResPaint);
+                values.put(IconDB.COLUMN_ICON_LOW_RES, Utilities.flattenBitmap(mLowResBitmap));
+            }
+        }
+        return values;
+    }
+
+    private static Bitmap loadIconNoResize(Cursor c, int iconIndex, BitmapFactory.Options options) {
+        byte[] data = c.getBlob(iconIndex);
+        try {
+            return BitmapFactory.decodeByteArray(data, 0, data.length, options);
+        } catch (Exception e) {
             return null;
         }
-
-        if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key);
-        Bitmap icon = null;
-        FileInputStream resourceFile = null;
-        try {
-            resourceFile = mContext.openFileInput(getResourceFilename(componentName));
-            byte[] buffer = new byte[1024];
-            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-            int bytesRead = 0;
-            while(bytesRead >= 0) {
-                bytes.write(buffer, 0, bytesRead);
-                bytesRead = resourceFile.read(buffer, 0, buffer.length);
-            }
-            if (DEBUG) Log.d(TAG, "read " + bytes.size());
-            icon = BitmapFactory.decodeByteArray(bytes.toByteArray(), 0, bytes.size());
-            if (icon == null) {
-                Log.w(TAG, "failed to decode pre-load icon for " + key);
-            }
-        } catch (FileNotFoundException e) {
-            if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key);
-        } catch (IOException e) {
-            Log.w(TAG, "failed to read pre-load icon for: " + key, e);
-        } finally {
-            if(resourceFile != null) {
-                try {
-                    resourceFile.close();
-                } catch (IOException e) {
-                    Log.d(TAG, "failed to manage pre-load icon file: " + key, e);
-                }
-            }
-        }
-
-        return icon;
-    }
-
-    /**
-     * Remove a pre-loaded icon from the persistent icon cache.
-     *
-     * @param componentName the component that should own the icon
-     */
-    public void deletePreloadedIcon(ComponentName componentName, UserHandleCompat user) {
-        // We don't keep icons for other profiles in persistent cache.
-        if (!user.equals(UserHandleCompat.myUserHandle()) || componentName == null) {
-            return;
-        }
-        remove(componentName, user);
-        boolean success = mContext.deleteFile(getResourceFilename(componentName));
-        if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache");
-    }
-
-    private static String getResourceFilename(ComponentName component) {
-        String resourceName = component.flattenToShortString();
-        String filename = resourceName.replace(File.separatorChar, '_');
-        return RESOURCE_FILE_PREFIX + filename;
     }
 }
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index 7e55af2..d93cdcc 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -18,21 +18,12 @@
 
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.drawable.TransitionDrawable;
 import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
 
 import com.android.launcher3.compat.UserHandleCompat;
 
 public class InfoDropTarget extends ButtonDropTarget {
 
-    private ColorStateList mOriginalTextColor;
-    private TransitionDrawable mDrawable;
-
     public InfoDropTarget(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -44,96 +35,44 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        mOriginalTextColor = getTextColors();
-
         // Get the hover color
-        Resources r = getResources();
-        mHoverColor = r.getColor(R.color.info_target_hover_tint);
-        mDrawable = (TransitionDrawable) getCurrentDrawable();
+        mHoverColor = getResources().getColor(R.color.info_target_hover_tint);
 
-        if (mDrawable == null) {
-            // TODO: investigate why this is ever happening. Presently only on one known device.
-            mDrawable = (TransitionDrawable) r.getDrawable(R.drawable.info_target_selector);
-            setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
-        }
-
-        if (null != mDrawable) {
-            mDrawable.setCrossFadeEnabled(true);
-        }
-
-        // Remove the text in the Phone UI in landscape
-        int orientation = getResources().getConfiguration().orientation;
-        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            if (!LauncherAppState.getInstance().isScreenLarge()) {
-                setText("");
-            }
-        }
+        setDrawable(R.drawable.ic_info_launcher);
     }
 
-    @Override
-    public boolean acceptDrop(DragObject d) {
-        // acceptDrop is called just before onDrop. We do the work here, rather than
-        // in onDrop, because it allows us to reject the drop (by returning false)
-        // so that the object being dragged isn't removed from the drag source.
+    public static void startDetailsActivityForInfo(Object info, Launcher launcher) {
         ComponentName componentName = null;
-        if (d.dragInfo instanceof AppInfo) {
-            componentName = ((AppInfo) d.dragInfo).componentName;
-        } else if (d.dragInfo instanceof ShortcutInfo) {
-            componentName = ((ShortcutInfo) d.dragInfo).intent.getComponent();
-        } else if (d.dragInfo instanceof PendingAddItemInfo) {
-            componentName = ((PendingAddItemInfo) d.dragInfo).componentName;
+        if (info instanceof AppInfo) {
+            componentName = ((AppInfo) info).componentName;
+        } else if (info instanceof ShortcutInfo) {
+            componentName = ((ShortcutInfo) info).intent.getComponent();
+        } else if (info instanceof PendingAddItemInfo) {
+            componentName = ((PendingAddItemInfo) info).componentName;
         }
         final UserHandleCompat user;
-        if (d.dragInfo instanceof ItemInfo) {
-            user = ((ItemInfo) d.dragInfo).user;
+        if (info instanceof ItemInfo) {
+            user = ((ItemInfo) info).user;
         } else {
             user = UserHandleCompat.myUserHandle();
         }
 
         if (componentName != null) {
-            mLauncher.startApplicationDetailsActivity(componentName, user);
+            launcher.startApplicationDetailsActivity(componentName, user);
         }
-
-        // There is no post-drop animation, so clean up the DragView now
-        d.deferDragViewCleanupPostAnimation = false;
-        return false;
     }
 
     @Override
-    public void onDragStart(DragSource source, Object info, int dragAction) {
-        boolean isVisible = true;
+    protected boolean supportsDrop(DragSource source, Object info) {
+        return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
+    }
 
-        // Hide this button unless we are dragging something from AllApps
-        if (!source.supportsAppInfoDropTarget()) {
-            isVisible = false;
-        }
-
-        mActive = isVisible;
-        mDrawable.resetTransition();
-        setTextColor(mOriginalTextColor);
-        ((ViewGroup) getParent()).setVisibility(isVisible ? View.VISIBLE : View.GONE);
+    public static boolean supportsDrop(Context context, Object info) {
+        return info instanceof AppInfo || info instanceof PendingAddItemInfo;
     }
 
     @Override
-    public void onDragEnd() {
-        super.onDragEnd();
-        mActive = false;
-    }
-
-    public void onDragEnter(DragObject d) {
-        super.onDragEnter(d);
-
-        mDrawable.startTransition(mTransitionDuration);
-        setTextColor(mHoverColor);
-    }
-
-    public void onDragExit(DragObject d) {
-        super.onDragExit(d);
-
-        if (!d.dragComplete) {
-            mDrawable.resetTransition();
-            setTextColor(mOriginalTextColor);
-        }
+    void completeDrop(DragObject d) {
+        startDetailsActivityForInfo(d.dragInfo, mLauncher);
     }
 }
diff --git a/src/com/android/launcher3/Insettable.java b/src/com/android/launcher3/Insettable.java
index 1d2356c..3b8ef2f 100644
--- a/src/com/android/launcher3/Insettable.java
+++ b/src/com/android/launcher3/Insettable.java
@@ -18,6 +18,10 @@
 
 import android.graphics.Rect;
 
+/**
+ * Allows the implementing {@link View} to not draw underneath system bars.
+ * e.g., notification bar on top and home key area on the bottom.
+ */
 public interface Insettable {
 
     void setInsets(Rect insets);
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 1ab3085..3fc8fc0 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -22,6 +22,7 @@
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.text.TextUtils;
@@ -32,6 +33,7 @@
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -144,12 +146,26 @@
             return;
         }
 
-        if (DBG) Log.d(TAG, "Got INSTALL_SHORTCUT: " + data.toUri(0));
         PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
+        if (info.launchIntent == null || info.label == null) {
+            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
+            return;
+        }
 
+        info = convertToLauncherActivityIfPossible(info);
         queuePendingShortcutInfo(info, context);
     }
 
+    public static ShortcutInfo fromShortcutIntent(Context context, Intent data) {
+        PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
+        if (info.launchIntent == null || info.label == null) {
+            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
+            return null;
+        }
+        info = convertToLauncherActivityIfPossible(info);
+        return info.getShortcutInfo();
+    }
+
     static void queueInstallShortcut(LauncherActivityInfoCompat info, Context context) {
         queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
     }
@@ -186,11 +202,6 @@
                 final PendingInstallShortcutInfo pendingInfo = iter.next();
                 final Intent intent = pendingInfo.launchIntent;
 
-                if (LauncherAppState.isDisableAllApps() && !isValidShortcutLaunchIntent(intent)) {
-                    if (DBG) Log.d(TAG, "Ignoring shortcut with launchIntent:" + intent);
-                    continue;
-                }
-
                 // If the intent specifies a package, make sure the package exists
                 String packageName = pendingInfo.getTargetPackage();
                 if (!TextUtils.isEmpty(packageName)) {
@@ -201,56 +212,28 @@
                     }
                 }
 
-                final boolean exists = LauncherModel.shortcutExists(context, pendingInfo.label,
-                        intent, pendingInfo.user);
-                if (!exists) {
-                    // Generate a shortcut info to add into the model
-                    addShortcuts.add(pendingInfo.getShortcutInfo());
-                }
+                // Generate a shortcut info to add into the model
+                addShortcuts.add(pendingInfo.getShortcutInfo());
             }
 
             // Add the new apps to the model and bind them
             if (!addShortcuts.isEmpty()) {
                 LauncherAppState app = LauncherAppState.getInstance();
-                app.getModel().addAndBindAddedWorkspaceApps(context, addShortcuts);
+                app.getModel().addAndBindAddedWorkspaceItems(context, addShortcuts);
             }
         }
     }
 
     /**
-     * Returns true if the intent is a valid launch intent for a shortcut.
-     * This is used to identify shortcuts which are different from the ones exposed by the
-     * applications' manifest file.
-     *
-     * When DISABLE_ALL_APPS is true, shortcuts exposed via the app's manifest should never be
-     * duplicated or removed(unless the app is un-installed).
-     *
-     * @param launchIntent The intent that will be launched when the shortcut is clicked.
-     */
-    static boolean isValidShortcutLaunchIntent(Intent launchIntent) {
-        if (launchIntent != null
-                && Intent.ACTION_MAIN.equals(launchIntent.getAction())
-                && launchIntent.getComponent() != null
-                && launchIntent.getCategories() != null
-                && launchIntent.getCategories().size() == 1
-                && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
-                && launchIntent.getExtras() == null
-                && TextUtils.isEmpty(launchIntent.getDataString())) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
      * Ensures that we have a valid, non-null name.  If the provided name is null, we will return
      * the application name instead.
      */
-    private static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
+    @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
         if (name == null) {
             try {
                 PackageManager pm = context.getPackageManager();
                 ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0);
-                name = info.loadLabel(pm).toString();
+                name = info.loadLabel(pm);
             } catch (PackageManager.NameNotFoundException nnfe) {
                 return "";
             }
@@ -335,7 +318,7 @@
                     .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
                     .key(NAME_KEY).value(name);
                 if (icon != null) {
-                    byte[] iconByteArray = ItemInfo.flattenBitmap(icon);
+                    byte[] iconByteArray = Utilities.flattenBitmap(icon);
                     json = json.key(ICON_KEY).value(
                             Base64.encodeToString(
                                     iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
@@ -354,16 +337,7 @@
 
         public ShortcutInfo getShortcutInfo() {
             if (activityInfo != null) {
-                final ShortcutInfo info = new ShortcutInfo();
-                info.user = user;
-                info.title = label;
-                info.contentDescription = label;
-                info.customIcon = false;
-                info.intent = launchIntent;
-                info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-                info.flags = AppInfo.initFlags(activityInfo);
-                info.firstInstallTime = activityInfo.getFirstInstallTime();
-                return info;
+                return ShortcutInfo.fromActivityInfo(activityInfo, mContext);
             } else {
                 return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
             }
@@ -377,6 +351,10 @@
             }
             return packageName;
         }
+
+        public boolean isLuncherActivity() {
+            return activityInfo != null;
+        }
     }
 
     private static PendingInstallShortcutInfo decode(String encoded, Context context) {
@@ -424,4 +402,34 @@
         }
         return null;
     }
+
+    /**
+     * Tries to create a new PendingInstallShortcutInfo which represents the same target,
+     * but is an app target and not a shortcut.
+     * @return the newly created info or the original one.
+     */
+    private static PendingInstallShortcutInfo convertToLauncherActivityIfPossible(
+            PendingInstallShortcutInfo original) {
+        if (original.isLuncherActivity()) {
+            // Already an activity target
+            return original;
+        }
+        if (!Utilities.isLauncherAppTarget(original.launchIntent)
+                || !original.user.equals(UserHandleCompat.myUserHandle())) {
+            // We can only convert shortcuts which point to a main activity in the current user.
+            return original;
+        }
+
+        PackageManager pm = original.mContext.getPackageManager();
+        ResolveInfo info = pm.resolveActivity(original.launchIntent, 0);
+
+        if (info == null) {
+            return original;
+        }
+
+        // Ignore any conflicts in the label name, as that can change based on locale.
+        LauncherActivityInfoCompat launcherInfo = LauncherActivityInfoCompat
+                .fromResolveInfo(info, original.mContext);
+        return new PendingInstallShortcutInfo(launcherInfo, original.mContext);
+    }
 }
diff --git a/src/com/android/launcher3/InterruptibleInOutAnimator.java b/src/com/android/launcher3/InterruptibleInOutAnimator.java
index 2898b34..29df38b 100644
--- a/src/com/android/launcher3/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher3/InterruptibleInOutAnimator.java
@@ -21,6 +21,8 @@
 import android.animation.ValueAnimator;
 import android.view.View;
 
+import com.android.launcher3.util.Thunk;
+
 /**
  * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
  * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
@@ -43,7 +45,7 @@
     private static final int OUT = 2;
 
     // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
-    private int mDirection = STOPPED;
+    @Thunk int mDirection = STOPPED;
 
     public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
         mAnimator = LauncherAnimUtils.ofFloat(view, fromValue, toValue).setDuration(duration);
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
new file mode 100644
index 0000000..ae204c4
--- /dev/null
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+import com.android.launcher3.util.Thunk;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+public class InvariantDeviceProfile {
+
+    // This is a static that we use for the default icon size on a 4/5-inch phone
+    private static float DEFAULT_ICON_SIZE_DP = 60;
+
+    private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
+
+    // Constants that affects the interpolation curve between statically defined device profile
+    // buckets.
+    private static float KNEARESTNEIGHBOR = 3;
+    private static float WEIGHT_POWER = 5;
+
+    // used to offset float not being able to express extremely small weights in extreme cases.
+    private static float WEIGHT_EFFICIENT = 100000f;
+
+    // Profile-defining invariant properties
+    String name;
+    float minWidthDps;
+    float minHeightDps;
+
+    /**
+     * Number of icons per row and column in the workspace.
+     */
+    public int numRows;
+    public int numColumns;
+
+    /**
+     * The minimum number of predicted apps in all apps.
+     */
+    int minAllAppsPredictionColumns;
+
+    /**
+     * Number of icons per row and column in the folder.
+     */
+    public int numFolderRows;
+    public int numFolderColumns;
+    float iconSize;
+    int iconBitmapSize;
+    int fillResIconDpi;
+    float iconTextSize;
+
+    /**
+     * Number of icons inside the hotseat area.
+     */
+    float numHotseatIcons;
+    float hotseatIconSize;
+    int defaultLayoutId;
+
+    // Derived invariant properties
+    int hotseatAllAppsRank;
+
+    DeviceProfile landscapeProfile;
+    DeviceProfile portraitProfile;
+
+    InvariantDeviceProfile() {
+    }
+
+    public InvariantDeviceProfile(InvariantDeviceProfile p) {
+        this(p.name, p.minWidthDps, p.minHeightDps, p.numRows, p.numColumns,
+                p.numFolderRows, p.numFolderColumns, p.minAllAppsPredictionColumns,
+                p.iconSize, p.iconTextSize, p.numHotseatIcons, p.hotseatIconSize,
+                p.defaultLayoutId);
+    }
+
+    InvariantDeviceProfile(String n, float w, float h, int r, int c, int fr, int fc, int maapc,
+            float is, float its, float hs, float his, int dlId) {
+        // Ensure that we have an odd number of hotseat items (since we need to place all apps)
+        if (hs % 2 == 0) {
+            throw new RuntimeException("All Device Profiles must have an odd number of hotseat spaces");
+        }
+
+        name = n;
+        minWidthDps = w;
+        minHeightDps = h;
+        numRows = r;
+        numColumns = c;
+        numFolderRows = fr;
+        numFolderColumns = fc;
+        minAllAppsPredictionColumns = maapc;
+        iconSize = is;
+        iconTextSize = its;
+        numHotseatIcons = hs;
+        hotseatIconSize = his;
+        defaultLayoutId = dlId;
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    InvariantDeviceProfile(Context context) {
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = wm.getDefaultDisplay();
+        DisplayMetrics dm = new DisplayMetrics();
+        display.getMetrics(dm);
+
+        Point smallestSize = new Point();
+        Point largestSize = new Point();
+        display.getCurrentSizeRange(smallestSize, largestSize);
+
+        // This guarantees that width < height
+        minWidthDps = Utilities.dpiFromPx(Math.min(smallestSize.x, smallestSize.y), dm);
+        minHeightDps = Utilities.dpiFromPx(Math.min(largestSize.x, largestSize.y), dm);
+
+        ArrayList<InvariantDeviceProfile> closestProfiles =
+                findClosestDeviceProfiles(minWidthDps, minHeightDps, getPredefinedDeviceProfiles());
+        InvariantDeviceProfile interpolatedDeviceProfileOut =
+                invDistWeightedInterpolate(minWidthDps,  minHeightDps, closestProfiles);
+
+        InvariantDeviceProfile closestProfile = closestProfiles.get(0);
+        numRows = closestProfile.numRows;
+        numColumns = closestProfile.numColumns;
+        numHotseatIcons = closestProfile.numHotseatIcons;
+        hotseatAllAppsRank = (int) (numHotseatIcons / 2);
+        defaultLayoutId = closestProfile.defaultLayoutId;
+        numFolderRows = closestProfile.numFolderRows;
+        numFolderColumns = closestProfile.numFolderColumns;
+        minAllAppsPredictionColumns = closestProfile.minAllAppsPredictionColumns;
+
+        iconSize = interpolatedDeviceProfileOut.iconSize;
+        iconBitmapSize = Utilities.pxFromDp(iconSize, dm);
+        iconTextSize = interpolatedDeviceProfileOut.iconTextSize;
+        hotseatIconSize = interpolatedDeviceProfileOut.hotseatIconSize;
+        fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
+
+        // If the partner customization apk contains any grid overrides, apply them
+        // Supported overrides: numRows, numColumns, iconSize
+        applyPartnerDeviceProfileOverrides(context, dm);
+
+        Point realSize = new Point();
+        display.getRealSize(realSize);
+        // The real size never changes. smallSide and largeSide will remain the
+        // same in any orientation.
+        int smallSide = Math.min(realSize.x, realSize.y);
+        int largeSide = Math.max(realSize.x, realSize.y);
+
+        landscapeProfile = new DeviceProfile(context, this, smallestSize, largestSize,
+                largeSide, smallSide, true /* isLandscape */);
+        portraitProfile = new DeviceProfile(context, this, smallestSize, largestSize,
+                smallSide, largeSide, false /* isLandscape */);
+    }
+
+    ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles() {
+        ArrayList<InvariantDeviceProfile> predefinedDeviceProfiles = new ArrayList<>();
+        // width, height, #rows, #columns, #folder rows, #folder columns,
+        // iconSize, iconTextSize, #hotseat, #hotseatIconSize, defaultLayoutId.
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Super Short Stubby",
+                255, 300,     2, 3, 2, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Shorter Stubby",
+                255, 400,     3, 3, 3, 3, 3, 48, 13, 3, 48, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Short Stubby",
+                275, 420,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Stubby",
+                255, 450,     3, 4, 3, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus S",
+                296, 491.33f, 4, 4, 4, 4, 4, 48, 13, 5, 48, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 4",
+                335, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 5",
+                359, 567,     4, 4, 4, 4, 4, DEFAULT_ICON_SIZE_DP, 13, 5, 56, R.xml.default_workspace_4x4));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Large Phone",
+                406, 694,     5, 5, 4, 4, 4, 64, 14.4f,  5, 56, R.xml.default_workspace_5x5));
+        // The tablet profile is odd in that the landscape orientation
+        // also includes the nav bar on the side
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 7",
+                575, 904,     5, 6, 4, 5, 4, 72, 14.4f,  7, 60, R.xml.default_workspace_5x6));
+        // Larger tablet profiles always have system bars on the top & bottom
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("Nexus 10",
+                727, 1207,    5, 6, 4, 5, 4, 76, 14.4f,  7, 64, R.xml.default_workspace_5x6));
+        predefinedDeviceProfiles.add(new InvariantDeviceProfile("20-inch Tablet",
+                1527, 2527,   7, 7, 6, 6, 4, 100, 20,  7, 72, R.xml.default_workspace_4x4));
+        return predefinedDeviceProfiles;
+    }
+
+    private int getLauncherIconDensity(int requiredSize) {
+        // Densities typically defined by an app.
+        int[] densityBuckets = new int[] {
+                DisplayMetrics.DENSITY_LOW,
+                DisplayMetrics.DENSITY_MEDIUM,
+                DisplayMetrics.DENSITY_TV,
+                DisplayMetrics.DENSITY_HIGH,
+                DisplayMetrics.DENSITY_XHIGH,
+                DisplayMetrics.DENSITY_XXHIGH,
+                DisplayMetrics.DENSITY_XXXHIGH
+        };
+
+        int density = DisplayMetrics.DENSITY_XXXHIGH;
+        for (int i = densityBuckets.length - 1; i >= 0; i--) {
+            float expectedSize = ICON_SIZE_DEFINED_IN_APP_DP * densityBuckets[i]
+                    / DisplayMetrics.DENSITY_DEFAULT;
+            if (expectedSize >= requiredSize) {
+                density = densityBuckets[i];
+            }
+        }
+
+        return density;
+    }
+
+    /**
+     * Apply any Partner customization grid overrides.
+     *
+     * Currently we support: all apps row / column count.
+     */
+    private void applyPartnerDeviceProfileOverrides(Context context, DisplayMetrics dm) {
+        Partner p = Partner.get(context.getPackageManager());
+        if (p != null) {
+            p.applyInvariantDeviceProfileOverrides(this, dm);
+        }
+    }
+
+    @Thunk float dist(float x0, float y0, float x1, float y1) {
+        return (float) Math.hypot(x1 - x0, y1 - y0);
+    }
+
+    /**
+     * Returns the closest device profiles ordered by closeness to the specified width and height
+     */
+    // Package private visibility for testing.
+    ArrayList<InvariantDeviceProfile> findClosestDeviceProfiles(
+            final float width, final float height, ArrayList<InvariantDeviceProfile> points) {
+
+        // Sort the profiles by their closeness to the dimensions
+        ArrayList<InvariantDeviceProfile> pointsByNearness = points;
+        Collections.sort(pointsByNearness, new Comparator<InvariantDeviceProfile>() {
+            public int compare(InvariantDeviceProfile a, InvariantDeviceProfile b) {
+                return (int) (dist(width, height, a.minWidthDps, a.minHeightDps)
+                        - dist(width, height, b.minWidthDps, b.minHeightDps));
+            }
+        });
+
+        return pointsByNearness;
+    }
+
+    // Package private visibility for testing.
+    InvariantDeviceProfile invDistWeightedInterpolate(float width, float height,
+                ArrayList<InvariantDeviceProfile> points) {
+        float weights = 0;
+
+        InvariantDeviceProfile p = points.get(0);
+        if (dist(width, height, p.minWidthDps, p.minHeightDps) == 0) {
+            return p;
+        }
+
+        InvariantDeviceProfile out = new InvariantDeviceProfile();
+        for (int i = 0; i < points.size() && i < KNEARESTNEIGHBOR; ++i) {
+            p = new InvariantDeviceProfile(points.get(i));
+            float w = weight(width, height, p.minWidthDps, p.minHeightDps, WEIGHT_POWER);
+            weights += w;
+            out.add(p.multiply(w));
+        }
+        return out.multiply(1.0f/weights);
+    }
+
+    private void add(InvariantDeviceProfile p) {
+        iconSize += p.iconSize;
+        iconTextSize += p.iconTextSize;
+        hotseatIconSize += p.hotseatIconSize;
+    }
+
+    private InvariantDeviceProfile multiply(float w) {
+        iconSize *= w;
+        iconTextSize *= w;
+        hotseatIconSize *= w;
+        return this;
+    }
+
+    private float weight(float x0, float y0, float x1, float y1, float pow) {
+        float d = dist(x0, y0, x1, y1);
+        if (Float.compare(d, 0f) == 0) {
+            return Float.POSITIVE_INFINITY;
+        }
+        return (float) (WEIGHT_EFFICIENT / Math.pow(d, pow));
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index 09b77f7..f7e0ea4 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -20,13 +20,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.util.Log;
 
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.util.Arrays;
 
 /**
@@ -39,7 +36,7 @@
      */
     static final String EXTRA_PROFILE = "profile";
     
-    static final int NO_ID = -1;
+    public static final int NO_ID = -1;
     
     /**
      * The id in the settings database for this item
@@ -85,7 +82,7 @@
     /**
      * Indicates the Y cell span.
      */
-    int spanY = 1;
+    public int spanY = 1;
 
     /**
      * Indicates the minimum X cell span.
@@ -98,6 +95,11 @@
     public int minSpanY = 1;
 
     /**
+     * Indicates the position in an ordered list.
+     */
+    public int rank = 0;
+
+    /**
      * Indicates that this item needs to be updated in the db
      */
     public boolean requiresDbUpdate = false;
@@ -105,21 +107,21 @@
     /**
      * Title of the item
      */
-    CharSequence title;
+    public CharSequence title;
 
     /**
      * Content description of the item.
      */
-    CharSequence contentDescription;
+    public CharSequence contentDescription;
 
     /**
      * The position of the item in a drag-and-drop operation.
      */
-    int[] dropPos = null;
+    public int[] dropPos = null;
 
-    UserHandleCompat user;
+    public UserHandleCompat user;
 
-    ItemInfo() {
+    public ItemInfo() {
         user = UserHandleCompat.myUserHandle();
     }
 
@@ -135,6 +137,7 @@
         cellY = info.cellY;
         spanX = info.spanX;
         spanY = info.spanY;
+        rank = info.rank;
         screenId = info.screenId;
         itemType = info.itemType;
         container = info.container;
@@ -161,6 +164,7 @@
         values.put(LauncherSettings.Favorites.CELLY, cellY);
         values.put(LauncherSettings.Favorites.SPANX, spanX);
         values.put(LauncherSettings.Favorites.SPANY, spanY);
+        values.put(LauncherSettings.Favorites.RANK, rank);
         long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
         values.put(LauncherSettings.Favorites.PROFILE_ID, serialNumber);
 
@@ -170,30 +174,9 @@
         }
     }
 
-    void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
-        values.put(LauncherSettings.Favorites.CELLX, cellX);
-        values.put(LauncherSettings.Favorites.CELLY, cellY);
-    }
-
-    static byte[] flattenBitmap(Bitmap bitmap) {
-        // Try go guesstimate how much space the icon will take when serialized
-        // to avoid unnecessary allocations/copies during the write.
-        int size = bitmap.getWidth() * bitmap.getHeight() * 4;
-        ByteArrayOutputStream out = new ByteArrayOutputStream(size);
-        try {
-            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
-            out.flush();
-            out.close();
-            return out.toByteArray();
-        } catch (IOException e) {
-            Log.w("Favorite", "Could not write icon");
-            return null;
-        }
-    }
-
     static void writeBitmap(ContentValues values, Bitmap bitmap) {
         if (bitmap != null) {
-            byte[] data = flattenBitmap(bitmap);
+            byte[] data = Utilities.flattenBitmap(bitmap);
             values.put(LauncherSettings.Favorites.ICON, data);
         }
     }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ac46fd3..6648b6e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2008 The Android Open Source Project
  *
@@ -22,8 +21,8 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -37,25 +36,24 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -66,6 +64,7 @@
 import android.os.Message;
 import android.os.StrictMode;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
@@ -82,40 +81,41 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
-import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.DecelerateInterpolator;
+import android.view.animation.OvershootInterpolator;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Advanceable;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.PagedView.PageSwitchListener;
+import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.LauncherAppsCompat;
-import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetHostViewLoader;
+import com.android.launcher3.widget.WidgetsContainerView;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.text.DateFormat;
@@ -132,12 +132,13 @@
  */
 public class Launcher extends Activity
         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
-                   View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {
+                   View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
+                   LauncherStateTransitionAnimation.Callbacks {
     static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
     static final boolean PROFILE_STARTUP = false;
-    static final boolean DEBUG_WIDGETS = false;
+    static final boolean DEBUG_WIDGETS = true;
     static final boolean DEBUG_STRICT_MODE = false;
     static final boolean DEBUG_RESUME_TIME = false;
     static final boolean DEBUG_DUMP_LOG = false;
@@ -146,28 +147,29 @@
 
     private static final int REQUEST_CREATE_SHORTCUT = 1;
     private static final int REQUEST_CREATE_APPWIDGET = 5;
-    private static final int REQUEST_PICK_SHORTCUT = 7;
     private static final int REQUEST_PICK_APPWIDGET = 9;
     private static final int REQUEST_PICK_WALLPAPER = 10;
 
     private static final int REQUEST_BIND_APPWIDGET = 11;
     private static final int REQUEST_RECONFIGURE_APPWIDGET = 12;
 
+    private static final int WORKSPACE_BACKGROUND_GRADIENT = 0;
+    private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1;
+    private static final int WORKSPACE_BACKGROUND_BLACK = 2;
+
+    private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
+
     /**
      * IntentStarter uses request codes starting with this. This must be greater than all activity
      * request codes used internally.
      */
     protected static final int REQUEST_LAST = 100;
 
-    static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
-
     static final int SCREEN_COUNT = 5;
-    static final int DEFAULT_SCREEN = 2;
 
     // To turn on these properties, type
     // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
     static final String DUMP_STATE_PROPERTY = "launcher_dump_state";
-    static final String DISABLE_ALL_APPS_PROPERTY = "launcher_noallapps";
 
     // The Intent extra that defines whether to ignore the launch animation
     static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
@@ -185,10 +187,6 @@
     private static final String RUNTIME_STATE_PENDING_ADD_CELL_X = "launcher.add_cell_x";
     // Type: int
     private static final String RUNTIME_STATE_PENDING_ADD_CELL_Y = "launcher.add_cell_y";
-    // Type: boolean
-    private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
-    // Type: long
-    private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
     // Type: int
     private static final String RUNTIME_STATE_PENDING_ADD_SPAN_X = "launcher.add_span_x";
     // Type: int
@@ -216,9 +214,10 @@
     public static final String USER_HAS_MIGRATED = "launcher.user_migrated_from_old_data";
 
     /** The different states that Launcher can be in. */
-    private enum State { NONE, WORKSPACE, APPS_CUSTOMIZE, APPS_CUSTOMIZE_SPRING_LOADED };
-    private State mState = State.WORKSPACE;
-    private AnimatorSet mStateAnimation;
+    enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED }
+
+    @Thunk State mState = State.WORKSPACE;
+    @Thunk LauncherStateTransitionAnimation mStateTransitionAnimation;
 
     private boolean mIsSafeModeEnabled;
 
@@ -231,50 +230,50 @@
     private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
     private static final int ACTIVITY_START_DELAY = 1000;
 
-    private static final Object sLock = new Object();
-    private static int sScreen = DEFAULT_SCREEN;
-
     private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
     private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
 
     // How long to wait before the new-shortcut animation automatically pans the workspace
     private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
-    private static int NEW_APPS_ANIMATION_DELAY = 500;
-    private static final int SINGLE_FRAME_DELAY = 16;
+    @Thunk static int NEW_APPS_ANIMATION_DELAY = 500;
 
     private final BroadcastReceiver mCloseSystemDialogsReceiver
             = new CloseSystemDialogsIntentReceiver();
-    private final ContentObserver mWidgetObserver = new AppWidgetResetObserver();
 
     private LayoutInflater mInflater;
 
-    private Workspace mWorkspace;
+    @Thunk Workspace mWorkspace;
     private View mLauncherView;
     private View mPageIndicators;
-    private DragLayer mDragLayer;
+    @Thunk DragLayer mDragLayer;
     private DragController mDragController;
     private View mWeightWatcher;
 
     private AppWidgetManagerCompat mAppWidgetManager;
     private LauncherAppWidgetHost mAppWidgetHost;
 
-    private ItemInfo mPendingAddInfo = new ItemInfo();
-    private AppWidgetProviderInfo mPendingAddWidgetInfo;
+    @Thunk ItemInfo mPendingAddInfo = new ItemInfo();
+    private LauncherAppWidgetProviderInfo mPendingAddWidgetInfo;
     private int mPendingAddWidgetId = -1;
 
     private int[] mTmpAddItemCellCoordinates = new int[2];
 
-    private FolderInfo mFolderInfo;
-
-    private Hotseat mHotseat;
+    @Thunk Hotseat mHotseat;
     private ViewGroup mOverviewPanel;
 
     private View mAllAppsButton;
+    private View mWidgetsButton;
 
     private SearchDropTargetBar mSearchDropTargetBar;
-    private AppsCustomizeTabHost mAppsCustomizeTabHost;
-    private AppsCustomizePagedView mAppsCustomizeContent;
+
+    // Main container view for the all apps screen.
+    @Thunk AllAppsContainerView mAppsView;
+
+    // Main container view and the model for the widget tray screen.
+    @Thunk WidgetsContainerView mWidgetsView;
+    @Thunk WidgetsModel mWidgetsModel;
+
     private boolean mAutoAdvanceRunning = false;
     private AppWidgetHostView mQsb;
 
@@ -286,7 +285,7 @@
 
     private SpannableStringBuilder mDefaultKeySsb = null;
 
-    private boolean mWorkspaceLoading = true;
+    @Thunk boolean mWorkspaceLoading = true;
 
     private boolean mPaused = true;
     private boolean mRestoring;
@@ -300,14 +299,12 @@
 
     private LauncherModel mModel;
     private IconCache mIconCache;
-    private boolean mUserPresent = true;
+    @Thunk boolean mUserPresent = true;
     private boolean mVisible = false;
     private boolean mHasFocus = false;
     private boolean mAttached = false;
 
-    private static LocaleConfiguration sLocaleConfiguration = null;
-
-    private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+    private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
 
     private View.OnTouchListener mHapticFeedbackTouchListener;
 
@@ -317,14 +314,14 @@
     private final int mAdvanceStagger = 250;
     private long mAutoAdvanceSentTime;
     private long mAutoAdvanceTimeLeft = -1;
-    private HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
+    @Thunk HashMap<View, AppWidgetProviderInfo> mWidgetsToAdvance =
         new HashMap<View, AppWidgetProviderInfo>();
 
     // Determines how long to wait after a rotation before restoring the screen orientation to
     // match the sensor state.
     private final int mRestoreScreenOrientationDelay = 500;
 
-    private Drawable mWorkspaceBackgroundDrawable;
+    @Thunk Drawable mWorkspaceBackgroundDrawable;
 
     private final ArrayList<Integer> mSynchronouslyBoundPages = new ArrayList<Integer>();
     private static final boolean DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE = false;
@@ -340,18 +337,43 @@
     // it from the context.
     private SharedPreferences mSharedPrefs;
 
-    private static ArrayList<ComponentName> mIntentsOnWorkspaceFromUpgradePath = null;
-
     // Holds the page that we need to animate to, and the icon views that we need to animate up
     // when we scroll to that page on resume.
-    private ImageView mFolderIconImageView;
+    @Thunk ImageView mFolderIconImageView;
     private Bitmap mFolderIconBitmap;
     private Canvas mFolderIconCanvas;
     private Rect mRectForFolderAnimation = new Rect();
 
+    private DeviceProfile mDeviceProfile;
+
+    // This is set to the view that launched the activity that navigated the user away from
+    // launcher. Since there is no callback for when the activity has finished launching, enable
+    // the press state and keep this reference to reset the press state when we return to launcher.
     private BubbleTextView mWaitingForResume;
 
-    private Runnable mBuildLayersRunnable = new Runnable() {
+    protected static HashMap<String, CustomAppWidget> sCustomAppWidgets =
+            new HashMap<String, CustomAppWidget>();
+
+    private static final boolean ENABLE_CUSTOM_WIDGET_TEST = false;
+    static {
+        if (ENABLE_CUSTOM_WIDGET_TEST) {
+            sCustomAppWidgets.put(DummyWidget.class.getName(), new DummyWidget());
+        }
+    }
+
+    // TODO: remove this field and call method directly when Launcher3 can depend on M APIs
+    private static Method sClipRevealMethod = null;
+    static {
+        Class<?> activityOptionsClass = ActivityOptions.class;
+        try {
+            sClipRevealMethod = activityOptionsClass.getDeclaredMethod("makeClipRevealAnimation",
+                    View.class, int.class, int.class, int.class, int.class);
+        } catch (Exception e) {
+            // Earlier version
+        }
+    }
+
+    @Thunk Runnable mBuildLayersRunnable = new Runnable() {
         public void run() {
             if (mWorkspace != null) {
                 mWorkspace.buildPageHardwareLayers();
@@ -361,7 +383,7 @@
 
     private static PendingAddArguments sPendingAddItem;
 
-    private static class PendingAddArguments {
+    @Thunk static class PendingAddArguments {
         int requestCode;
         Intent intent;
         long container;
@@ -372,8 +394,23 @@
     }
 
     private Stats mStats;
-
     FocusIndicatorView mFocusHandler;
+    private boolean mRotationEnabled = false;
+
+    @Thunk void setOrientation() {
+        if (mRotationEnabled) {
+            unlockScreenOrientation(true);
+        } else {
+            setRequestedOrientation(
+                    ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+        }
+    }
+
+    private Runnable mUpdateOrientationRunnable = new Runnable() {
+        public void run() {
+            setOrientation();
+        }
+    };
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -400,20 +437,22 @@
 
         LauncherAppState.setApplicationContext(getApplicationContext());
         LauncherAppState app = LauncherAppState.getInstance();
-        LauncherAppState.getLauncherProvider().setLauncherProviderChangeListener(this);
 
-        // Lazy-initialize the dynamic grid
-        DeviceProfile grid = app.initDynamicGrid(this);
+        // Load configuration-specific DeviceProfile
+        mDeviceProfile = getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE ?
+                        app.getInvariantDeviceProfile().landscapeProfile
+                            : app.getInvariantDeviceProfile().portraitProfile;
 
-        // the LauncherApplication should call this, but in case of Instrumentation it might not be present yet
         mSharedPrefs = getSharedPreferences(LauncherAppState.getSharedPreferencesKey(),
                 Context.MODE_PRIVATE);
         mIsSafeModeEnabled = getPackageManager().isSafeMode();
         mModel = app.setLauncher(this);
         mIconCache = app.getIconCache();
-        mIconCache.flushInvalidIcons(grid);
+
         mDragController = new DragController(this);
         mInflater = getLayoutInflater();
+        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this);
 
         mStats = new Stats(this);
 
@@ -432,13 +471,10 @@
                     Environment.getExternalStorageDirectory() + "/launcher");
         }
 
-        checkForLocaleChange();
         setContentView(R.layout.launcher);
 
         setupViews();
-        grid.layout(this);
-
-        registerContentObservers();
+        mDeviceProfile.layout(this);
 
         lockAllApps();
 
@@ -453,11 +489,11 @@
             if (DISABLE_SYNCHRONOUS_BINDING_CURRENT_PAGE) {
                 // If the user leaves launcher, then we should just load items asynchronously when
                 // they return.
-                mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE);
+                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
             } else {
                 // We only load the page synchronously if the user rotates (or triggers a
                 // configuration change) while launcher is in the foreground
-                mModel.startLoader(true, mWorkspace.getRestorePage());
+                mModel.startLoader(mWorkspace.getRestorePage());
             }
         }
 
@@ -468,8 +504,16 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         registerReceiver(mCloseSystemDialogsReceiver, filter);
 
-        // On large interfaces, we want the screen to auto-rotate based on the current orientation
-        unlockScreenOrientation(true);
+        mRotationEnabled = Utilities.isRotationAllowedForDevice(getApplicationContext());
+        // In case we are on a device with locked rotation, we should look at preferences to check
+        // if the user has specifically allowed rotation.
+        if (!mRotationEnabled) {
+            mRotationEnabled = Utilities.isAllowRotationPrefEnabled(getApplicationContext(), false);
+        }
+
+        // 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
+        setOrientation();
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onCreate(savedInstanceState);
@@ -490,6 +534,16 @@
         }
     }
 
+    @Override
+    public void onSettingsChanged(String settings, boolean value) {
+        if (Utilities.ALLOW_ROTATION_PREFERENCE_KEY.equals(settings)) {
+            mRotationEnabled = value;
+            if (!waitUntilResume(mUpdateOrientationRunnable, true)) {
+                mUpdateOrientationRunnable.run();
+            }
+        }
+    }
+
     private LauncherCallbacks mLauncherCallbacks;
 
     public void onPostCreate(Bundle savedInstanceState) {
@@ -501,6 +555,47 @@
 
     public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
         mLauncherCallbacks = callbacks;
+        mLauncherCallbacks.setLauncherSearchCallback(new Launcher.LauncherSearchCallbacks() {
+            private boolean mWorkspaceImportanceStored = false;
+            private boolean mHotseatImportanceStored = false;
+            private int mWorkspaceImportanceForAccessibility =
+                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+            private int mHotseatImportanceForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+
+            @Override
+            public void onSearchOverlayOpened() {
+                if (mWorkspaceImportanceStored || mHotseatImportanceStored) {
+                    return;
+                }
+                // The underlying workspace and hotseat are temporarily suppressed by the search
+                // overlay. So they sholudn't be accessible.
+                if (mWorkspace != null) {
+                    mWorkspaceImportanceForAccessibility =
+                            mWorkspace.getImportantForAccessibility();
+                    mWorkspace.setImportantForAccessibility(
+                            View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+                    mWorkspaceImportanceStored = true;
+                }
+                if (mHotseat != null) {
+                    mHotseatImportanceForAccessibility = mHotseat.getImportantForAccessibility();
+                    mHotseat.setImportantForAccessibility(
+                            View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+                    mHotseatImportanceStored = true;
+                }
+            }
+
+            @Override
+            public void onSearchOverlayClosed() {
+                if (mWorkspaceImportanceStored && mWorkspace != null) {
+                    mWorkspace.setImportantForAccessibility(mWorkspaceImportanceForAccessibility);
+                }
+                if (mHotseatImportanceStored && mHotseat != null) {
+                    mHotseat.setImportantForAccessibility(mHotseatImportanceForAccessibility);
+                }
+                mWorkspaceImportanceStored = false;
+                mHotseatImportanceStored = false;
+            }
+        });
         return true;
     }
 
@@ -511,6 +606,14 @@
         }
     }
 
+    /**
+     * Updates the bounds of all the overlays to match the new fixed bounds.
+     */
+    public void updateOverlayBounds(Rect newBounds) {
+        mAppsView.setSearchBarBounds(newBounds);
+        mWidgetsView.setSearchBarBounds(newBounds);
+    }
+
     /** To be overridden by subclasses to hint to Launcher that we have custom content */
     protected boolean hasCustomContentToLeft() {
         if (mLauncherCallbacks != null) {
@@ -549,108 +652,6 @@
         }
     }
 
-    private void checkForLocaleChange() {
-        if (sLocaleConfiguration == null) {
-            new AsyncTask<Void, Void, LocaleConfiguration>() {
-                @Override
-                protected LocaleConfiguration doInBackground(Void... unused) {
-                    LocaleConfiguration localeConfiguration = new LocaleConfiguration();
-                    readConfiguration(Launcher.this, localeConfiguration);
-                    return localeConfiguration;
-                }
-
-                @Override
-                protected void onPostExecute(LocaleConfiguration result) {
-                    sLocaleConfiguration = result;
-                    checkForLocaleChange();  // recursive, but now with a locale configuration
-                }
-            }.execute();
-            return;
-        }
-
-        final Configuration configuration = getResources().getConfiguration();
-
-        final String previousLocale = sLocaleConfiguration.locale;
-        final String locale = configuration.locale.toString();
-
-        final int previousMcc = sLocaleConfiguration.mcc;
-        final int mcc = configuration.mcc;
-
-        final int previousMnc = sLocaleConfiguration.mnc;
-        final int mnc = configuration.mnc;
-
-        boolean localeChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc;
-
-        if (localeChanged) {
-            sLocaleConfiguration.locale = locale;
-            sLocaleConfiguration.mcc = mcc;
-            sLocaleConfiguration.mnc = mnc;
-
-            mIconCache.flush();
-
-            final LocaleConfiguration localeConfiguration = sLocaleConfiguration;
-            new AsyncTask<Void, Void, Void>() {
-                public Void doInBackground(Void ... args) {
-                    writeConfiguration(Launcher.this, localeConfiguration);
-                    return null;
-                }
-            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
-        }
-    }
-
-    private static class LocaleConfiguration {
-        public String locale;
-        public int mcc = -1;
-        public int mnc = -1;
-    }
-
-    private static void readConfiguration(Context context, LocaleConfiguration configuration) {
-        DataInputStream in = null;
-        try {
-            in = new DataInputStream(context.openFileInput(LauncherFiles.LAUNCHER_PREFERENCES));
-            configuration.locale = in.readUTF();
-            configuration.mcc = in.readInt();
-            configuration.mnc = in.readInt();
-        } catch (FileNotFoundException e) {
-            // Ignore
-        } catch (IOException e) {
-            // Ignore
-        } finally {
-            if (in != null) {
-                try {
-                    in.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-
-    private static void writeConfiguration(Context context, LocaleConfiguration configuration) {
-        DataOutputStream out = null;
-        try {
-            out = new DataOutputStream(context.openFileOutput(
-                    LauncherFiles.LAUNCHER_PREFERENCES, MODE_PRIVATE));
-            out.writeUTF(configuration.locale);
-            out.writeInt(configuration.mcc);
-            out.writeInt(configuration.mnc);
-            out.flush();
-        } catch (FileNotFoundException e) {
-            // Ignore
-        } catch (IOException e) {
-            //noinspection ResultOfMethodCallIgnored
-            context.getFileStreamPath(LauncherFiles.LAUNCHER_PREFERENCES).delete();
-        } finally {
-            if (out != null) {
-                try {
-                    out.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-
     public Stats getStats() {
         return mStats;
     }
@@ -659,24 +660,13 @@
         return mInflater;
     }
 
-    boolean isDraggingEnabled() {
+    public boolean isDraggingEnabled() {
         // We prevent dragging when we are loading the workspace as it is possible to pick up a view
         // that is subsequently removed from the workspace in startBinding().
         return !mModel.isLoadingWorkspace();
     }
 
-    static int getScreen() {
-        synchronized (sLock) {
-            return sScreen;
-        }
-    }
-
-    static void setScreen(int screen) {
-        synchronized (sLock) {
-            sScreen = screen;
-        }
-    }
-
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public static int generateViewId() {
         if (Build.VERSION.SDK_INT >= 17) {
             return View.generateViewId();
@@ -766,7 +756,7 @@
             return;
         } else if (requestCode == REQUEST_PICK_WALLPAPER) {
             if (resultCode == RESULT_OK && mWorkspace.isInOverviewMode()) {
-                mWorkspace.exitOverviewMode(false);
+                showWorkspace(false);
             }
             return;
         }
@@ -882,6 +872,15 @@
         }
     }
 
+    /** @Override for MNC */
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (mLauncherCallbacks != null) {
+            mLauncherCallbacks.onRequestPermissionsResult(requestCode, permissions,
+                    grantResults);
+        }
+    }
+
     private PendingAddArguments preparePendingAddArgs(int requestCode, Intent data, int
             appWidgetId, ItemInfo info) {
         PendingAddArguments args = new PendingAddArguments();
@@ -914,7 +913,7 @@
         }
     }
 
-    private void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
+    @Thunk void completeTwoStageWidgetDrop(final int resultCode, final int appWidgetId) {
         CellLayout cellLayout =
                 (CellLayout) mWorkspace.getScreenWithId(mPendingAddInfo.screenId);
         Runnable onCompleteRunnable = null;
@@ -986,18 +985,26 @@
         // Restore the previous launcher state
         if (mOnResumeState == State.WORKSPACE) {
             showWorkspace(false);
-        } else if (mOnResumeState == State.APPS_CUSTOMIZE) {
-            showAllApps(false, mAppsCustomizeContent.getContentType(), false);
+        } else if (mOnResumeState == State.APPS) {
+            boolean launchedFromApp = (mWaitingForResume != null);
+            // Don't update the predicted apps if the user is returning to launcher in the apps
+            // view after launching an app, as they may be depending on the UI to be static to
+            // switch to another app, otherwise, if it was
+            showAppsView(false /* animated */, false /* resetListToTop */,
+                    !launchedFromApp /* updatePredictedApps */, false /* focusSearchBar */);
+        } else if (mOnResumeState == State.WIDGETS) {
+            showWidgetsView(false, false);
         }
         mOnResumeState = State.NONE;
 
-        // Background was set to gradient in onPause(), restore to black if in all apps.
-        setWorkspaceBackground(mState == State.WORKSPACE);
+        // Background was set to gradient in onPause(), restore to transparent if in all apps.
+        setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_GRADIENT
+                : WORKSPACE_BACKGROUND_TRANSPARENT);
 
         mPaused = false;
         if (mRestoring || mOnResumeNeedsLoad) {
             setWorkspaceLoading(true);
-            mModel.startLoader(true, PagedView.INVALID_RESTORE_PAGE);
+            mModel.startLoader(PagedView.INVALID_RESTORE_PAGE);
             mRestoring = false;
             mOnResumeNeedsLoad = false;
         }
@@ -1009,15 +1016,9 @@
                 startTimeCallbacks = System.currentTimeMillis();
             }
 
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.setBulkBind(true);
-            }
             for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
                 mBindOnResumeCallbacks.get(i).run();
             }
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.setBulkBind(false);
-            }
             mBindOnResumeCallbacks.clear();
             if (DEBUG_RESUME_TIME) {
                 Log.d(TAG, "Time spent processing callbacks in onResume: " +
@@ -1043,9 +1044,7 @@
         // (framework issue). On resuming, we ensure that any widgets are inflated for the current
         // orientation.
         getWorkspace().reinflateWidgetsIfNecessary();
-
-        // Process any items that were added while Launcher was away.
-        InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+        reinflateQSBIfNecessary();
 
         if (DEBUG_RESUME_TIME) {
             Log.d(TAG, "Time spent in onResume: " + (System.currentTimeMillis() - startTime));
@@ -1059,10 +1058,13 @@
                 mWorkspace.getCustomContentCallbacks().onShow(true);
             }
         }
-        mWorkspace.updateInteractionForState();
+        updateInteraction(Workspace.State.NORMAL, mWorkspace.getState());
         mWorkspace.onResume();
 
-        PackageInstallerCompat.getInstance(this).onResume();
+        if (!isWorkspaceLoading()) {
+            // Process any items that were added while Launcher was away.
+            InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+        }
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onResume();
@@ -1073,7 +1075,6 @@
     protected void onPause() {
         // Ensure that items added to Launcher are queued until Launcher returns
         InstallShortcutReceiver.enableInstallQueue();
-        PackageInstallerCompat.getInstance(this).onPause();
 
         super.onPause();
         mPaused = true;
@@ -1136,6 +1137,18 @@
         public void forceExitFullImmersion();
     }
 
+    public interface LauncherSearchCallbacks {
+        /**
+         * Called when the search overlay is shown.
+         */
+        public void onSearchOverlayOpened();
+
+        /**
+         * Called when the search overlay is dismissed.
+         */
+        public void onSearchOverlayClosed();
+    }
+
     public interface LauncherOverlayCallbacks {
         /**
          * This method indicates whether a call to {@link #enterFullImmersion()} will succeed,
@@ -1187,11 +1200,13 @@
     protected boolean hasSettings() {
         if (mLauncherCallbacks != null) {
             return mLauncherCallbacks.hasSettings();
+        } else {
+            // On devices with a locked orientation, we will at least have the allow rotation
+            // setting.
+            return !Utilities.isRotationAllowedForDevice(this);
         }
-        return false;
     }
 
-
     public void addToCustomContentPage(View customContent,
             CustomContentCallbacks callbacks, String description) {
         mWorkspace.addToCustomContentPage(customContent, callbacks, description);
@@ -1208,9 +1223,8 @@
         if (mModel.isCurrentCallbacks(this)) {
             mModel.stopLoader();
         }
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.surrender();
-        }
+        //TODO(hyunyoungs): stop the widgets loader when there is a rotation.
+
         return Boolean.TRUE;
     }
 
@@ -1296,8 +1310,8 @@
         }
 
         State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
-        if (state == State.APPS_CUSTOMIZE) {
-            mOnResumeState = State.APPS_CUSTOMIZE;
+        if (state == State.APPS || state == State.WIDGETS) {
+            mOnResumeState = state;
         }
 
         int currentScreen = savedState.getInt(RUNTIME_STATE_CURRENT_SCREEN,
@@ -1316,32 +1330,16 @@
             mPendingAddInfo.cellY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_CELL_Y);
             mPendingAddInfo.spanX = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_X);
             mPendingAddInfo.spanY = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SPAN_Y);
-            mPendingAddWidgetInfo = savedState.getParcelable(RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
+            AppWidgetProviderInfo info = savedState.getParcelable(
+                    RUNTIME_STATE_PENDING_ADD_WIDGET_INFO);
+            mPendingAddWidgetInfo = info == null ?
+                    null : LauncherAppWidgetProviderInfo.fromProviderInfo(this, info);
+
             mPendingAddWidgetId = savedState.getInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID);
             setWaitingForResult(true);
             mRestoring = true;
         }
 
-        boolean renameFolder = savedState.getBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, false);
-        if (renameFolder) {
-            long id = savedState.getLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID);
-            mFolderInfo = mModel.getFolderById(this, sFolders, id);
-            mRestoring = true;
-        }
-
-        // Restore the AppsCustomize tab
-        if (mAppsCustomizeTabHost != null) {
-            String curTab = savedState.getString("apps_customize_currentTab");
-            if (curTab != null) {
-                mAppsCustomizeTabHost.setContentTypeImmediate(
-                        mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
-                mAppsCustomizeContent.loadAssociatedPages(
-                        mAppsCustomizeContent.getCurrentPage());
-            }
-
-            int currentIndex = savedState.getInt("apps_customize_currentIndex");
-            mAppsCustomizeContent.restorePageForIndex(currentIndex);
-        }
         mItemIdToViewId = (HashMap<Integer, Integer>)
                 savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
     }
@@ -1369,13 +1367,12 @@
         // Setup the hotseat
         mHotseat = (Hotseat) findViewById(R.id.hotseat);
         if (mHotseat != null) {
-            mHotseat.setup(this);
             mHotseat.setOnLongClickListener(this);
         }
 
         mOverviewPanel = (ViewGroup) findViewById(R.id.overview_panel);
-        View widgetButton = findViewById(R.id.widget_button);
-        widgetButton.setOnClickListener(new OnClickListener() {
+        mWidgetsButton = findViewById(R.id.widget_button);
+        mWidgetsButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View arg0) {
                 if (!mWorkspace.isSwitchingState()) {
@@ -1383,7 +1380,7 @@
                 }
             }
         });
-        widgetButton.setOnTouchListener(getHapticFeedbackTouchListener());
+        mWidgetsButton.setOnTouchListener(getHapticFeedbackTouchListener());
 
         View wallpaperButton = findViewById(R.id.wallpaper_button);
         wallpaperButton.setOnClickListener(new OnClickListener() {
@@ -1423,11 +1420,14 @@
         mSearchDropTargetBar = (SearchDropTargetBar)
                 mDragLayer.findViewById(R.id.search_drop_target_bar);
 
-        // Setup AppsCustomize
-        mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
-        mAppsCustomizeContent = (AppsCustomizePagedView)
-                mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
-        mAppsCustomizeContent.setup(this, dragController);
+        // Setup Apps and Widgets
+        mAppsView = (AllAppsContainerView) findViewById(R.id.apps_view);
+        mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view);
+        if (mLauncherCallbacks != null && mLauncherCallbacks.getAllAppsSearchBarController() != null) {
+            mAppsView.setSearchBarController(mLauncherCallbacks.getAllAppsSearchBarController());
+        } else {
+            mAppsView.setSearchBarController(mAppsView.newDefaultAppSearchController());
+        }
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
         dragController.setDragScoller(mWorkspace);
@@ -1436,7 +1436,7 @@
         dragController.addDropTarget(mWorkspace);
         if (mSearchDropTargetBar != null) {
             mSearchDropTargetBar.setup(this, dragController);
-            mSearchDropTargetBar.setQsbSearchBar(getQsbBar());
+            mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
         }
 
         if (getResources().getBoolean(R.bool.debug_memory_enabled)) {
@@ -1466,30 +1466,32 @@
         return mAllAppsButton;
     }
 
+    public View getWidgetsButton() {
+        return mWidgetsButton;
+    }
+
     /**
      * Creates a view representing a shortcut.
      *
      * @param info The data structure describing the shortcut.
-     *
-     * @return A View inflated from R.layout.application.
      */
     View createShortcut(ShortcutInfo info) {
-        return createShortcut(R.layout.application,
-                (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
+        return createShortcut((ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
     }
 
     /**
      * Creates a view representing a shortcut inflated from the specified resource.
      *
-     * @param layoutResId The id of the XML layout used to create the shortcut.
      * @param parent The group the shortcut belongs to.
      * @param info The data structure describing the shortcut.
      *
      * @return A View inflated from layoutResId.
      */
-    View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
-        BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
-        favorite.applyFromShortcutInfo(info, mIconCache, true);
+    public View createShortcut(ViewGroup parent, ShortcutInfo info) {
+        BubbleTextView favorite = (BubbleTextView) mInflater.inflate(R.layout.app_icon,
+                parent, false);
+        favorite.applyFromShortcutInfo(info, mIconCache);
+        favorite.setCompoundDrawablePadding(mDeviceProfile.iconDrawablePaddingPx);
         favorite.setOnClickListener(this);
         favorite.setOnFocusChangeListener(mFocusHandler);
         return favorite;
@@ -1499,7 +1501,6 @@
      * Add a shortcut to the workspace.
      *
      * @param data The intent describing the shortcut.
-     * @param cellInfo The position on screen where to create the shortcut.
      */
     private void completeAddShortcut(Intent data, long container, long screenId, int cellX,
             int cellY) {
@@ -1507,14 +1508,13 @@
         int[] touchXY = mPendingAddInfo.dropPos;
         CellLayout layout = getCellLayout(container, screenId);
 
-        boolean foundCellSpan = false;
-
-        ShortcutInfo info = mModel.infoFromShortcutIntent(this, data);
+        ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(this, data);
         if (info == null) {
             return;
         }
         final View view = createShortcut(info);
 
+        boolean foundCellSpan = false;
         // First we check if we already know the exact location where we want to add this item.
         if (cellX >= 0 && cellY >= 0) {
             cellXY[0] = cellX;
@@ -1545,7 +1545,7 @@
             return;
         }
 
-        LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1], false);
+        LauncherModel.addItemToDatabase(this, info, container, screenId, cellXY[0], cellXY[1]);
 
         if (!mRestoring) {
             mWorkspace.addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1,
@@ -1553,119 +1553,67 @@
         }
     }
 
-    static int[] getSpanForWidget(Context context, ComponentName component, int minWidth,
-            int minHeight) {
-        Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context, component, null);
+    private int[] getSpanForWidget(ComponentName component, int minWidth, int minHeight) {
+        Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(this, component, null);
         // We want to account for the extra amount of padding that we are adding to the widget
         // to ensure that it gets the full amount of space that it has requested
         int requiredWidth = minWidth + padding.left + padding.right;
         int requiredHeight = minHeight + padding.top + padding.bottom;
-        return CellLayout.rectToCell(requiredWidth, requiredHeight, null);
+        return CellLayout.rectToCell(this, requiredWidth, requiredHeight, null);
     }
 
-    static int[] getSpanForWidget(Context context, AppWidgetProviderInfo info) {
-        return getSpanForWidget(context, info.provider, info.minWidth, info.minHeight);
+    public int[] getSpanForWidget(AppWidgetProviderInfo info) {
+        return getSpanForWidget(info.provider, info.minWidth, info.minHeight);
     }
 
-    static int[] getMinSpanForWidget(Context context, AppWidgetProviderInfo info) {
-        return getSpanForWidget(context, info.provider, info.minResizeWidth, info.minResizeHeight);
-    }
-
-    static int[] getSpanForWidget(Context context, PendingAddWidgetInfo info) {
-        return getSpanForWidget(context, info.componentName, info.minWidth, info.minHeight);
-    }
-
-    static int[] getMinSpanForWidget(Context context, PendingAddWidgetInfo info) {
-        return getSpanForWidget(context, info.componentName, info.minResizeWidth,
-                info.minResizeHeight);
+    public int[] getMinSpanForWidget(AppWidgetProviderInfo info) {
+        return getSpanForWidget(info.provider, info.minResizeWidth, info.minResizeHeight);
     }
 
     /**
      * Add a widget to the workspace.
      *
      * @param appWidgetId The app widget id
-     * @param cellInfo The position on screen where to create the widget.
      */
-    private void completeAddAppWidget(final int appWidgetId, long container, long screenId,
-            AppWidgetHostView hostView, AppWidgetProviderInfo appWidgetInfo) {
+    @Thunk void completeAddAppWidget(int appWidgetId, long container, long screenId,
+            AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
+
+        ItemInfo info = mPendingAddInfo;
         if (appWidgetInfo == null) {
-            appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+            appWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(this,
+                    mAppWidgetManager.getAppWidgetInfo(appWidgetId));
         }
 
-        // Calculate the grid spans needed to fit this widget
-        CellLayout layout = getCellLayout(container, screenId);
-
-        int[] minSpanXY = getMinSpanForWidget(this, appWidgetInfo);
-        int[] spanXY = getSpanForWidget(this, appWidgetInfo);
-
-        // Try finding open space on Launcher screen
-        // We have saved the position to which the widget was dragged-- this really only matters
-        // if we are placing widgets on a "spring-loaded" screen
-        int[] cellXY = mTmpAddItemCellCoordinates;
-        int[] touchXY = mPendingAddInfo.dropPos;
-        int[] finalSpan = new int[2];
-        boolean foundCellSpan = false;
-        if (mPendingAddInfo.cellX >= 0 && mPendingAddInfo.cellY >= 0) {
-            cellXY[0] = mPendingAddInfo.cellX;
-            cellXY[1] = mPendingAddInfo.cellY;
-            spanXY[0] = mPendingAddInfo.spanX;
-            spanXY[1] = mPendingAddInfo.spanY;
-            foundCellSpan = true;
-        } else if (touchXY != null) {
-            // when dragging and dropping, just find the closest free spot
-            int[] result = layout.findNearestVacantArea(
-                    touchXY[0], touchXY[1], minSpanXY[0], minSpanXY[1], spanXY[0],
-                    spanXY[1], cellXY, finalSpan);
-            spanXY[0] = finalSpan[0];
-            spanXY[1] = finalSpan[1];
-            foundCellSpan = (result != null);
-        } else {
-            foundCellSpan = layout.findCellForSpan(cellXY, minSpanXY[0], minSpanXY[1]);
+        if (appWidgetInfo.isCustomWidget) {
+            appWidgetId = LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
         }
 
-        if (!foundCellSpan) {
-            if (appWidgetId != -1) {
-                // Deleting an app widget ID is a void call but writes to disk before returning
-                // to the caller...
-                new AsyncTask<Void, Void, Void>() {
-                    public Void doInBackground(Void ... args) {
-                        mAppWidgetHost.deleteAppWidgetId(appWidgetId);
-                        return null;
-                    }
-                }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
-            }
-            showOutOfSpaceMessage(isHotseatLayout(layout));
-            return;
-        }
-
-        // Build Launcher-specific widget info and save to database
-        LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId,
-                appWidgetInfo.provider);
-        launcherInfo.spanX = spanXY[0];
-        launcherInfo.spanY = spanXY[1];
-        launcherInfo.minSpanX = mPendingAddInfo.minSpanX;
-        launcherInfo.minSpanY = mPendingAddInfo.minSpanY;
+        LauncherAppWidgetInfo launcherInfo;
+        launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider);
+        launcherInfo.spanX = info.spanX;
+        launcherInfo.spanY = info.spanY;
+        launcherInfo.minSpanX = info.minSpanX;
+        launcherInfo.minSpanY = info.minSpanY;
         launcherInfo.user = mAppWidgetManager.getUser(appWidgetInfo);
 
         LauncherModel.addItemToDatabase(this, launcherInfo,
-                container, screenId, cellXY[0], cellXY[1], false);
+                container, screenId, info.cellX, info.cellY);
 
         if (!mRestoring) {
             if (hostView == null) {
                 // Perform actual inflation because we're live
-                launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
-                launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
+                launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId,
+                        appWidgetInfo);
             } else {
                 // The AppWidgetHostView has already been inflated and instantiated
                 launcherInfo.hostView = hostView;
             }
-
             launcherInfo.hostView.setTag(launcherInfo);
             launcherInfo.hostView.setVisibility(View.VISIBLE);
             launcherInfo.notifyWidgetSizeChanged(this);
 
-            mWorkspace.addInScreen(launcherInfo.hostView, container, screenId, cellXY[0], cellXY[1],
-                    launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
+            mWorkspace.addInScreen(launcherInfo.hostView, container, screenId, info.cellX,
+                    info.cellY, launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
 
             addWidgetToAutoAdvanceIfNeeded(launcherInfo.hostView, appWidgetInfo);
         }
@@ -1679,28 +1627,26 @@
             if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 mUserPresent = false;
                 mDragLayer.clearAllResizeFrames();
-                updateRunning();
+                updateAutoAdvanceState();
 
                 // Reset AllApps to its initial state only if we are not in the middle of
                 // processing a multi-step drop
-                if (mAppsCustomizeTabHost != null && mPendingAddInfo.container == ItemInfo.NO_ID) {
+                if (mAppsView != null && mWidgetsView != null &&
+                        mPendingAddInfo.container == ItemInfo.NO_ID) {
                     showWorkspace(false);
                 }
             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                 mUserPresent = true;
-                updateRunning();
+                updateAutoAdvanceState();
             } else if (ENABLE_DEBUG_INTENTS && DebugIntents.DELETE_DATABASE.equals(action)) {
                 mModel.resetLoadedState(false, true);
-                mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
+                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE,
                         LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE);
             } else if (ENABLE_DEBUG_INTENTS && DebugIntents.MIGRATE_DATABASE.equals(action)) {
                 mModel.resetLoadedState(false, true);
-                mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
+                mModel.startLoader(PagedView.INVALID_RESTORE_PAGE,
                         LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
                                 | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
-            } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
-                    || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
-                getModel().forceReload();
             }
         }
     };
@@ -1714,8 +1660,6 @@
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_USER_PRESENT);
         // For handling managed profiles
-        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
-        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
         if (ENABLE_DEBUG_INTENTS) {
             filter.addAction(DebugIntents.DELETE_DATABASE);
             filter.addAction(DebugIntents.MIGRATE_DATABASE);
@@ -1731,40 +1675,19 @@
      * Sets up transparent navigation and status bars in LMP.
      * This method is a no-op for other platform versions.
      */
-    @TargetApi(19)
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     private void setupTransparentSystemBarsForLmp() {
-        // TODO(sansid): use the APIs directly when compiling against L sdk.
-        // Currently we use reflection to access the flags and the API to set the transparency
-        // on the System bars.
         if (Utilities.isLmpOrAbove()) {
-            try {
-                getWindow().getAttributes().systemUiVisibility |=
-                        (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
-                                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
-                getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
-                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
-                Field drawsSysBackgroundsField = WindowManager.LayoutParams.class.getField(
-                        "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS");
-                getWindow().addFlags(drawsSysBackgroundsField.getInt(null));
-
-                Method setStatusBarColorMethod =
-                        Window.class.getDeclaredMethod("setStatusBarColor", int.class);
-                Method setNavigationBarColorMethod =
-                        Window.class.getDeclaredMethod("setNavigationBarColor", int.class);
-                setStatusBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
-                setNavigationBarColorMethod.invoke(getWindow(), Color.TRANSPARENT);
-            } catch (NoSuchFieldException e) {
-                Log.w(TAG, "NoSuchFieldException while setting up transparent bars");
-            } catch (NoSuchMethodException ex) {
-                Log.w(TAG, "NoSuchMethodException while setting up transparent bars");
-            } catch (IllegalAccessException e) {
-                Log.w(TAG, "IllegalAccessException while setting up transparent bars");
-            } catch (IllegalArgumentException e) {
-                Log.w(TAG, "IllegalArgumentException while setting up transparent bars");
-            } catch (InvocationTargetException e) {
-                Log.w(TAG, "InvocationTargetException while setting up transparent bars");
-            } finally {}
+            Window window = getWindow();
+            window.getAttributes().systemUiVisibility |=
+                    (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            window.setStatusBarColor(Color.TRANSPARENT);
+            window.setNavigationBarColor(Color.TRANSPARENT);
         }
     }
 
@@ -1777,17 +1700,16 @@
             unregisterReceiver(mReceiver);
             mAttached = false;
         }
-        updateRunning();
+        updateAutoAdvanceState();
     }
 
     public void onWindowVisibilityChanged(int visibility) {
         mVisible = visibility == View.VISIBLE;
-        updateRunning();
+        updateAutoAdvanceState();
         // The following code used to be in onResume, but it turns out onResume is called when
         // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
         // is a more appropriate event to handle
         if (mVisible) {
-            mAppsCustomizeTabHost.onWindowVisible();
             if (!mWorkspaceLoading) {
                 final ViewTreeObserver observer = mWorkspace.getViewTreeObserver();
                 // We want to let Launcher draw itself at least once before we force it to build
@@ -1822,14 +1744,14 @@
         }
     }
 
-    private void sendAdvanceMessage(long delay) {
+    @Thunk void sendAdvanceMessage(long delay) {
         mHandler.removeMessages(ADVANCE_MSG);
         Message msg = mHandler.obtainMessage(ADVANCE_MSG);
         mHandler.sendMessageDelayed(msg, delay);
         mAutoAdvanceSentTime = System.currentTimeMillis();
     }
 
-    private void updateRunning() {
+    @Thunk void updateAutoAdvanceState() {
         boolean autoAdvanceRunning = mVisible && mUserPresent && !mWidgetsToAdvance.isEmpty();
         if (autoAdvanceRunning != mAutoAdvanceRunning) {
             mAutoAdvanceRunning = autoAdvanceRunning;
@@ -1847,16 +1769,17 @@
         }
     }
 
-    private final Handler mHandler = new Handler() {
+    @Thunk final Handler mHandler = new Handler(new Handler.Callback() {
+
         @Override
-        public void handleMessage(Message msg) {
+        public boolean handleMessage(Message msg) {
             if (msg.what == ADVANCE_MSG) {
                 int i = 0;
                 for (View key: mWidgetsToAdvance.keySet()) {
                     final View v = key.findViewById(mWidgetsToAdvance.get(key).autoAdvanceViewId);
                     final int delay = mAdvanceStagger * i;
                     if (v instanceof Advanceable) {
-                       postDelayed(new Runnable() {
+                        mHandler.postDelayed(new Runnable() {
                            public void run() {
                                ((Advanceable) v).advance();
                            }
@@ -1866,8 +1789,9 @@
                 }
                 sendAdvanceMessage(mAdvanceInterval);
             }
+            return true;
         }
-    };
+    });
 
     void addWidgetToAutoAdvanceIfNeeded(View hostView, AppWidgetProviderInfo appWidgetInfo) {
         if (appWidgetInfo == null || appWidgetInfo.autoAdvanceViewId == -1) return;
@@ -1875,14 +1799,14 @@
         if (v instanceof Advanceable) {
             mWidgetsToAdvance.put(hostView, appWidgetInfo);
             ((Advanceable) v).fyiWillBeAdvancedByHostKThx();
-            updateRunning();
+            updateAutoAdvanceState();
         }
     }
 
     void removeWidgetToAutoAdvance(View hostView) {
         if (mWidgetsToAdvance.containsKey(hostView)) {
             mWidgetsToAdvance.remove(hostView);
-            updateRunning();
+            updateAutoAdvanceState();
         }
     }
 
@@ -1891,7 +1815,7 @@
         launcherInfo.hostView = null;
     }
 
-    void showOutOfSpaceMessage(boolean isHotseatLayout) {
+    public void showOutOfSpaceMessage(boolean isHotseatLayout) {
         int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
         Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
     }
@@ -1900,6 +1824,14 @@
         return mDragLayer;
     }
 
+    public AllAppsContainerView getAppsView() {
+        return mAppsView;
+    }
+
+    public WidgetsContainerView getWidgetsView() {
+        return mWidgetsView;
+    }
+
     public Workspace getWorkspace() {
         return mWorkspace;
     }
@@ -1928,6 +1860,10 @@
         return mSharedPrefs;
     }
 
+    public DeviceProfile getDeviceProfile() {
+        return mDeviceProfile;
+    }
+
     public void closeSystemDialogs() {
         getWindow().closeAllPanels();
 
@@ -1985,9 +1921,14 @@
                 imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
             }
 
-            // Reset the apps customize page
-            if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
-                mAppsCustomizeTabHost.reset();
+            // Reset the apps view
+            if (!alreadyOnHome && mAppsView != null) {
+                mAppsView.scrollToTop();
+            }
+
+            // Reset the widgets view
+            if (!alreadyOnHome && mWidgetsView != null) {
+                mWidgetsView.scrollToTop();
             }
 
             if (mLauncherCallbacks != null) {
@@ -2037,21 +1978,8 @@
             outState.putInt(RUNTIME_STATE_PENDING_ADD_WIDGET_ID, mPendingAddWidgetId);
         }
 
-        if (mFolderInfo != null && mWaitingForResult) {
-            outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true);
-            outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
-        }
-
-        // Save the current AppsCustomize tab
-        if (mAppsCustomizeTabHost != null) {
-            AppsCustomizePagedView.ContentType type = mAppsCustomizeContent.getContentType();
-            String currentTabTag = mAppsCustomizeTabHost.getTabTagForContentType(type);
-            if (currentTabTag != null) {
-                outState.putString("apps_customize_currentTab", currentTabTag);
-            }
-            int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
-            outState.putInt("apps_customize_currentIndex", currentIndex);
-        }
+        // Save the current widgets tray?
+        // TODO(hyunyoungs)
         outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
 
         if (mLauncherCallbacks != null) {
@@ -2089,13 +2017,6 @@
 
         TextKeyListener.getInstance().release();
 
-        // Disconnect any of the callbacks and drawables associated with ItemInfos on the workspace
-        // to prevent leaking Launcher activities on orientation change.
-        if (mModel != null) {
-            mModel.unbindItemInfosAndClearQueuedBindRunnables();
-        }
-
-        getContentResolver().unregisterContentObserver(mWidgetObserver);
         unregisterReceiver(mCloseSystemDialogsReceiver);
 
         mDragLayer.clearAllResizeFrames();
@@ -2117,10 +2038,26 @@
 
     @Override
     public void startActivityForResult(Intent intent, int requestCode) {
+        onStartForResult(requestCode);
+        super.startActivityForResult(intent, requestCode);
+    }
+
+    @Override
+    public void startIntentSenderForResult (IntentSender intent, int requestCode,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
+        onStartForResult(requestCode);
+        try {
+            super.startIntentSenderForResult(intent, requestCode,
+                fillInIntent, flagsMask, flagsValues, extraFlags, options);
+        } catch (IntentSender.SendIntentException e) {
+            throw new ActivityNotFoundException();
+        }
+    }
+
+    private void onStartForResult(int requestCode) {
         if (requestCode >= 0) {
             setWaitingForResult(true);
         }
-        super.startActivityForResult(intent, requestCode);
     }
 
     /**
@@ -2131,8 +2068,6 @@
     public void startSearch(String initialQuery, boolean selectInitialQuery,
             Bundle appSearchData, boolean globalSearch) {
 
-        showWorkspace(true);
-
         if (initialQuery == null) {
             // Use any text typed in the launcher as the initial query
             initialQuery = getTypedText();
@@ -2151,6 +2086,9 @@
         if (clearTextImmediately) {
             clearTypedText();
         }
+
+        // We need to show the workspace after starting the search
+        showWorkspace(true);
     }
 
     /**
@@ -2284,14 +2222,14 @@
         mPendingAddInfo.dropPos = null;
     }
 
-    void addAppWidgetImpl(final int appWidgetId, final ItemInfo info,
-            final AppWidgetHostView boundWidget, final AppWidgetProviderInfo appWidgetInfo) {
+    void addAppWidgetImpl(final int appWidgetId, final ItemInfo info, final
+            AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo) {
         addAppWidgetImpl(appWidgetId, info, boundWidget, appWidgetInfo, 0);
     }
 
     void addAppWidgetImpl(final int appWidgetId, final ItemInfo info,
-            final AppWidgetHostView boundWidget, final AppWidgetProviderInfo appWidgetInfo, int
-            delay) {
+            final AppWidgetHostView boundWidget, final LauncherAppWidgetProviderInfo appWidgetInfo,
+            int delay) {
         if (appWidgetInfo.configure != null) {
             mPendingAddWidgetInfo = appWidgetInfo;
             mPendingAddWidgetId = appWidgetId;
@@ -2321,20 +2259,39 @@
         closeFolder();
         mWorkspace.moveToCustomContentScreen(animate);
     }
+
+    public void addPendingItem(PendingAddItemInfo info, long container, long screenId,
+            int[] cell, int spanX, int spanY) {
+        switch (info.itemType) {
+            case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+            case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                int span[] = new int[2];
+                span[0] = spanX;
+                span[1] = spanY;
+                addAppWidgetFromDrop((PendingAddWidgetInfo) info,
+                        container, screenId, cell, span);
+                break;
+            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                processShortcutFromDrop(info.componentName, container, screenId, cell);
+                break;
+            default:
+                throw new IllegalStateException("Unknown item type: " + info.itemType);
+            }
+    }
+
     /**
      * Process a shortcut drop.
      *
      * @param componentName The name of the component
      * @param screenId The ID of the screen where it should be added
      * @param cell The cell it should be added to, optional
-     * @param position The location on the screen where it was dropped, optional
      */
-    void processShortcutFromDrop(ComponentName componentName, long container, long screenId,
-            int[] cell, int[] loc) {
+    private void processShortcutFromDrop(ComponentName componentName, long container, long screenId,
+            int[] cell) {
         resetAddInfo();
         mPendingAddInfo.container = container;
         mPendingAddInfo.screenId = screenId;
-        mPendingAddInfo.dropPos = loc;
+        mPendingAddInfo.dropPos = null;
 
         if (cell != null) {
             mPendingAddInfo.cellX = cell[0];
@@ -2343,7 +2300,7 @@
 
         Intent createShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
         createShortcutIntent.setComponent(componentName);
-        processShortcut(createShortcutIntent);
+        Utilities.startActivityForResultSafely(this, createShortcutIntent, REQUEST_CREATE_SHORTCUT);
     }
 
     /**
@@ -2352,14 +2309,13 @@
      * @param info The PendingAppWidgetInfo of the widget being added.
      * @param screenId The ID of the screen where it should be added
      * @param cell The cell it should be added to, optional
-     * @param position The location on the screen where it was dropped, optional
      */
-    void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId,
-            int[] cell, int[] span, int[] loc) {
+    private void addAppWidgetFromDrop(PendingAddWidgetInfo info, long container, long screenId,
+            int[] cell, int[] span) {
         resetAddInfo();
         mPendingAddInfo.container = info.container = container;
         mPendingAddInfo.screenId = info.screenId = screenId;
-        mPendingAddInfo.dropPos = loc;
+        mPendingAddInfo.dropPos = null;
         mPendingAddInfo.minSpanX = info.minSpanX;
         mPendingAddInfo.minSpanY = info.minSpanY;
 
@@ -2377,6 +2333,9 @@
         if (hostView != null) {
             appWidgetId = hostView.getAppWidgetId();
             addAppWidgetImpl(appWidgetId, info, hostView, info.info);
+
+            // Clear the boundWidget so that it doesn't get destroyed.
+            info.boundWidget = null;
         } else {
             // In this case, we either need to start an activity to get permission to bind
             // the widget, or we need to start an activity to configure the widget, or both.
@@ -2401,22 +2360,14 @@
         }
     }
 
-    void processShortcut(Intent intent) {
-        Utilities.startActivityForResultSafely(this, intent, REQUEST_CREATE_SHORTCUT);
-    }
-
-    void processWallpaper(Intent intent) {
-        startActivityForResult(intent, REQUEST_PICK_WALLPAPER);
-    }
-
     FolderIcon addFolder(CellLayout layout, long container, final long screenId, int cellX,
             int cellY) {
         final FolderInfo folderInfo = new FolderInfo();
         folderInfo.title = getText(R.string.folder_name);
 
         // Update the model
-        LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId, cellX, cellY,
-                false);
+        LauncherModel.addItemToDatabase(Launcher.this, folderInfo, container, screenId,
+                cellX, cellY);
         sFolders.put(folderInfo.id, folderInfo);
 
         // Create the view
@@ -2434,23 +2385,6 @@
         sFolders.remove(folder.id);
     }
 
-    protected ComponentName getWallpaperPickerComponent() {
-        if (mLauncherCallbacks != null) {
-            return mLauncherCallbacks.getWallpaperPickerComponent();
-        }
-        return new ComponentName(getPackageName(), LauncherWallpaperPickerActivity.class.getName());
-    }
-
-    /**
-     * Registers various content observers. The current implementation registers
-     * only a favorites observer to keep track of the favorites applications.
-     */
-    private void registerContentObservers() {
-        ContentResolver resolver = getContentResolver();
-        resolver.registerContentObserver(LauncherProvider.CONTENT_APPWIDGET_RESET_URI,
-                true, mWidgetObserver);
-    }
-
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
@@ -2480,15 +2414,17 @@
             return;
         }
 
-        if (isAllAppsVisible()) {
-            if (mAppsCustomizeContent.getContentType() ==
-                    AppsCustomizePagedView.ContentType.Applications) {
-                showWorkspace(true);
-            } else {
-                showOverviewMode(true);
-            }
+        if (mDragController.isDragging()) {
+            mDragController.cancelDrag();
+            return;
+        }
+
+        if (isAppsViewVisible()) {
+            showWorkspace(true);
+        } else if (isWidgetsViewVisible())  {
+            showOverviewMode(true);
         } else if (mWorkspace.isInOverviewMode()) {
-            mWorkspace.exitOverviewMode(true);
+            showWorkspace(true);
         } else if (mWorkspace.getOpenFolder() != null) {
             Folder openFolder = mWorkspace.getOpenFolder();
             if (openFolder.isEditingName()) {
@@ -2505,9 +2441,10 @@
     }
 
     /**
-     * Re-listen when widgets are reset.
+     * Re-listen when widget host is reset.
      */
-    private void onAppWidgetReset() {
+    @Override
+    public void onAppWidgetHostReset() {
         if (mAppWidgetHost != null) {
             mAppWidgetHost.startListening();
         }
@@ -2531,14 +2468,14 @@
 
         if (v instanceof Workspace) {
             if (mWorkspace.isInOverviewMode()) {
-                mWorkspace.exitOverviewMode(true);
+                showWorkspace(true);
             }
             return;
         }
 
         if (v instanceof CellLayout) {
             if (mWorkspace.isInOverviewMode()) {
-                mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true);
+                showWorkspace(mWorkspace.indexOfChild(v), true);
             }
         }
 
@@ -2560,13 +2497,7 @@
         }
     }
 
-    public void onClickPagedViewIcon(View v) {
-        startAppShortcutOrInfoActivity(v);
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onClickPagedViewIcon(v);
-        }
-    }
-
+    @SuppressLint("ClickableViewAccessibility")
     public boolean onTouch(View v, MotionEvent event) {
         return false;
     }
@@ -2585,7 +2516,8 @@
             int widgetId = info.appWidgetId;
             AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId);
             if (appWidgetInfo != null) {
-                mPendingAddWidgetInfo = appWidgetInfo;
+                mPendingAddWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
+                        this, appWidgetInfo);
                 mPendingAddInfo.copyFrom(info);
                 mPendingAddWidgetId = widgetId;
 
@@ -2616,13 +2548,17 @@
      */
     protected void onClickAllAppsButton(View v) {
         if (LOGD) Log.d(TAG, "onClickAllAppsButton");
-        if (isAllAppsVisible()) {
-            showWorkspace(true);
-        } else {
-            showAllApps(true, AppsCustomizePagedView.ContentType.Applications, false);
+        if (!isAppsViewVisible()) {
+            showAppsView(true /* animated */, false /* resetListToTop */,
+                    true /* updatePredictedApps */, false /* focusSearchBar */);
         }
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onClickAllAppsButton(v);
+    }
+
+    protected void onLongClickAllAppsButton(View v) {
+        if (LOGD) Log.d(TAG, "onLongClickAllAppsButton");
+        if (!isAppsViewVisible()) {
+            showAppsView(true /* animated */, false /* resetListToTop */,
+                    true /* updatePredictedApps */, true /* focusSearchBar */);
         }
     }
 
@@ -2704,7 +2640,7 @@
         }
     }
 
-    private void startAppShortcutOrInfoActivity(View v) {
+    @Thunk void startAppShortcutOrInfoActivity(View v) {
         Object tag = v.getTag();
         final ShortcutInfo shortcut;
         final Intent intent;
@@ -2724,7 +2660,7 @@
         }
 
         boolean success = startActivitySafely(v, intent, tag);
-        mStats.recordLaunch(intent, shortcut);
+        mStats.recordLaunch(v, intent, shortcut);
 
         if (success && v instanceof BubbleTextView) {
             mWaitingForResume = (BubbleTextView) v;
@@ -2790,7 +2726,7 @@
         if (mIsSafeModeEnabled) {
             Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
         } else {
-            showAllApps(true, AppsCustomizePagedView.ContentType.Widgets, true);
+            showWidgetsView(true /* animated */, true /* resetPageToZero */);
             if (mLauncherCallbacks != null) {
                 mLauncherCallbacks.onClickAddWidgetButton(view);
             }
@@ -2803,9 +2739,8 @@
      */
     protected void onClickWallpaperPicker(View v) {
         if (LOGD) Log.d(TAG, "onClickWallpaperPicker");
-        final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
-        pickWallpaper.setComponent(getWallpaperPickerComponent());
-        startActivityForResult(pickWallpaper, REQUEST_PICK_WALLPAPER);
+        startActivityForResult(new Intent(Intent.ACTION_SET_WALLPAPER).setPackage(getPackageName()),
+                REQUEST_PICK_WALLPAPER);
 
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onClickWallpaperPicker(v);
@@ -2820,22 +2755,15 @@
         if (LOGD) Log.d(TAG, "onClickSettingsButton");
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onClickSettingsButton(v);
+        } else {
+            startActivity(new Intent(this, SettingsActivity.class));
         }
     }
 
-    public void onTouchDownAllAppsButton(View v) {
-        // Provide the same haptic feedback that the system offers for virtual keys.
-        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-    }
-
-    public void performHapticFeedbackOnTouchDown(View v) {
-        // Provide the same haptic feedback that the system offers for virtual keys.
-        v.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
-    }
-
     public View.OnTouchListener getHapticFeedbackTouchListener() {
         if (mHapticFeedbackTouchListener == null) {
             mHapticFeedbackTouchListener = new View.OnTouchListener() {
+                @SuppressLint("ClickableViewAccessibility")
                 @Override
                 public boolean onTouch(View v, MotionEvent event) {
                     if ((event.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
@@ -2885,6 +2813,19 @@
         }
     }
 
+    /** Updates the interaction state. */
+    public void updateInteraction(Workspace.State fromState, Workspace.State toState) {
+        // Only update the interacting state if we are transitioning to/from a view with an
+        // overlay
+        boolean fromStateWithOverlay = fromState != Workspace.State.NORMAL;
+        boolean toStateWithOverlay = toState != Workspace.State.NORMAL;
+        if (toStateWithOverlay) {
+            onInteractionBegin();
+        } else if (fromStateWithOverlay) {
+            onInteractionEnd();
+        }
+    }
+
     void startApplicationDetailsActivity(ComponentName componentName, UserHandleCompat user) {
         try {
             LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
@@ -2922,7 +2863,7 @@
         }
     }
 
-    boolean startActivity(View v, Intent intent, Object tag) {
+    private boolean startActivity(View v, Intent intent, Object tag) {
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
             // Only launch using the new animation if the shortcut has not opted out (this is a
@@ -2940,10 +2881,45 @@
 
             Bundle optsBundle = null;
             if (useLaunchAnimation) {
-                ActivityOptions opts = Utilities.isLmpOrAbove() ?
-                        ActivityOptions.makeCustomAnimation(this, R.anim.task_open_enter, R.anim.no_anim) :
-                        ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
-                optsBundle = opts.toBundle();
+                ActivityOptions opts = null;
+                if (sClipRevealMethod != null) {
+                    // TODO: call method directly when Launcher3 can depend on M APIs
+                    int left = 0, top = 0;
+                    int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
+                    if (v instanceof TextView) {
+                        // Launch from center of icon, not entire view
+                        Drawable icon = Workspace.getTextViewIcon((TextView) v);
+                        if (icon != null) {
+                            Rect bounds = icon.getBounds();
+                            left = (width - bounds.width()) / 2;
+                            top = v.getPaddingTop();
+                            width = bounds.width();
+                            height = bounds.height();
+                        }
+                    }
+                    try {
+                        opts = (ActivityOptions) sClipRevealMethod.invoke(null, v,
+                                left, top, width, height);
+                    } catch (IllegalAccessException e) {
+                        Log.d(TAG, "Could not call makeClipRevealAnimation: " + e);
+                        sClipRevealMethod = null;
+                    } catch (InvocationTargetException e) {
+                        Log.d(TAG, "Could not call makeClipRevealAnimation: " + e);
+                        sClipRevealMethod = null;
+                    }
+                }
+                if (opts == null && !Utilities.isLmpOrAbove()) {
+                    // Below L, we use a scale up animation
+                    opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
+                                    v.getMeasuredWidth(), v.getMeasuredHeight());
+                } else if (opts == null && Utilities.isLmpMR1()) {
+                    // On L devices, we use the device default slide-up transition.
+                    // On L MR1 devices, we a custom version of the slide-up transition which
+                    // doesn't have the delay present in the device default.
+                    opts = ActivityOptions.makeCustomAnimation(this,
+                            R.anim.task_open_enter, R.anim.no_anim);
+                }
+                optsBundle = opts != null ? opts.toBundle() : null;
             }
 
             if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
@@ -2965,7 +2941,7 @@
         return false;
     }
 
-    boolean startActivitySafely(View v, Intent intent, Object tag) {
+    @Thunk boolean startActivitySafely(View v, Intent intent, Object tag) {
         boolean success = false;
         if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
             Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
@@ -3095,10 +3071,19 @@
      */
     public void openFolder(FolderIcon folderIcon) {
         Folder folder = folderIcon.getFolder();
+        Folder openFolder = mWorkspace != null ? mWorkspace.getOpenFolder() : null;
+        if (openFolder != null && openFolder != folder) {
+            // Close any open folder before opening a folder.
+            closeFolder();
+        }
+
         FolderInfo info = folder.mInfo;
 
         info.opened = true;
 
+        // While the folder is open, the position of the icon cannot change.
+        ((CellLayout.LayoutParams) folderIcon.getLayoutParams()).canReorder = false;
+
         // Just verify that the folder hasn't already been added to the DragLayer.
         // There was a one-off crash where the folder had a parent already.
         if (folder.getParent() == null) {
@@ -3127,13 +3112,16 @@
         }
     }
 
-    void closeFolder(Folder folder) {
+    public void closeFolder(Folder folder) {
         folder.getInfo().opened = false;
 
         ViewGroup parent = (ViewGroup) folder.getParent().getParent();
         if (parent != null) {
             FolderIcon fi = (FolderIcon) mWorkspace.getViewForTag(folder.mInfo);
             shrinkAndFadeInFolderIcon(fi);
+            if (fi != null) {
+                ((CellLayout.LayoutParams) fi.getLayoutParams()).canReorder = true;
+            }
         }
         folder.animateClosed();
 
@@ -3147,9 +3135,15 @@
         if (isWorkspaceLocked()) return false;
         if (mState != State.WORKSPACE) return false;
 
+        if (v == mAllAppsButton) {
+            onLongClickAllAppsButton(v);
+            return true;
+        }
+
         if (v instanceof Workspace) {
             if (!mWorkspace.isInOverviewMode()) {
-                if (mWorkspace.enterOverviewMode()) {
+                if (!mWorkspace.isTouchActive()) {
+                    showOverviewMode(true);
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     return true;
@@ -3165,7 +3159,7 @@
         View itemUnderLongClick = null;
         if (v.getTag() instanceof ItemInfo) {
             ItemInfo info = (ItemInfo) v.getTag();
-            longClickCellInfo = new CellLayout.CellInfo(v, info);;
+            longClickCellInfo = new CellLayout.CellInfo(v, info);
             itemUnderLongClick = longClickCellInfo.cell;
             resetAddInfo();
         }
@@ -3173,8 +3167,7 @@
         // The hotseat touch handling does not go through Workspace, and we always allow long press
         // on hotseat items.
         final boolean inHotseat = isHotseatLayout(v);
-        boolean allowLongPress = inHotseat || mWorkspace.allowLongPress();
-        if (allowLongPress && !mDragController.isDragging()) {
+        if (!mDragController.isDragging()) {
             if (itemUnderLongClick == null) {
                 // User long pressed on empty space
                 mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
@@ -3182,7 +3175,7 @@
                 if (mWorkspace.isInOverviewMode()) {
                     mWorkspace.startReordering(v);
                 } else {
-                    mWorkspace.enterOverviewMode();
+                    showOverviewMode(true);
                 }
             } else {
                 final boolean isAllAppsButton = inHotseat && isAllAppsButtonRank(
@@ -3206,7 +3199,7 @@
     /**
      * Returns the CellLayout of the specified container at the specified screen.
      */
-    CellLayout getCellLayout(long container, long screenId) {
+    public CellLayout getCellLayout(long container, long screenId) {
         if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
             if (mHotseat != null) {
                 return mHotseat.getLayout();
@@ -3214,17 +3207,36 @@
                 return null;
             }
         } else {
-            return (CellLayout) mWorkspace.getScreenWithId(screenId);
+            return mWorkspace.getScreenWithId(screenId);
         }
     }
 
+    /**
+     * For overridden classes.
+     */
     public boolean isAllAppsVisible() {
-        return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE);
+        return isAppsViewVisible();
     }
 
-    private void setWorkspaceBackground(boolean workspace) {
-        mLauncherView.setBackground(workspace ?
-                mWorkspaceBackgroundDrawable : null);
+    public boolean isAppsViewVisible() {
+        return (mState == State.APPS) || (mOnResumeState == State.APPS);
+    }
+
+    public boolean isWidgetsViewVisible() {
+        return (mState == State.WIDGETS) || (mOnResumeState == State.WIDGETS);
+    }
+
+    private void setWorkspaceBackground(int background) {
+        switch (background) {
+            case WORKSPACE_BACKGROUND_TRANSPARENT:
+                getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+                break;
+            case WORKSPACE_BACKGROUND_BLACK:
+                getWindow().setBackgroundDrawable(null);
+                break;
+            default:
+                getWindow().setBackgroundDrawable(mWorkspaceBackgroundDrawable);
+        }
     }
 
     protected void changeWallpaperVisiblity(boolean visible) {
@@ -3234,577 +3246,7 @@
         if (wpflags != curflags) {
             getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
         }
-        setWorkspaceBackground(visible);
-    }
-
-    private void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
-        if (v instanceof LauncherTransitionable) {
-            ((LauncherTransitionable) v).onLauncherTransitionPrepare(this, animated, toWorkspace);
-        }
-    }
-
-    private void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
-        if (v instanceof LauncherTransitionable) {
-            ((LauncherTransitionable) v).onLauncherTransitionStart(this, animated, toWorkspace);
-        }
-
-        // Update the workspace transition step as well
-        dispatchOnLauncherTransitionStep(v, 0f);
-    }
-
-    private void dispatchOnLauncherTransitionStep(View v, float t) {
-        if (v instanceof LauncherTransitionable) {
-            ((LauncherTransitionable) v).onLauncherTransitionStep(this, t);
-        }
-    }
-
-    private void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
-        if (v instanceof LauncherTransitionable) {
-            ((LauncherTransitionable) v).onLauncherTransitionEnd(this, animated, toWorkspace);
-        }
-
-        // Update the workspace transition step as well
-        dispatchOnLauncherTransitionStep(v, 1f);
-    }
-
-    /**
-     * Things to test when changing the following seven functions.
-     *   - Home from workspace
-     *          - from center screen
-     *          - from other screens
-     *   - Home from all apps
-     *          - from center screen
-     *          - from other screens
-     *   - Back from all apps
-     *          - from center screen
-     *          - from other screens
-     *   - Launch app from workspace and quit
-     *          - with back
-     *          - with home
-     *   - Launch app from all apps and quit
-     *          - with back
-     *          - with home
-     *   - Go to a screen that's not the default, then all
-     *     apps, and launch and app, and go back
-     *          - with back
-     *          -with home
-     *   - On workspace, long press power and go back
-     *          - with back
-     *          - with home
-     *   - On all apps, long press power and go back
-     *          - with back
-     *          - with home
-     *   - On workspace, power off
-     *   - On all apps, power off
-     *   - Launch an app and turn off the screen while in that app
-     *          - Go back with home key
-     *          - Go back with back key  TODO: make this not go to workspace
-     *          - From all apps
-     *          - From workspace
-     *   - Enter and exit car mode (becuase it causes an extra configuration changed)
-     *          - From all apps
-     *          - From the center workspace
-     *          - From another workspace
-     */
-
-    /**
-     * Zoom the camera out from the workspace to reveal 'toView'.
-     * Assumes that the view to show is anchored at either the very top or very bottom
-     * of the screen.
-     */
-    private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded) {
-        AppsCustomizePagedView.ContentType contentType = mAppsCustomizeContent.getContentType();
-        showAppsCustomizeHelper(animated, springLoaded, contentType);
-    }
-
-    private void showAppsCustomizeHelper(final boolean animated, final boolean springLoaded,
-                                         final AppsCustomizePagedView.ContentType contentType) {
-        if (mStateAnimation != null) {
-            mStateAnimation.setDuration(0);
-            mStateAnimation.cancel();
-            mStateAnimation = null;
-        }
-
-        boolean material = Utilities.isLmpOrAbove();
-
-        final Resources res = getResources();
-
-        final int duration = res.getInteger(R.integer.config_appsCustomizeZoomInTime);
-        final int fadeDuration = res.getInteger(R.integer.config_appsCustomizeFadeInTime);
-        final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
-        final int itemsAlphaStagger =
-                res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
-
-        final float scale = (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
-        final View fromView = mWorkspace;
-        final AppsCustomizeTabHost toView = mAppsCustomizeTabHost;
-
-        final ArrayList<View> layerViews = new ArrayList<View>();
-
-        Workspace.State workspaceState = contentType == AppsCustomizePagedView.ContentType.Widgets ?
-                Workspace.State.OVERVIEW_HIDDEN : Workspace.State.NORMAL_HIDDEN;
-        Animator workspaceAnim =
-                mWorkspace.getChangeStateAnimation(workspaceState, animated, layerViews);
-        if (!LauncherAppState.isDisableAllApps()
-                || contentType == AppsCustomizePagedView.ContentType.Widgets) {
-            // Set the content type for the all apps/widgets space
-            mAppsCustomizeTabHost.setContentTypeImmediate(contentType);
-        }
-
-        // If for some reason our views aren't initialized, don't animate
-        boolean initialized = getAllAppsButton() != null;
-
-        if (animated && initialized) {
-            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
-            final AppsCustomizePagedView content = (AppsCustomizePagedView)
-                    toView.findViewById(R.id.apps_customize_pane_content);
-
-            final View page = content.getPageAt(content.getCurrentPage());
-            final View revealView = toView.findViewById(R.id.fake_page);
-
-            final boolean isWidgetTray = contentType == AppsCustomizePagedView.ContentType.Widgets;
-            if (isWidgetTray) {
-                revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
-            } else {
-                revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
-            }
-
-            // Hide the real page background, and swap in the fake one
-            content.setPageBackgroundsVisible(false);
-            revealView.setVisibility(View.VISIBLE);
-            // We need to hide this view as the animation start will be posted.
-            revealView.setAlpha(0);
-
-            int width = revealView.getMeasuredWidth();
-            int height = revealView.getMeasuredHeight();
-            float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
-
-            revealView.setTranslationY(0);
-            revealView.setTranslationX(0);
-
-            // Get the y delta between the center of the page and the center of the all apps button
-            int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
-                    getAllAppsButton(), null);
-
-            float alpha = 0;
-            float xDrift = 0;
-            float yDrift = 0;
-            if (material) {
-                alpha = isWidgetTray ? 0.3f : 1f;
-                yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
-                xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
-            } else {
-                yDrift = 2 * height / 3;
-                xDrift = 0;
-            }
-            final float initAlpha = alpha;
-
-            revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            layerViews.add(revealView);
-            PropertyValuesHolder panelAlpha = PropertyValuesHolder.ofFloat("alpha", initAlpha, 1f);
-            PropertyValuesHolder panelDriftY =
-                    PropertyValuesHolder.ofFloat("translationY", yDrift, 0);
-            PropertyValuesHolder panelDriftX =
-                    PropertyValuesHolder.ofFloat("translationX", xDrift, 0);
-
-            ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
-                    panelAlpha, panelDriftY, panelDriftX);
-
-            panelAlphaAndDrift.setDuration(revealDuration);
-            panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
-            mStateAnimation.play(panelAlphaAndDrift);
-
-            if (page != null) {
-                page.setVisibility(View.VISIBLE);
-                page.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                layerViews.add(page);
-
-                ObjectAnimator pageDrift = ObjectAnimator.ofFloat(page, "translationY", yDrift, 0);
-                page.setTranslationY(yDrift);
-                pageDrift.setDuration(revealDuration);
-                pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
-                pageDrift.setStartDelay(itemsAlphaStagger);
-                mStateAnimation.play(pageDrift);
-
-                page.setAlpha(0f);
-                ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(page, "alpha", 0f, 1f);
-                itemsAlpha.setDuration(revealDuration);
-                itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
-                itemsAlpha.setStartDelay(itemsAlphaStagger);
-                mStateAnimation.play(itemsAlpha);
-            }
-
-            View pageIndicators = toView.findViewById(R.id.apps_customize_page_indicator);
-            pageIndicators.setAlpha(0.01f);
-            ObjectAnimator indicatorsAlpha =
-                    ObjectAnimator.ofFloat(pageIndicators, "alpha", 1f);
-            indicatorsAlpha.setDuration(revealDuration);
-            mStateAnimation.play(indicatorsAlpha);
-
-            if (material) {
-                final View allApps = getAllAppsButton();
-                int allAppsButtonSize = LauncherAppState.getInstance().
-                        getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
-                float startRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
-                Animator reveal = ViewAnimationUtils.createCircularReveal(revealView, width / 2,
-                                height / 2, startRadius, revealRadius);
-                reveal.setDuration(revealDuration);
-                reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-
-                reveal.addListener(new AnimatorListenerAdapter() {
-                    public void onAnimationStart(Animator animation) {
-                        if (!isWidgetTray) {
-                            allApps.setVisibility(View.INVISIBLE);
-                        }
-                    }
-                    public void onAnimationEnd(Animator animation) {
-                        if (!isWidgetTray) {
-                            allApps.setVisibility(View.VISIBLE);
-                        }
-                    }
-                });
-                mStateAnimation.play(reveal);
-            }
-
-            mStateAnimation.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    dispatchOnLauncherTransitionEnd(fromView, animated, false);
-                    dispatchOnLauncherTransitionEnd(toView, animated, false);
-
-                    revealView.setVisibility(View.INVISIBLE);
-                    revealView.setLayerType(View.LAYER_TYPE_NONE, null);
-                    if (page != null) {
-                        page.setLayerType(View.LAYER_TYPE_NONE, null);
-                    }
-                    content.setPageBackgroundsVisible(true);
-
-                    // Hide the search bar
-                    if (mSearchDropTargetBar != null) {
-                        mSearchDropTargetBar.hideSearchBar(false);
-                    }
-
-                    // This can hold unnecessary references to views.
-                    mStateAnimation = null;
-                }
-
-            });
-
-            if (workspaceAnim != null) {
-                mStateAnimation.play(workspaceAnim);
-            }
-
-            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
-            dispatchOnLauncherTransitionPrepare(toView, animated, false);
-            final AnimatorSet stateAnimation = mStateAnimation;
-            final Runnable startAnimRunnable = new Runnable() {
-                public void run() {
-                    // Check that mStateAnimation hasn't changed while
-                    // we waited for a layout/draw pass
-                    if (mStateAnimation != stateAnimation)
-                        return;
-                    dispatchOnLauncherTransitionStart(fromView, animated, false);
-                    dispatchOnLauncherTransitionStart(toView, animated, false);
-
-                    revealView.setAlpha(initAlpha);
-                    if (Utilities.isLmpOrAbove()) {
-                        for (int i = 0; i < layerViews.size(); i++) {
-                            View v = layerViews.get(i);
-                            if (v != null) {
-                                if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
-                            }
-                        }
-                    }
-                    mStateAnimation.start();
-                }
-            };
-            toView.bringToFront();
-            toView.setVisibility(View.VISIBLE);
-            toView.post(startAnimRunnable);
-        } else {
-            toView.setTranslationX(0.0f);
-            toView.setTranslationY(0.0f);
-            toView.setScaleX(1.0f);
-            toView.setScaleY(1.0f);
-            toView.setVisibility(View.VISIBLE);
-            toView.bringToFront();
-
-            if (!springLoaded && !LauncherAppState.getInstance().isScreenLarge()) {
-                // Hide the search bar
-                if (mSearchDropTargetBar != null) {
-                    mSearchDropTargetBar.hideSearchBar(false);
-                }
-            }
-            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
-            dispatchOnLauncherTransitionStart(fromView, animated, false);
-            dispatchOnLauncherTransitionEnd(fromView, animated, false);
-            dispatchOnLauncherTransitionPrepare(toView, animated, false);
-            dispatchOnLauncherTransitionStart(toView, animated, false);
-            dispatchOnLauncherTransitionEnd(toView, animated, false);
-        }
-    }
-
-    /**
-     * Zoom the camera back into the workspace, hiding 'fromView'.
-     * This is the opposite of showAppsCustomizeHelper.
-     * @param animated If true, the transition will be animated.
-     */
-    private void hideAppsCustomizeHelper(Workspace.State toState, final boolean animated,
-            final boolean springLoaded, final Runnable onCompleteRunnable) {
-
-        if (mStateAnimation != null) {
-            mStateAnimation.setDuration(0);
-            mStateAnimation.cancel();
-            mStateAnimation = null;
-        }
-
-        boolean material = Utilities.isLmpOrAbove();
-        Resources res = getResources();
-
-        final int duration = res.getInteger(R.integer.config_appsCustomizeZoomOutTime);
-        final int fadeOutDuration = res.getInteger(R.integer.config_appsCustomizeFadeOutTime);
-        final int revealDuration = res.getInteger(R.integer.config_appsCustomizeConcealTime);
-        final int itemsAlphaStagger =
-                res.getInteger(R.integer.config_appsCustomizeItemsAlphaStagger);
-
-        final float scaleFactor = (float)
-                res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor);
-        final View fromView = mAppsCustomizeTabHost;
-        final View toView = mWorkspace;
-        Animator workspaceAnim = null;
-        final ArrayList<View> layerViews = new ArrayList<View>();
-
-        if (toState == Workspace.State.NORMAL) {
-            workspaceAnim = mWorkspace.getChangeStateAnimation(
-                    toState, animated, layerViews);
-        } else if (toState == Workspace.State.SPRING_LOADED ||
-                toState == Workspace.State.OVERVIEW) {
-            workspaceAnim = mWorkspace.getChangeStateAnimation(
-                    toState, animated, layerViews);
-        }
-
-        // If for some reason our views aren't initialized, don't animate
-        boolean initialized = getAllAppsButton() != null;
-
-        if (animated && initialized) {
-            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
-            if (workspaceAnim != null) {
-                mStateAnimation.play(workspaceAnim);
-            }
-
-            final AppsCustomizePagedView content = (AppsCustomizePagedView)
-                    fromView.findViewById(R.id.apps_customize_pane_content);
-
-            final View page = content.getPageAt(content.getNextPage());
-
-            // We need to hide side pages of the Apps / Widget tray to avoid some ugly edge cases
-            int count = content.getChildCount();
-            for (int i = 0; i < count; i++) {
-                View child = content.getChildAt(i);
-                if (child != page) {
-                    child.setVisibility(View.INVISIBLE);
-                }
-            }
-            final View revealView = fromView.findViewById(R.id.fake_page);
-
-            // hideAppsCustomizeHelper is called in some cases when it is already hidden
-            // don't perform all these no-op animations. In particularly, this was causing
-            // the all-apps button to pop in and out.
-            if (fromView.getVisibility() == View.VISIBLE) {
-                AppsCustomizePagedView.ContentType contentType = content.getContentType();
-                final boolean isWidgetTray =
-                        contentType == AppsCustomizePagedView.ContentType.Widgets;
-
-                if (isWidgetTray) {
-                    revealView.setBackground(res.getDrawable(R.drawable.quantum_panel_dark));
-                } else {
-                    revealView.setBackground(res.getDrawable(R.drawable.quantum_panel));
-                }
-
-                int width = revealView.getMeasuredWidth();
-                int height = revealView.getMeasuredHeight();
-                float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
-
-                // Hide the real page background, and swap in the fake one
-                revealView.setVisibility(View.VISIBLE);
-                content.setPageBackgroundsVisible(false);
-
-                final View allAppsButton = getAllAppsButton();
-                revealView.setTranslationY(0);
-                int[] allAppsToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
-                        allAppsButton, null);
-
-                float xDrift = 0;
-                float yDrift = 0;
-                if (material) {
-                    yDrift = isWidgetTray ? height / 2 : allAppsToPanelDelta[1];
-                    xDrift = isWidgetTray ? 0 : allAppsToPanelDelta[0];
-                } else {
-                    yDrift = 2 * height / 3;
-                    xDrift = 0;
-                }
-
-                revealView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                TimeInterpolator decelerateInterpolator = material ?
-                        new LogDecelerateInterpolator(100, 0) :
-                        new DecelerateInterpolator(1f);
-
-                // The vertical motion of the apps panel should be delayed by one frame
-                // from the conceal animation in order to give the right feel. We correpsondingly
-                // shorten the duration so that the slide and conceal end at the same time.
-                ObjectAnimator panelDriftY = LauncherAnimUtils.ofFloat(revealView, "translationY",
-                        0, yDrift);
-                panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
-                panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
-                panelDriftY.setInterpolator(decelerateInterpolator);
-                mStateAnimation.play(panelDriftY);
-
-                ObjectAnimator panelDriftX = LauncherAnimUtils.ofFloat(revealView, "translationX",
-                        0, xDrift);
-                panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
-                panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
-                panelDriftX.setInterpolator(decelerateInterpolator);
-                mStateAnimation.play(panelDriftX);
-
-                if (isWidgetTray || !material) {
-                    float finalAlpha = material ? 0.4f : 0f;
-                    revealView.setAlpha(1f);
-                    ObjectAnimator panelAlpha = LauncherAnimUtils.ofFloat(revealView, "alpha",
-                            1f, finalAlpha);
-                    panelAlpha.setDuration(material ? revealDuration : 150);
-                    panelAlpha.setInterpolator(decelerateInterpolator);
-                    panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
-                    mStateAnimation.play(panelAlpha);
-                }
-
-                if (page != null) {
-                    page.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-
-                    ObjectAnimator pageDrift = LauncherAnimUtils.ofFloat(page, "translationY",
-                            0, yDrift);
-                    page.setTranslationY(0);
-                    pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
-                    pageDrift.setInterpolator(decelerateInterpolator);
-                    pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
-                    mStateAnimation.play(pageDrift);
-
-                    page.setAlpha(1f);
-                    ObjectAnimator itemsAlpha = LauncherAnimUtils.ofFloat(page, "alpha", 1f, 0f);
-                    itemsAlpha.setDuration(100);
-                    itemsAlpha.setInterpolator(decelerateInterpolator);
-                    mStateAnimation.play(itemsAlpha);
-                }
-
-                View pageIndicators = fromView.findViewById(R.id.apps_customize_page_indicator);
-                pageIndicators.setAlpha(1f);
-                ObjectAnimator indicatorsAlpha =
-                        LauncherAnimUtils.ofFloat(pageIndicators, "alpha", 0f);
-                indicatorsAlpha.setDuration(revealDuration);
-                indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
-                mStateAnimation.play(indicatorsAlpha);
-
-                width = revealView.getMeasuredWidth();
-
-                if (material) {
-                    if (!isWidgetTray) {
-                        allAppsButton.setVisibility(View.INVISIBLE);
-                    }
-                    int allAppsButtonSize = LauncherAppState.getInstance().
-                            getDynamicGrid().getDeviceProfile().allAppsButtonVisualSize;
-                    float finalRadius = isWidgetTray ? 0 : allAppsButtonSize / 2;
-                    Animator reveal =
-                            LauncherAnimUtils.createCircularReveal(revealView, width / 2,
-                                    height / 2, revealRadius, finalRadius);
-                    reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
-                    reveal.setDuration(revealDuration);
-                    reveal.setStartDelay(itemsAlphaStagger);
-
-                    reveal.addListener(new AnimatorListenerAdapter() {
-                        public void onAnimationEnd(Animator animation) {
-                            revealView.setVisibility(View.INVISIBLE);
-                            if (!isWidgetTray) {
-                                allAppsButton.setVisibility(View.VISIBLE);
-                            }
-                        }
-                    });
-
-                    mStateAnimation.play(reveal);
-                }
-
-                dispatchOnLauncherTransitionPrepare(fromView, animated, true);
-                dispatchOnLauncherTransitionPrepare(toView, animated, true);
-                mAppsCustomizeContent.stopScrolling();
-            }
-
-            mStateAnimation.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    fromView.setVisibility(View.GONE);
-                    dispatchOnLauncherTransitionEnd(fromView, animated, true);
-                    dispatchOnLauncherTransitionEnd(toView, animated, true);
-                    if (onCompleteRunnable != null) {
-                        onCompleteRunnable.run();
-                    }
-
-                    revealView.setLayerType(View.LAYER_TYPE_NONE, null);
-                    if (page != null) {
-                        page.setLayerType(View.LAYER_TYPE_NONE, null);
-                    }
-                    content.setPageBackgroundsVisible(true);
-                    // Unhide side pages
-                    int count = content.getChildCount();
-                    for (int i = 0; i < count; i++) {
-                        View child = content.getChildAt(i);
-                        child.setVisibility(View.VISIBLE);
-                    }
-
-                    // Reset page transforms
-                    if (page != null) {
-                        page.setTranslationX(0);
-                        page.setTranslationY(0);
-                        page.setAlpha(1);
-                    }
-                    content.setCurrentPage(content.getNextPage());
-
-                    mAppsCustomizeContent.updateCurrentPageScroll();
-
-                    // This can hold unnecessary references to views.
-                    mStateAnimation = null;
-                }
-            });
-
-            final AnimatorSet stateAnimation = mStateAnimation;
-            final Runnable startAnimRunnable = new Runnable() {
-                public void run() {
-                    // Check that mStateAnimation hasn't changed while
-                    // we waited for a layout/draw pass
-                    if (mStateAnimation != stateAnimation)
-                        return;
-                    dispatchOnLauncherTransitionStart(fromView, animated, false);
-                    dispatchOnLauncherTransitionStart(toView, animated, false);
-
-                    if (Utilities.isLmpOrAbove()) {
-                        for (int i = 0; i < layerViews.size(); i++) {
-                            View v = layerViews.get(i);
-                            if (v != null) {
-                                if (Utilities.isViewAttachedToWindow(v)) v.buildLayer();
-                            }
-                        }
-                    }
-                    mStateAnimation.start();
-                }
-            };
-            fromView.post(startAnimRunnable);
-        } else {
-            fromView.setVisibility(View.GONE);
-            dispatchOnLauncherTransitionPrepare(fromView, animated, true);
-            dispatchOnLauncherTransitionStart(fromView, animated, true);
-            dispatchOnLauncherTransitionEnd(fromView, animated, true);
-            dispatchOnLauncherTransitionPrepare(toView, animated, true);
-            dispatchOnLauncherTransitionStart(toView, animated, true);
-            dispatchOnLauncherTransitionEnd(toView, animated, true);
-        }
+        setWorkspaceBackground(visible ? WORKSPACE_BACKGROUND_GRADIENT : WORKSPACE_BACKGROUND_BLACK);
     }
 
     @Override
@@ -3816,25 +3258,42 @@
             SQLiteDatabase.releaseMemory();
 
             // This clears all widget bitmaps from the widget tray
-            if (mAppsCustomizeTabHost != null) {
-                mAppsCustomizeTabHost.trimMemory();
-            }
+            // TODO(hyunyoungs)
+        }
+        if (mLauncherCallbacks != null) {
+            mLauncherCallbacks.onTrimMemory(level);
         }
     }
 
-    protected void showWorkspace(boolean animated) {
-        showWorkspace(animated, null);
+    @Override
+    public void onStateTransitionHideSearchBar() {
+        // Hide the search bar
+        if (mSearchDropTargetBar != null) {
+            mSearchDropTargetBar.hideSearchBar(false /* animated */);
+        }
     }
 
-    protected void showWorkspace() {
-        showWorkspace(true);
+    public void showWorkspace(boolean animated) {
+        showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null);
     }
 
-    void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
-        if (mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL) {
+    public void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
+        showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
+                onCompleteRunnable);
+    }
+
+    protected void showWorkspace(int snapToPage, boolean animated) {
+        showWorkspace(snapToPage, animated, null);
+    }
+
+    void showWorkspace(int snapToPage, boolean animated, Runnable onCompleteRunnable) {
+        boolean changed = mState != State.WORKSPACE ||
+                mWorkspace.getState() != Workspace.State.NORMAL;
+        if (changed) {
             boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
             mWorkspace.setVisibility(View.VISIBLE);
-            hideAppsCustomizeHelper(Workspace.State.NORMAL, animated, false, onCompleteRunnable);
+            mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
+                    snapToPage, animated, onCompleteRunnable);
 
             // Show the search bar (only animate if we were showing the drop target bar in spring
             // loaded mode)
@@ -3853,73 +3312,131 @@
 
         // Resume the auto-advance of widgets
         mUserPresent = true;
-        updateRunning();
+        updateAutoAdvanceState();
 
-        // Send an accessibility event to announce the context change
-        getWindow().getDecorView()
-                .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-
-        onWorkspaceShown(animated);
+        if (changed) {
+            // Send an accessibility event to announce the context change
+            getWindow().getDecorView()
+                    .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        }
     }
 
     void showOverviewMode(boolean animated) {
         mWorkspace.setVisibility(View.VISIBLE);
-        hideAppsCustomizeHelper(Workspace.State.OVERVIEW, animated, false, null);
+        mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW,
+                WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
+                null /* onCompleteRunnable */);
         mState = State.WORKSPACE;
-        onWorkspaceShown(animated);
     }
 
-    public void onWorkspaceShown(boolean animated) {
-    }
-
-    void showAllApps(boolean animated, AppsCustomizePagedView.ContentType contentType,
-                     boolean resetPageToZero) {
-        if (mState != State.WORKSPACE) return;
-
-        if (resetPageToZero) {
-            mAppsCustomizeTabHost.reset();
+    /**
+     * Shows the apps view.
+     */
+    void showAppsView(boolean animated, boolean resetListToTop, boolean updatePredictedApps,
+            boolean focusSearchBar) {
+        if (resetListToTop) {
+            mAppsView.scrollToTop();
         }
-        showAppsCustomizeHelper(animated, false, contentType);
-        mAppsCustomizeTabHost.post(new Runnable() {
+        if (updatePredictedApps) {
+            tryAndUpdatePredictedApps();
+        }
+        showAppsOrWidgets(State.APPS, animated, focusSearchBar);
+    }
+
+    /**
+     * Shows the widgets view.
+     */
+    void showWidgetsView(boolean animated, boolean resetPageToZero) {
+        if (LOGD) Log.d(TAG, "showWidgetsView:" + animated + " resetPageToZero:" + resetPageToZero);
+        if (resetPageToZero) {
+            mWidgetsView.scrollToTop();
+        }
+        showAppsOrWidgets(State.WIDGETS, animated, false);
+
+        mWidgetsView.post(new Runnable() {
             @Override
             public void run() {
-                // We post this in-case the all apps view isn't yet constructed.
-                mAppsCustomizeTabHost.requestFocus();
+                mWidgetsView.requestFocus();
             }
         });
+    }
+
+    /**
+     * Sets up the transition to show the apps/widgets view.
+     *
+     * @return whether the current from and to state allowed this operation
+     */
+    // TODO: calling method should use the return value so that when {@code false} is returned
+    // the workspace transition doesn't fall into invalid state.
+    private boolean showAppsOrWidgets(State toState, boolean animated, boolean focusSearchBar) {
+        if (mState != State.WORKSPACE &&  mState != State.APPS_SPRING_LOADED &&
+                mState != State.WIDGETS_SPRING_LOADED) {
+            return false;
+        }
+        if (toState != State.APPS && toState != State.WIDGETS) {
+            return false;
+        }
+
+        if (toState == State.APPS) {
+            mStateTransitionAnimation.startAnimationToAllApps(animated, focusSearchBar);
+        } else {
+            mStateTransitionAnimation.startAnimationToWidgets(animated);
+        }
 
         // Change the state *after* we've called all the transition code
-        mState = State.APPS_CUSTOMIZE;
+        mState = toState;
 
         // Pause the auto-advance of widgets until we are out of AllApps
         mUserPresent = false;
-        updateRunning();
+        updateAutoAdvanceState();
         closeFolder();
 
         // Send an accessibility event to announce the context change
         getWindow().getDecorView()
                 .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        return true;
     }
 
-    void enterSpringLoadedDragMode() {
-        if (isAllAppsVisible()) {
-            hideAppsCustomizeHelper(Workspace.State.SPRING_LOADED, true, true, null);
-            mState = State.APPS_CUSTOMIZE_SPRING_LOADED;
+    /**
+     * Updates the workspace and interaction state on state change, and return the animation to this
+     * new state.
+     */
+    public Animator startWorkspaceStateChangeAnimation(Workspace.State toState, int toPage,
+            boolean animated, boolean hasOverlaySearchBar, HashMap<View, Integer> layerViews) {
+        Workspace.State fromState = mWorkspace.getState();
+        Animator anim = mWorkspace.setStateWithAnimation(toState, toPage, animated,
+                hasOverlaySearchBar, layerViews);
+        updateInteraction(fromState, toState);
+        return anim;
+    }
+
+    public void enterSpringLoadedDragMode() {
+        if (LOGD) Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s", mState.name()));
+        if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED ||
+                mState == State.WIDGETS_SPRING_LOADED) {
+            return;
         }
+
+        mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED,
+                WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true /* animated */,
+                null /* onCompleteRunnable */);
+        mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
     }
 
-    void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
+    public void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
             final Runnable onCompleteRunnable) {
-        if (mState != State.APPS_CUSTOMIZE_SPRING_LOADED) return;
+        if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
 
         mHandler.postDelayed(new Runnable() {
             @Override
             public void run() {
                 if (successfulDrop) {
+                    // TODO(hyunyoungs): verify if this hack is still needed, if not, delete.
+                    //
                     // Before we show workspace, hide all apps again because
                     // exitSpringLoadedDragMode made it visible. This is a bit hacky; we should
                     // clean up our state transition functions
-                    mAppsCustomizeTabHost.setVisibility(View.GONE);
+                    mWidgetsView.setVisibility(View.GONE);
                     showWorkspace(true, onCompleteRunnable);
                 } else {
                     exitSpringLoadedDragMode();
@@ -3929,13 +3446,25 @@
     }
 
     void exitSpringLoadedDragMode() {
-        if (mState == State.APPS_CUSTOMIZE_SPRING_LOADED) {
-            final boolean animated = true;
-            final boolean springLoaded = true;
-            showAppsCustomizeHelper(animated, springLoaded);
-            mState = State.APPS_CUSTOMIZE;
+        if (mState == State.APPS_SPRING_LOADED) {
+            showAppsView(true /* animated */, false /* resetListToTop */,
+                    false /* updatePredictedApps */, false /* focusSearchBar */);
+        } else if (mState == State.WIDGETS_SPRING_LOADED) {
+            showWidgetsView(true, false);
         }
-        // Otherwise, we are not in spring loaded mode, so don't do anything.
+    }
+
+    /**
+     * Updates the set of predicted apps if it hasn't been updated since the last time Launcher was
+     * resumed.
+     */
+    private void tryAndUpdatePredictedApps() {
+        if (mLauncherCallbacks != null) {
+            List<ComponentKey> apps = mLauncherCallbacks.getPredictedApps();
+            if (apps != null) {
+                mAppsView.setPredictedApps(apps);
+            }
+        }
     }
 
     void lockAllApps() {
@@ -3950,7 +3479,7 @@
         // NO-OP
     }
 
-    public View getQsbBar() {
+    public View getOrCreateQsbBar() {
         if (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()) {
             return mLauncherCallbacks.getQsbBar();
         }
@@ -3994,24 +3523,39 @@
                     .commit();
             }
 
+            mAppWidgetHost.setQsbWidgetId(widgetId);
             if (widgetId != -1) {
                 mQsb = mAppWidgetHost.createView(this, widgetId, searchProvider);
                 mQsb.updateAppWidgetOptions(opts);
                 mQsb.setPadding(0, 0, 0, 0);
                 mSearchDropTargetBar.addView(mQsb);
+                mSearchDropTargetBar.setQsbSearchBar(mQsb);
             }
         }
         return mQsb;
     }
 
+    private void reinflateQSBIfNecessary() {
+        if (mQsb instanceof LauncherAppWidgetHostView &&
+                ((LauncherAppWidgetHostView) mQsb).isReinflateRequired()) {
+            mSearchDropTargetBar.removeView(mQsb);
+            mQsb = null;
+            mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
+        }
+    }
+
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         final boolean result = super.dispatchPopulateAccessibilityEvent(event);
         final List<CharSequence> text = event.getText();
         text.clear();
         // Populate event with a fake title based on the current state.
-        if (mState == State.APPS_CUSTOMIZE) {
-            text.add(mAppsCustomizeTabHost.getContentTag());
+        if (mState == State.APPS) {
+            text.add(getString(R.string.all_apps_button_label));
+        } else if (mState == State.WIDGETS) {
+            text.add(getString(R.string.widget_button_text));
+        } else if (mWorkspace != null) {
+            text.add(mWorkspace.getCurrentPageDescription());
         } else {
             text.add(getString(R.string.all_apps_home_button_label));
         }
@@ -4021,7 +3565,7 @@
     /**
      * Receives notifications when system dialogs are to be closed.
      */
-    private class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
+    @Thunk class CloseSystemDialogsIntentReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             closeSystemDialogs();
@@ -4029,36 +3573,21 @@
     }
 
     /**
-     * Receives notifications whenever the appwidgets are reset.
-     */
-    private class AppWidgetResetObserver extends ContentObserver {
-        public AppWidgetResetObserver() {
-            super(new Handler());
-        }
-
-        @Override
-        public void onChange(boolean selfChange) {
-            onAppWidgetReset();
-        }
-    }
-
-    /**
      * If the activity is currently paused, signal that we need to run the passed Runnable
      * in onResume.
      *
      * This needs to be called from incoming places where resources might have been loaded
-     * while we are paused.  That is becaues the Configuration might be wrong
-     * when we're not running, and if it comes back to what it was when we
-     * were paused, we are not restarted.
+     * while the activity is paused. That is because the Configuration (e.g., rotation)  might be
+     * wrong when we're not running, and if the activity comes back to what the configuration was
+     * when we were paused, activity is not restarted.
      *
      * Implementation of the method from LauncherModel.Callbacks.
      *
-     * @return true if we are currently paused.  The caller might be able to
-     * skip some work in that case since we will come back again.
+     * @return {@code true} if we are currently paused. The caller might be able to skip some work
      */
-    private boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
+    @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
         if (mPaused) {
-            Log.i(TAG, "Deferring update until onResume");
+            if (LOGD) Log.d(TAG, "Deferring update until onResume");
             if (deletePreviousRunnables) {
                 while (mBindOnResumeCallbacks.remove(run)) {
                 }
@@ -4094,7 +3623,7 @@
      */
     public boolean setLoadOnResume() {
         if (mPaused) {
-            Log.i(TAG, "setLoadOnResume");
+            if (LOGD) Log.d(TAG, "setLoadOnResume");
             mOnResumeNeedsLoad = true;
             return true;
         } else {
@@ -4155,10 +3684,6 @@
 
     @Override
     public void bindAddScreens(ArrayList<Long> orderedScreenIds) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - bindAddScreens()", true);
-        Launcher.addDumpLog(TAG, "11683562 -   orderedScreenIds: " +
-                TextUtils.join(", ", orderedScreenIds), true);
         int count = orderedScreenIds.size();
         for (int i = 0; i < count; i++) {
             mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i));
@@ -4221,9 +3746,8 @@
         // Remove the extra empty screen
         mWorkspace.removeExtraEmptyScreen(false, false);
 
-        if (!LauncherAppState.isDisableAllApps() &&
-                addedApps != null && mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.addApps(addedApps);
+        if (addedApps != null && mAppsView != null) {
+            mAppsView.addApps(addedApps);
         }
     }
 
@@ -4339,7 +3863,7 @@
     /**
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindFolders(final HashMap<Long, FolderInfo> folders) {
+    public void bindFolders(final LongArrayMap<FolderInfo> folders) {
         Runnable r = new Runnable() {
             public void run() {
                 bindFolders(folders);
@@ -4348,8 +3872,7 @@
         if (waitUntilResume(r)) {
             return;
         }
-        sFolders.clear();
-        sFolders.putAll(folders);
+        sFolders = folders.clone();
     }
 
     /**
@@ -4373,12 +3896,12 @@
         }
         final Workspace workspace = mWorkspace;
 
-        AppWidgetProviderInfo appWidgetInfo;
+        LauncherAppWidgetProviderInfo appWidgetInfo =
+                LauncherModel.getProviderInfo(this, item.providerName, item.user);
+
         if (!mIsSafeModeEnabled
                 && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0)
                 && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) {
-
-            appWidgetInfo = mModel.findAppWidgetProviderInfoWithComponent(this, item.providerName);
             if (appWidgetInfo == null) {
                 if (DEBUG_WIDGETS) {
                     Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId
@@ -4391,13 +3914,13 @@
             // Note: This assumes that the id remap broadcast is received before this step.
             // If that is not the case, the id remap will be ignored and user may see the
             // click to setup view.
-            PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(appWidgetInfo, null, null);
+            PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null);
             pendingInfo.spanX = item.spanX;
             pendingInfo.spanY = item.spanY;
             pendingInfo.minSpanX = item.minSpanX;
             pendingInfo.minSpanY = item.minSpanY;
-            Bundle options =
-                    AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+            Bundle options = null;
+                    WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
 
             int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
             boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -4428,9 +3951,9 @@
 
         if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
             final int appWidgetId = item.appWidgetId;
-            appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
             if (DEBUG_WIDGETS) {
-                Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider);
+                Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component "
+                        + appWidgetInfo.provider);
             }
 
             item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
@@ -4449,7 +3972,9 @@
 
         workspace.addInScreen(item.hostView, item.container, item.screenId, item.cellX,
                 item.cellY, item.spanX, item.spanY, false);
-        addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+        if (!item.isCustomWidget()) {
+            addWidgetToAutoAdvanceIfNeeded(item.hostView, appWidgetInfo);
+        }
 
         workspace.requestLayout();
 
@@ -4488,10 +4013,10 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void finishBindingItems(final boolean upgradePath) {
+    public void finishBindingItems() {
         Runnable r = new Runnable() {
             public void run() {
-                finishBindingItems(upgradePath);
+                finishBindingItems();
             }
         };
         if (waitUntilResume(r)) {
@@ -4526,14 +4051,10 @@
             sPendingAddItem = null;
         }
 
-        if (upgradePath) {
-            mWorkspace.getUniqueComponents(true, null);
-            mIntentsOnWorkspaceFromUpgradePath = mWorkspace.getUniqueComponents(true, null);
-        }
-        PackageInstallerCompat.getInstance(this).onFinishBind();
+        InstallShortcutReceiver.disableAndFlushInstallQueue(this);
 
         if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.finishBindingItems(upgradePath);
+            mLauncherCallbacks.finishBindingItems(false);
         }
     }
 
@@ -4568,18 +4089,16 @@
                 PropertyValuesHolder.ofFloat("scaleY", 1f));
         bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
         bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
-        bounceAnim.setInterpolator(new SmoothPagedView.OvershootInterpolator());
+        bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
         return bounceAnim;
     }
 
     public boolean useVerticalBarLayout() {
-        return LauncherAppState.getInstance().getDynamicGrid().
-                getDeviceProfile().isVerticalBarLayout();
+        return mDeviceProfile.isVerticalBarLayout();
     }
 
     protected Rect getSearchBarBounds() {
-        return LauncherAppState.getInstance().getDynamicGrid().
-                getDeviceProfile().getSearchBarBounds();
+        return mDeviceProfile.getSearchBarBounds(Utilities.isRtl(getResources()));
     }
 
     public void bindSearchablesChanged() {
@@ -4590,33 +4109,34 @@
             mSearchDropTargetBar.removeView(mQsb);
             mQsb = null;
         }
-        mSearchDropTargetBar.setQsbSearchBar(getQsbBar());
+        mSearchDropTargetBar.setQsbSearchBar(getOrCreateQsbBar());
     }
 
     /**
+     * A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent
+     * multiple calls to bind the same list.)
+     */
+    @Thunk ArrayList<AppInfo> mTmpAppsList;
+    private Runnable mBindAllApplicationsRunnable = new Runnable() {
+        public void run() {
+            bindAllApplications(mTmpAppsList);
+            mTmpAppsList = null;
+        }
+    };
+
+    /**
      * Add the icons for all apps.
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void bindAllApplications(final ArrayList<AppInfo> apps) {
-        if (LauncherAppState.isDisableAllApps()) {
-            if (mIntentsOnWorkspaceFromUpgradePath != null) {
-                if (LauncherModel.UPGRADE_USE_MORE_APPS_FOLDER) {
-                    getHotseat().addAllAppsFolder(mIconCache, apps,
-                            mIntentsOnWorkspaceFromUpgradePath, Launcher.this, mWorkspace);
-                }
-                mIntentsOnWorkspaceFromUpgradePath = null;
-            }
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.onPackagesUpdated(
-                        LauncherModel.getSortedWidgetsAndShortcuts(this));
-            }
-        } else {
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.setApps(apps);
-                mAppsCustomizeContent.onPackagesUpdated(
-                        LauncherModel.getSortedWidgetsAndShortcuts(this));
-            }
+        if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
+            mTmpAppsList = apps;
+            return;
+        }
+
+        if (mAppsView != null) {
+            mAppsView.setApps(apps);
         }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.bindAllApplications(apps);
@@ -4638,9 +4158,8 @@
             return;
         }
 
-        if (!LauncherAppState.isDisableAllApps() &&
-                mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.updateApps(apps);
+        if (mAppsView != null) {
+            mAppsView.updateApps(apps);
         }
     }
 
@@ -4695,22 +4214,17 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     @Override
-    public void updatePackageState(ArrayList<PackageInstallInfo> installInfo) {
-        if (mWorkspace != null) {
-            mWorkspace.updatePackageState(installInfo);
+    public void bindRestoreItemsChange(final HashSet<ItemInfo> updates) {
+        Runnable r = new Runnable() {
+            public void run() {
+                bindRestoreItemsChange(updates);
+            }
+        };
+        if (waitUntilResume(r)) {
+            return;
         }
-    }
 
-    /**
-     * Update the label and icon of all the icons in a package
-     *
-     * Implementation of the method from LauncherModel.Callbacks.
-     */
-    @Override
-    public void updatePackageBadge(String packageName) {
-        if (mWorkspace != null) {
-            mWorkspace.updatePackageBadge(packageName, UserHandleCompat.myUserHandle());
-        }
+        mWorkspace.updateRestoreItems(updates);
     }
 
     /**
@@ -4754,31 +4268,27 @@
         }
 
         // Update AllApps
-        if (!LauncherAppState.isDisableAllApps() &&
-                mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.removeApps(appInfos);
+        if (mAppsView != null) {
+            mAppsView.removeApps(appInfos);
         }
     }
 
-    /**
-     * A number of packages were updated.
-     */
-    private ArrayList<Object> mWidgetsAndShortcuts;
     private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
             public void run() {
-                bindPackagesUpdated(mWidgetsAndShortcuts);
-                mWidgetsAndShortcuts = null;
+                bindAllPackages(mWidgetsModel);
             }
         };
-    public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) {
+
+    @Override
+    public void bindAllPackages(final WidgetsModel model) {
         if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
-            mWidgetsAndShortcuts = widgetsAndShortcuts;
+            mWidgetsModel = model;
             return;
         }
 
-        // Update the widgets pane
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts);
+        if (mWidgetsView != null && model != null) {
+            mWidgetsView.addWidgets(model);
+            mWidgetsModel = null;
         }
     }
 
@@ -4815,13 +4325,18 @@
     }
 
     public void lockScreenOrientation() {
-        if (Utilities.isRotationEnabled(this)) {
-            setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
-                    .getConfiguration().orientation));
+        if (mRotationEnabled) {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+                setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources()
+                        .getConfiguration().orientation));
+            } else {
+                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
+            }
         }
     }
+
     public void unlockScreenOrientation(boolean immediate) {
-        if (Utilities.isRotationEnabled(this)) {
+        if (mRotationEnabled) {
             if (immediate) {
                 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
             } else {
@@ -4984,7 +4499,7 @@
         editor.apply();
     }
 
-    private void showFirstRunClings() {
+    @Thunk void showFirstRunClings() {
         // The two first run cling paths are mutually exclusive, if the launcher is preinstalled
         // on the device, then we always show the first run cling experience (or if there is no
         // launcher2). Otherwise, we prompt the user upon started for migration
@@ -5012,42 +4527,54 @@
         if (mSearchDropTargetBar != null) mSearchDropTargetBar.hideSearchBar(false);
     }
 
+    // TODO: These method should be a part of LauncherSearchCallback
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     public ItemInfo createAppDragInfo(Intent appLaunchIntent) {
-        // Called from search suggestion, not supported in other profiles.
-        final UserHandleCompat myUser = UserHandleCompat.myUserHandle();
+        // Called from search suggestion
+        UserHandleCompat user = null;
+        if (Utilities.isLmpOrAbove()) {
+            UserHandle userHandle = appLaunchIntent.getParcelableExtra(Intent.EXTRA_USER);
+            if (userHandle != null) {
+                user = UserHandleCompat.fromUser(userHandle);
+            }
+        }
+        return createAppDragInfo(appLaunchIntent, user);
+    }
+
+    // TODO: This method should be a part of LauncherSearchCallback
+    public ItemInfo createAppDragInfo(Intent intent, UserHandleCompat user) {
+        if (user == null) {
+            user = UserHandleCompat.myUserHandle();
+        }
+
+        // Called from search suggestion, add the profile extra to the intent to ensure that we
+        // can launch it correctly
         LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(this);
-        LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(appLaunchIntent,
-                myUser);
+        LauncherActivityInfoCompat activityInfo = launcherApps.resolveActivity(intent, user);
         if (activityInfo == null) {
             return null;
         }
-        return new AppInfo(this, activityInfo, myUser, mIconCache, null);
+        return new AppInfo(this, activityInfo, user, mIconCache);
     }
 
+    // TODO: This method should be a part of LauncherSearchCallback
     public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
             Bitmap icon) {
-        // Called from search suggestion, not supported in other profiles.
-        return createShortcutDragInfo(shortcutIntent, caption, icon,
+        return new ShortcutInfo(shortcutIntent, caption, caption, icon,
                 UserHandleCompat.myUserHandle());
     }
 
-    public ItemInfo createShortcutDragInfo(Intent shortcutIntent, CharSequence caption,
-            Bitmap icon, UserHandleCompat user) {
-        UserManagerCompat userManager = UserManagerCompat.getInstance(this);
-        CharSequence contentDescription = userManager.getBadgedLabelForUser(caption, user);
-        return new ShortcutInfo(shortcutIntent, caption, contentDescription, icon, user);
-    }
-
-    protected void moveWorkspaceToDefaultScreen() {
-        mWorkspace.moveToDefaultScreen(false);
-    }
-
+    // TODO: This method should be a part of LauncherSearchCallback
     public void startDrag(View dragView, ItemInfo dragInfo, DragSource source) {
         dragView.setTag(dragInfo);
         mWorkspace.onExternalDragStartedWithItem(dragView);
         mWorkspace.beginExternalDragShared(dragView, source);
     }
 
+    protected void moveWorkspaceToDefaultScreen() {
+        mWorkspace.moveToDefaultScreen(false);
+    }
+
     @Override
     public void onPageSwitch(View newPage, int newPageIndex) {
         if (mLauncherCallbacks != null) {
@@ -5056,6 +4583,23 @@
     }
 
     /**
+     * Returns a FastBitmapDrawable with the icon, accurately sized.
+     */
+    public FastBitmapDrawable createIconDrawable(Bitmap icon) {
+        FastBitmapDrawable d = new FastBitmapDrawable(icon);
+        d.setFilterBitmap(true);
+        resizeIconDrawable(d);
+        return d;
+    }
+
+    /**
+     * Resizes an icon drawable to the correct icon size.
+     */
+    public void resizeIconDrawable(Drawable icon) {
+        icon.setBounds(0, 0, mDeviceProfile.iconSizePx, mDeviceProfile.iconSizePx);
+    }
+
+    /**
      * Prints out out state for debugging.
      */
     public void dumpState() {
@@ -5067,10 +4611,8 @@
         Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState);
         Log.d(TAG, "sFolders.size=" + sFolders.size());
         mModel.dumpState();
+        // TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState();
 
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.dumpState();
-        }
         Log.d(TAG, "END launcher3 dump state");
     }
 
@@ -5125,6 +4667,14 @@
         }
     }
 
+    public static CustomAppWidget getCustomAppWidget(String name) {
+        return sCustomAppWidgets.get(name);
+    }
+
+    public static HashMap<String, CustomAppWidget> getCustomAppWidgets() {
+        return sCustomAppWidgets;
+    }
+
     public void dumpLogsToLocalData() {
         if (DEBUG_DUMP_LOG) {
             new AsyncTask<Void, Void, Void>() {
@@ -5173,14 +4723,6 @@
     }
 }
 
-interface LauncherTransitionable {
-    View getContent();
-    void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace);
-    void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace);
-    void onLauncherTransitionStep(Launcher l, float t);
-    void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace);
-}
-
 interface DebugIntents {
     static final String DELETE_DATABASE = "com.android.launcher3.action.DELETE_DATABASE";
     static final String MIGRATE_DATABASE = "com.android.launcher3.action.MIGRATE_DATABASE";
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index be295f8..6a248a3 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -21,10 +21,14 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.os.Build;
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewTreeObserver;
 
+import com.android.launcher3.util.UiThreadCircularReveal;
+
 import java.util.HashSet;
 import java.util.WeakHashMap;
 
@@ -128,13 +132,12 @@
         return anim;
     }
 
-    public static Animator createCircularReveal(View view, int centerX,
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static ValueAnimator createCircularReveal(View view, int centerX,
             int centerY, float startRadius, float endRadius) {
-        Animator anim = ViewAnimationUtils.createCircularReveal(view, centerX,
+        ValueAnimator anim = UiThreadCircularReveal.createCircularReveal(view, centerX,
                 centerY, startRadius, endRadius);
-        if (anim instanceof ValueAnimator) {
-            new FirstFrameAnimatorHelper((ValueAnimator) anim, view);
-        }
+        new FirstFrameAnimatorHelper(anim, view);
         return anim;
     }
 }
diff --git a/src/com/android/launcher3/LauncherAnimatorUpdateListener.java b/src/com/android/launcher3/LauncherAnimatorUpdateListener.java
deleted file mode 100644
index ec9fd4d..0000000
--- a/src/com/android/launcher3/LauncherAnimatorUpdateListener.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-
-abstract class LauncherAnimatorUpdateListener implements AnimatorUpdateListener {
-    public void onAnimationUpdate(ValueAnimator animation) {
-        final float b = (Float) animation.getAnimatedValue();
-        final float a = 1f - b;
-        onAnimationUpdate(a, b);
-    }
-
-    abstract void onAnimationUpdate(float a, float b);
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b7c45a3..0b7b1fd 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,44 +16,28 @@
 
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
 import android.app.SearchManager;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.database.ContentObserver;
-import android.graphics.Point;
-import android.os.Build;
-import android.os.Handler;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.Display;
-import android.view.WindowManager;
+
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.compat.LauncherAppsCompat;
 import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
+import com.android.launcher3.util.Thunk;
+
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
 
-public class LauncherAppState implements DeviceProfile.DeviceProfileCallbacks {
-    private static final String TAG = "LauncherAppState";
-
-    private static final boolean DEBUG = false;
+public class LauncherAppState {
 
     private final AppFilter mAppFilter;
     private final BuildInfo mBuildInfo;
-    private final LauncherModel mModel;
+    @Thunk final LauncherModel mModel;
     private final IconCache mIconCache;
+    private final WidgetPreviewLoader mWidgetCache;
 
-    private final boolean mIsScreenLarge;
-    private final float mScreenDensity;
-    private final int mLongPressTimeout = 300;
-
-    private WidgetPreviewLoader.CacheDb mWidgetPreviewCacheDb;
     private boolean mWallpaperChangedSinceLastCheck;
 
     private static WeakReference<LauncherProvider> sLauncherProvider;
@@ -61,7 +45,9 @@
 
     private static LauncherAppState INSTANCE;
 
-    private DynamicGrid mDynamicGrid;
+    private InvariantDeviceProfile mInvariantDeviceProfile;
+
+    private LauncherAccessibilityDelegate mAccessibilityDelegate;
 
     public static LauncherAppState getInstance() {
         if (INSTANCE == null) {
@@ -96,42 +82,26 @@
             MemoryTracker.startTrackingMe(sContext, "L");
         }
 
-        // set sIsScreenXLarge and mScreenDensity *before* creating icon cache
-        mIsScreenLarge = isScreenLarge(sContext.getResources());
-        mScreenDensity = sContext.getResources().getDisplayMetrics().density;
-
-        recreateWidgetPreviewDb();
-        mIconCache = new IconCache(sContext);
+        mInvariantDeviceProfile = new InvariantDeviceProfile(sContext);
+        mIconCache = new IconCache(sContext, mInvariantDeviceProfile);
+        mWidgetCache = new WidgetPreviewLoader(sContext, mIconCache);
 
         mAppFilter = AppFilter.loadByName(sContext.getString(R.string.app_filter_class));
         mBuildInfo = BuildInfo.loadByName(sContext.getString(R.string.build_info_class));
         mModel = new LauncherModel(this, mIconCache, mAppFilter);
-        final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext);
-        launcherApps.addOnAppsChangedCallback(mModel);
+
+        LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
 
         // Register intent receivers
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
-        sContext.registerReceiver(mModel, filter);
-        filter = new IntentFilter();
         filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
-        sContext.registerReceiver(mModel, filter);
-        filter = new IntentFilter();
         filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
+        // For handling managed profiles
+        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED);
+        filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED);
+
         sContext.registerReceiver(mModel, filter);
-
-        // Register for changes to the favorites
-        ContentResolver resolver = sContext.getContentResolver();
-        resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true,
-                mFavoritesObserver);
-    }
-
-    public void recreateWidgetPreviewDb() {
-        if (mWidgetPreviewCacheDb != null) {
-            mWidgetPreviewCacheDb.close();
-        }
-        mWidgetPreviewCacheDb = new WidgetPreviewLoader.CacheDb(sContext);
     }
 
     /**
@@ -142,45 +112,37 @@
         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(sContext);
         launcherApps.removeOnAppsChangedCallback(mModel);
         PackageInstallerCompat.getInstance(sContext).onStop();
-
-        ContentResolver resolver = sContext.getContentResolver();
-        resolver.unregisterContentObserver(mFavoritesObserver);
     }
 
     /**
-     * Receives notifications whenever the user favorites have changed.
+     * Reloads the workspace items from the DB and re-binds the workspace. This should generally
+     * not be called as DB updates are automatically followed by UI update
      */
-    private final ContentObserver mFavoritesObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            // If the database has ever changed, then we really need to force a reload of the
-            // workspace on the next load
-            mModel.resetLoadedState(false, true);
-            mModel.startLoaderFromBackground();
-        }
-    };
+    public void reloadWorkspace() {
+        mModel.resetLoadedState(false, true);
+        mModel.startLoaderFromBackground();
+    }
 
     LauncherModel setLauncher(Launcher launcher) {
+        getLauncherProvider().setLauncherProviderChangeListener(launcher);
         mModel.initialize(launcher);
+        mAccessibilityDelegate = ((launcher != null) && Utilities.isLmpOrAbove()) ?
+            new LauncherAccessibilityDelegate(launcher) : null;
         return mModel;
     }
 
+    public LauncherAccessibilityDelegate getAccessibilityDelegate() {
+        return mAccessibilityDelegate;
+    }
+
     public IconCache getIconCache() {
         return mIconCache;
     }
 
-    LauncherModel getModel() {
+    public LauncherModel getModel() {
         return mModel;
     }
 
-    boolean shouldShowAppOrWidgetProvider(ComponentName componentName) {
-        return mAppFilter == null || mAppFilter.shouldShowApp(componentName);
-    }
-
-    WidgetPreviewLoader.CacheDb getWidgetPreviewCacheDb() {
-        return mWidgetPreviewCacheDb;
-    }
-
     static void setLauncherProvider(LauncherProvider provider) {
         sLauncherProvider = new WeakReference<LauncherProvider>(provider);
     }
@@ -193,71 +155,10 @@
         return LauncherFiles.SHARED_PREFERENCES_KEY;
     }
 
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    DeviceProfile initDynamicGrid(Context context) {
-        mDynamicGrid = createDynamicGrid(context, mDynamicGrid);
-        mDynamicGrid.getDeviceProfile().addCallback(this);
-        return mDynamicGrid.getDeviceProfile();
+    public WidgetPreviewLoader getWidgetCache() {
+        return mWidgetCache;
     }
-
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
-    static DynamicGrid createDynamicGrid(Context context, DynamicGrid dynamicGrid) {
-        // Determine the dynamic grid properties
-        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        Display display = wm.getDefaultDisplay();
-
-        Point realSize = new Point();
-        display.getRealSize(realSize);
-        DisplayMetrics dm = new DisplayMetrics();
-        display.getMetrics(dm);
-
-        if (dynamicGrid == null) {
-            Point smallestSize = new Point();
-            Point largestSize = new Point();
-            display.getCurrentSizeRange(smallestSize, largestSize);
-
-            dynamicGrid = new DynamicGrid(context,
-                    context.getResources(),
-                    Math.min(smallestSize.x, smallestSize.y),
-                    Math.min(largestSize.x, largestSize.y),
-                    realSize.x, realSize.y,
-                    dm.widthPixels, dm.heightPixels);
-        }
-
-        // Update the icon size
-        DeviceProfile grid = dynamicGrid.getDeviceProfile();
-        grid.updateFromConfiguration(context, context.getResources(),
-                realSize.x, realSize.y,
-                dm.widthPixels, dm.heightPixels);
-        return dynamicGrid;
-    }
-
-    public DynamicGrid getDynamicGrid() {
-        return mDynamicGrid;
-    }
-
-    public boolean isScreenLarge() {
-        return mIsScreenLarge;
-    }
-
-    // Need a version that doesn't require an instance of LauncherAppState for the wallpaper picker
-    public static boolean isScreenLarge(Resources res) {
-        return res.getBoolean(R.bool.is_large_tablet);
-    }
-
-    public static boolean isScreenLandscape(Context context) {
-        return context.getResources().getConfiguration().orientation ==
-            Configuration.ORIENTATION_LANDSCAPE;
-    }
-
-    public float getScreenDensity() {
-        return mScreenDensity;
-    }
-
-    public int getLongPressTimeout() {
-        return mLongPressTimeout;
-    }
-
+    
     public void onWallpaperChanged() {
         mWallpaperChangedSinceLastCheck = true;
     }
@@ -268,29 +169,11 @@
         return result;
     }
 
-    @Override
-    public void onAvailableSizeChanged(DeviceProfile grid) {
-        Utilities.setIconSize(grid.iconSizePx);
-    }
-
-    public static boolean isDisableAllApps() {
-        // Returns false on non-dogfood builds.
-        return getInstance().mBuildInfo.isDogfoodBuild() &&
-                Utilities.isPropertyEnabled(Launcher.DISABLE_ALL_APPS_PROPERTY);
+    public InvariantDeviceProfile getInvariantDeviceProfile() {
+        return mInvariantDeviceProfile;
     }
 
     public static boolean isDogfoodBuild() {
         return getInstance().mBuildInfo.isDogfoodBuild();
     }
-
-    public void setPackageState(ArrayList<PackageInstallInfo> installInfo) {
-        mModel.setPackageState(installInfo);
-    }
-
-    /**
-     * Updates the icons and label of all icons for the provided package name.
-     */
-    public void updatePackageBadge(String packageName) {
-        mModel.updatePackageBadge(packageName);
-    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java
index a309f26..de7c610 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHost.java
@@ -21,9 +21,12 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.os.TransactionTooLargeException;
+import android.view.LayoutInflater;
+import android.view.View;
 
 import java.util.ArrayList;
 
+
 /**
  * Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
  * which correctly captures all long-press events. This ensures that users can
@@ -33,16 +36,31 @@
 
     private final ArrayList<Runnable> mProviderChangeListeners = new ArrayList<Runnable>();
 
-    Launcher mLauncher;
+    private int mQsbWidgetId = -1;
+    private Launcher mLauncher;
 
     public LauncherAppWidgetHost(Launcher launcher, int hostId) {
         super(launcher, hostId);
         mLauncher = launcher;
     }
 
+    public void setQsbWidgetId(int widgetId) {
+        mQsbWidgetId = widgetId;
+    }
+
     @Override
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
+        if (appWidgetId == mQsbWidgetId) {
+            return new LauncherAppWidgetHostView(context) {
+
+                @Override
+                protected View getErrorView() {
+                    // For the QSB, show an empty view instead of an error view.
+                    return new View(getContext());
+                }
+            };
+        }
         return new LauncherAppWidgetHostView(context);
     }
 
@@ -77,12 +95,37 @@
     }
 
     protected void onProvidersChanged() {
-        // Once we get the message that widget packages are updated, we need to rebind items
-        // in AppsCustomize accordingly.
-        mLauncher.bindPackagesUpdated(LauncherModel.getSortedWidgetsAndShortcuts(mLauncher));
-
-        for (Runnable callback : mProviderChangeListeners) {
-            callback.run();
+        mLauncher.getModel().loadAndBindWidgetsAndShortcuts(mLauncher, mLauncher,
+                true /* refresh */);
+        if (!mProviderChangeListeners.isEmpty()) {
+            for (Runnable callback : new ArrayList<>(mProviderChangeListeners)) {
+                callback.run();
+            }
         }
     }
+
+    public AppWidgetHostView createView(Context context, int appWidgetId,
+            LauncherAppWidgetProviderInfo appWidget) {
+        if (appWidget.isCustomWidget) {
+            LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
+            LayoutInflater inflater = (LayoutInflater)
+                    context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            inflater.inflate(appWidget.initialLayout, lahv);
+            lahv.setAppWidget(0, appWidget);
+            lahv.updateLastInflationOrientation();
+            return lahv;
+        } else {
+            return super.createView(context, appWidgetId, appWidget);
+        }
+    }
+
+    /**
+     * Called when the AppWidget provider for a AppWidget has been upgraded to a new apk.
+     */
+    @Override
+    protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidget) {
+        LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
+                mLauncher, appWidget);
+        super.onProviderChanged(appWidgetId, info);
+    }
 }
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index e39727b..cf461a5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -35,6 +36,7 @@
     LayoutInflater mInflater;
 
     private CheckLongPressHelper mLongPressHelper;
+    private StylusEventHelper mStylusEventHelper;
     private Context mContext;
     private int mPreviousOrientation;
     private DragLayer mDragLayer;
@@ -45,8 +47,10 @@
         super(context);
         mContext = context;
         mLongPressHelper = new CheckLongPressHelper(this);
+        mStylusEventHelper = new StylusEventHelper(this);
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mDragLayer = ((Launcher) context).getDragLayer();
+        setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
     }
 
     @Override
@@ -54,10 +58,14 @@
         return mInflater.inflate(R.layout.appwidget_error, this, false);
     }
 
+    public void updateLastInflationOrientation() {
+        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
+    }
+
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
         // Store the orientation in which the widget was inflated
-        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
+        updateLastInflationOrientation();
         super.updateAppWidget(remoteViews);
     }
 
@@ -83,11 +91,17 @@
             return true;
         }
 
-        // Watch for longpress events at this level to make sure
-        // users can always pick up this widget
+        // Watch for longpress or stylus button press events at this level to
+        // make sure users can always pick up this widget
+        if (mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            mLongPressHelper.cancelLongPress();
+            return true;
+        }
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN: {
-                mLongPressHelper.postCheckForLongPress();
+                if (!mStylusEventHelper.inStylusButtonPressed()) {
+                    mLongPressHelper.postCheckForLongPress();
+                }
                 mDragLayer.setTouchCompleteListener(this);
                 break;
             }
@@ -137,6 +151,20 @@
     }
 
     @Override
+    public AppWidgetProviderInfo getAppWidgetInfo() {
+        AppWidgetProviderInfo info = super.getAppWidgetInfo();
+        if (info != null && !(info instanceof LauncherAppWidgetProviderInfo)) {
+            throw new IllegalStateException("Launcher widget must have"
+                    + " LauncherAppWidgetProviderInfo");
+        }
+        return info;
+    }
+
+    public LauncherAppWidgetProviderInfo getLauncherAppWidgetProviderInfo() {
+        return (LauncherAppWidgetProviderInfo) getAppWidgetInfo();
+    }
+
+    @Override
     public void onTouchComplete() {
         if (!mLongPressHelper.hasPerformedLongPress()) {
             // If a long press has been performed, we don't want to clear the record of that since
diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java
index 5c6535a..aad18b5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java
@@ -56,6 +56,11 @@
     static final int NO_ID = -1;
 
     /**
+     * Indicates that this is a locally defined widget and hence has no system allocated id.
+     */
+    static final int CUSTOM_WIDGET_ID = -100;
+
+    /**
      * Identifier for this widget when talking with
      * {@link android.appwidget.AppWidgetManager} for updates.
      */
@@ -86,7 +91,12 @@
     AppWidgetHostView hostView = null;
 
     LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
-        itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+        if (appWidgetId == CUSTOM_WIDGET_ID) {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+        } else {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+        }
+
         this.appWidgetId = appWidgetId;
         this.providerName = providerName;
 
@@ -99,6 +109,10 @@
         restoreStatus = RESTORE_COMPLETED;
     }
 
+    public boolean isCustomWidget() {
+        return appWidgetId == CUSTOM_WIDGET_ID;
+    }
+
     @Override
     void onAddToDatabase(Context context, ContentValues values) {
         super.onAddToDatabase(context, values);
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
new file mode 100644
index 0000000..85af92f
--- /dev/null
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -0,0 +1,113 @@
+package com.android.launcher3;
+
+import android.annotation.TargetApi;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Parcel;
+
+/**
+ * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords
+ * a common object for describing both framework provided AppWidgets as well as custom widgets
+ * (who's implementation is owned by the launcher). This object represents a widget type / class,
+ * as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo}
+ */
+public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
+
+    public boolean isCustomWidget = false;
+
+    private int mSpanX = -1;
+    private int mSpanY = -1;
+    private int mMinSpanX = -1;
+    private int mMinSpanY = -1;
+
+    public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
+            AppWidgetProviderInfo info) {
+
+        // In lieu of a public super copy constructor, we first write the AppWidgetProviderInfo
+        // into a parcel, and then construct a new LauncherAppWidgetProvider info from the
+        // associated super parcel constructor. This allows us to copy non-public members without
+        // using reflection.
+        Parcel p = Parcel.obtain();
+        info.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        LauncherAppWidgetProviderInfo lawpi = new LauncherAppWidgetProviderInfo(p);
+        p.recycle();
+        return lawpi;
+    }
+
+    public LauncherAppWidgetProviderInfo(Parcel in) {
+        super(in);
+    }
+
+    public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) {
+        isCustomWidget = true;
+
+        provider = new ComponentName(context, widget.getClass().getName());
+        icon = widget.getIcon();
+        label = widget.getLabel();
+        previewImage = widget.getPreviewImage();
+        initialLayout = widget.getWidgetLayout();
+        resizeMode = widget.getResizeMode();
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public String getLabel(PackageManager packageManager) {
+        if (isCustomWidget) {
+            return Utilities.trim(label);
+        }
+        return super.loadLabel(packageManager);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public Drawable getIcon(Context context, IconCache cache) {
+        if (isCustomWidget) {
+            return cache.getFullResIcon(provider.getPackageName(), icon);
+        }
+        return super.loadIcon(context,
+                LauncherAppState.getInstance().getInvariantDeviceProfile().fillResIconDpi);
+    }
+
+    public String toString(PackageManager pm) {
+        if (isCustomWidget) {
+            return "WidgetProviderInfo(" + provider + ")";
+        }
+        return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s",
+                provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm));
+    }
+
+    public int getSpanX(Launcher launcher) {
+        lazyLoadSpans(launcher);
+        return mSpanX;
+    }
+
+    public int getSpanY(Launcher launcher) {
+        lazyLoadSpans(launcher);
+        return mSpanY;
+    }
+
+    public int getMinSpanX(Launcher launcher) {
+        lazyLoadSpans(launcher);
+        return mMinSpanX;
+    }
+
+    public int getMinSpanY(Launcher launcher) {
+        lazyLoadSpans(launcher);
+        return mMinSpanY;
+    }
+
+    private void lazyLoadSpans(Launcher launcher) {
+        if (mSpanX < 0 || mSpanY < 0 || mMinSpanX < 0 || mMinSpanY < 0) {
+            int[] minResizeSpan = launcher.getMinSpanForWidget(this);
+            int[] span = launcher.getSpanForWidget(this);
+
+            mSpanX = span[0];
+            mSpanY = span[1];
+            mMinSpanX = minResizeSpan[0];
+            mMinSpanY = minResizeSpan[1];
+        }
+    }
+ }
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
deleted file mode 100644
index 8b179f1..0000000
--- a/src/com/android/launcher3/LauncherApplication.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.app.Application;
-
-public class LauncherApplication extends Application {
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        LauncherAppState.setApplicationContext(this);
-        LauncherAppState.getInstance();
-    }
-
-    @Override
-    public void onTerminate() {
-        super.onTerminate();
-        LauncherAppState.getInstance().onTerminate();
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java
index 3868a57..a92a889 100644
--- a/src/com/android/launcher3/LauncherBackupAgentHelper.java
+++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java
@@ -32,7 +32,7 @@
 
     private static final String LAUNCHER_DATA_PREFIX = "L";
 
-    static final boolean VERBOSE = true;
+    static final boolean VERBOSE = false;
     static final boolean DEBUG = false;
 
     private static BackupManager sBackupManager;
@@ -78,7 +78,7 @@
             super.onRestore(data, appVersionCode, newState);
             // If no favorite was migrated, clear the data and start fresh.
             final Cursor c = getContentResolver().query(
-                    LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, null, null, null, null);
+                    LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
             hasData = c.moveToNext();
             c.close();
         } catch (Exception e) {
@@ -90,6 +90,12 @@
         if (hasData && mHelper.restoreSuccessful) {
             LauncherAppState.getLauncherProvider().clearFlagEmptyDbCreated();
             LauncherClings.synchonouslyMarkFirstRunClingDismissed(this);
+
+            // TODO: Update the backup set to include rank.
+            if (mHelper.restoredBackupVersion <= 3) {
+                LauncherAppState.getLauncherProvider().updateFolderItemsRank();
+                LauncherAppState.getLauncherProvider().convertShortcutsToLauncherActivities();
+            }
         } else {
             if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB");
             LauncherAppState.getLauncherProvider().createEmptyDB();
diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java
index 4374347..8c6fedb 100644
--- a/src/com/android/launcher3/LauncherBackupHelper.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -19,14 +19,16 @@
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupHelper;
 import android.app.backup.BackupManager;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.res.XmlResourceParser;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -49,18 +51,20 @@
 import com.android.launcher3.backup.BackupProtos.Widget;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.Thunk;
 import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
 import com.google.protobuf.nano.MessageNano;
 
-import java.io.ByteArrayOutputStream;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.HashSet;
-import java.util.List;
 import java.util.zip.CRC32;
 
 /**
@@ -71,7 +75,7 @@
     private static final boolean VERBOSE = LauncherBackupAgentHelper.VERBOSE;
     private static final boolean DEBUG = LauncherBackupAgentHelper.DEBUG;
 
-    private static final int BACKUP_VERSION = 2;
+    private static final int BACKUP_VERSION = 3;
     private static final int MAX_JOURNAL_SIZE = 1000000;
 
     // Journal key is such that it is always smaller than any dynamically generated
@@ -84,11 +88,6 @@
     /** widgets contain previews, which are very large, dribble them out */
     private static final int MAX_WIDGETS_PER_PASS = 5;
 
-    private static final int IMAGE_COMPRESSION_QUALITY = 75;
-
-    private static final Bitmap.CompressFormat IMAGE_FORMAT =
-            android.graphics.Bitmap.CompressFormat.PNG;
-
     private static final String[] FAVORITE_PROJECTION = {
         Favorites._ID,                     // 0
         Favorites.MODIFIED,                // 1
@@ -136,24 +135,33 @@
 
     private static final int SCREEN_RANK_INDEX = 2;
 
-    private final Context mContext;
+    @Thunk final Context mContext;
     private final HashSet<String> mExistingKeys;
     private final ArrayList<Key> mKeys;
+    private final ItemTypeMatcher[] mItemTypeMatchers;
+    private final long mUserSerial;
 
-    private IconCache mIconCache;
     private BackupManager mBackupManager;
-    private HashMap<ComponentName, AppWidgetProviderInfo> mWidgetMap;
     private byte[] mBuffer = new byte[512];
     private long mLastBackupRestoreTime;
+    private boolean mBackupDataWasUpdated;
 
-    private DeviceProfieData mCurrentProfile;
+    private IconCache mIconCache;
+    private DeviceProfieData mDeviceProfileData;
+    private InvariantDeviceProfile mIdp;
+
     boolean restoreSuccessful;
+    int restoredBackupVersion = 1;
 
     public LauncherBackupHelper(Context context) {
         mContext = context;
         mExistingKeys = new HashSet<String>();
         mKeys = new ArrayList<Key>();
         restoreSuccessful = true;
+        mItemTypeMatchers = new ItemTypeMatcher[CommonAppTypeParser.SUPPORTED_TYPE_COUNT];
+
+        UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+        mUserSerial = userManager.getSerialNumberForUser(UserHandleCompat.myUserHandle());
     }
 
     private void dataChanged() {
@@ -171,6 +179,7 @@
                 mExistingKeys.add(keyToBackupKey(key));
             }
         }
+        restoredBackupVersion = journal.backupVersion;
     }
 
     /**
@@ -191,10 +200,19 @@
 
         Journal in = readJournal(oldState);
         if (!launcherIsReady()) {
+            dataChanged();
             // Perform backup later.
             writeJournal(newState, in);
             return;
         }
+
+        if (mDeviceProfileData == null) {
+            LauncherAppState app = LauncherAppState.getInstance();
+            mIdp = app.getInvariantDeviceProfile();
+            mDeviceProfileData = initDeviceProfileData(mIdp);
+            mIconCache = app.getIconCache();
+        }
+
         Log.v(TAG, "lastBackupTime = " + in.t);
         mKeys.clear();
         applyJournal(in);
@@ -202,7 +220,7 @@
         // Record the time before performing backup so that entries edited while the backup
         // was going on, do not get missed in next backup.
         long newBackupTime = System.currentTimeMillis();
-
+        mBackupDataWasUpdated = false;
         try {
             backupFavorites(data);
             backupScreens(data);
@@ -220,16 +238,30 @@
             for (String deleted: mExistingKeys) {
                 if (VERBOSE) Log.v(TAG, "dropping deleted item " + deleted);
                 data.writeEntityHeader(deleted, -1);
+                mBackupDataWasUpdated = true;
             }
 
             mExistingKeys.clear();
-            mLastBackupRestoreTime = newBackupTime;
+            if (!mBackupDataWasUpdated) {
+                // Check if any metadata has changed
+                mBackupDataWasUpdated = (in.profile == null)
+                        || !Arrays.equals(DeviceProfieData.toByteArray(in.profile),
+                            DeviceProfieData.toByteArray(mDeviceProfileData))
+                        || (in.backupVersion != BACKUP_VERSION)
+                        || (in.appVersion != getAppVersion());
+            }
 
-            // We store the journal at two places.
-            //   1) Storing it in newState allows us to do partial backups by comparing old state
-            //   2) Storing it in backup data allows us to validate keys during restore
-            Journal state = getCurrentStateJournal();
-            writeRowToBackup(JOURNAL_KEY, state, data);
+            if (mBackupDataWasUpdated) {
+                mLastBackupRestoreTime = newBackupTime;
+
+                // We store the journal at two places.
+                //   1) Storing it in newState allows us to do partial backups by comparing old state
+                //   2) Storing it in backup data allows us to validate keys during restore
+                Journal state = getCurrentStateJournal();
+                writeRowToBackup(JOURNAL_KEY, state, data);
+            } else {
+                if (DEBUG) Log.d(TAG, "Nothing was written during backup");
+            }
         } catch (IOException e) {
             Log.e(TAG, "launcher backup has failed", e);
         }
@@ -242,8 +274,7 @@
      * to this device.
      */
     private boolean isBackupCompatible(Journal oldState) {
-        DeviceProfieData currentProfile = getDeviceProfieData();
-
+        DeviceProfieData currentProfile = mDeviceProfileData;
         DeviceProfieData oldProfile = oldState.profile;
 
         if (oldProfile == null || oldProfile.desktopCols == 0) {
@@ -277,6 +308,14 @@
             return;
         }
 
+        if (mDeviceProfileData == null) {
+            // This call does not happen on a looper thread. So LauncherAppState
+            // can't be created . Instead initialize required dependencies directly.
+            mIdp = new InvariantDeviceProfile(mContext);
+            mDeviceProfileData = initDeviceProfileData(mIdp);
+            mIconCache = new IconCache(mContext, mIdp);
+        }
+
         int dataSize = data.size();
         if (mBuffer.length < dataSize) {
             mBuffer = new byte[dataSize];
@@ -351,7 +390,7 @@
         journal.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]);
         journal.appVersion = getAppVersion();
         journal.backupVersion = BACKUP_VERSION;
-        journal.profile = getDeviceProfieData();
+        journal.profile = mDeviceProfileData;
         return journal;
     }
 
@@ -364,23 +403,13 @@
         }
     }
 
-    /**
-     * @return the current device profile information.
-     */
-    private DeviceProfieData getDeviceProfieData() {
-        if (mCurrentProfile != null) {
-            return mCurrentProfile;
-        }
-        final Context applicationContext = mContext.getApplicationContext();
-        DeviceProfile profile = LauncherAppState.createDynamicGrid(applicationContext, null)
-                .getDeviceProfile();
-
-        mCurrentProfile = new DeviceProfieData();
-        mCurrentProfile.desktopRows = profile.numRows;
-        mCurrentProfile.desktopCols = profile.numColumns;
-        mCurrentProfile.hotseatCount = profile.numHotseatIcons;
-        mCurrentProfile.allappsRank = profile.hotseatAllAppsRank;
-        return mCurrentProfile;
+    private DeviceProfieData initDeviceProfileData(InvariantDeviceProfile profile) {
+        DeviceProfieData data = new DeviceProfieData();
+        data.desktopRows = profile.numRows;
+        data.desktopCols = profile.numColumns;
+        data.hotseatCount = profile.numHotseatIcons;
+        data.allappsRank = profile.hotseatAllAppsRank;
+        return data;
     }
 
     /**
@@ -430,7 +459,7 @@
 
         ContentResolver cr = mContext.getContentResolver();
         ContentValues values = unpackFavorite(buffer, dataSize);
-        cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values);
+        cr.insert(Favorites.CONTENT_URI, values);
     }
 
     /**
@@ -491,11 +520,6 @@
      */
     private void backupIcons(BackupDataOutput data) throws IOException {
         // persist icons that haven't been persisted yet
-        if (!initializeIconCache()) {
-            dataChanged(); // try again later
-            if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup");
-            return;
-        }
         final ContentResolver cr = mContext.getContentResolver();
         final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
         final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle();
@@ -579,7 +603,8 @@
             Log.w(TAG, "failed to unpack icon for " + key.name);
         }
         if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name);
-        IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi);
+        mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi,
+                "" /* label */, mUserSerial);
     }
 
     /**
@@ -591,17 +616,8 @@
      */
     private void backupWidgets(BackupDataOutput data) throws IOException {
         // persist static widget info that hasn't been persisted yet
-        final LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
-        if (appState == null || !initializeIconCache()) {
-            Log.w(TAG, "Failed to get icon cache during restore");
-            return;
-        }
         final ContentResolver cr = mContext.getContentResolver();
-        final WidgetPreviewLoader previewLoader = new WidgetPreviewLoader(mContext);
-        final PagedViewCellLayout widgetSpacingLayout = new PagedViewCellLayout(mContext);
         final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
-        final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile();
-        if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx);
         int backupWidgetCount = 0;
 
         String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND "
@@ -613,8 +629,6 @@
             while(cursor.moveToNext()) {
                 final long id = cursor.getLong(ID_INDEX);
                 final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX);
-                final int spanX = cursor.getInt(SPANX_INDEX);
-                final int spanY = cursor.getInt(SPANY_INDEX);
                 final ComponentName provider = ComponentName.unflattenFromString(providerName);
                 Key key = null;
                 String backupKey = null;
@@ -624,7 +638,7 @@
                 } else {
                     Log.w(TAG, "empty intent on appwidget: " + id);
                 }
-                if (mExistingKeys.contains(backupKey)) {
+                if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= BACKUP_VERSION) {
                     if (DEBUG) Log.d(TAG, "already saved widget " + backupKey);
 
                     // remember that we already backed this up previously
@@ -633,9 +647,8 @@
                     if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount);
                     if (backupWidgetCount < MAX_WIDGETS_PER_PASS) {
                         if (DEBUG) Log.d(TAG, "saving widget " + backupKey);
-                        previewLoader.setPreviewSize(spanX * profile.cellWidthPx,
-                                spanY * profile.cellHeightPx, widgetSpacingLayout);
-                        writeRowToBackup(key, packWidget(dpi, previewLoader, mIconCache, provider), data);
+                        UserHandleCompat user = UserHandleCompat.myUserHandle();
+                        writeRowToBackup(key, packWidget(dpi, provider, user), data);
                         mKeys.add(key);
                         backupWidgetCount ++;
                     } else {
@@ -671,8 +684,8 @@
             if (icon == null) {
                 Log.w(TAG, "failed to unpack widget icon for " + key.name);
             } else {
-                IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider),
-                        icon, widget.icon.dpi);
+                mIconCache.preloadIcon(ComponentName.unflattenFromString(widget.provider),
+                        icon, widget.icon.dpi, widget.label, mUserSerial);
             }
         }
 
@@ -738,6 +751,17 @@
         return checksum.getValue();
     }
 
+    /**
+     * @return true if its an hotseat item, that can be replaced during restore.
+     * TODO: Extend check for folders in hotseat.
+     */
+    private boolean isReplaceableHotseatItem(Favorite favorite) {
+        return favorite.container == Favorites.CONTAINER_HOTSEAT
+                && favorite.intent != null
+                && (favorite.itemType == Favorites.ITEM_TYPE_APPLICATION
+                || favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT);
+    }
+
     /** Serialize a Favorite for persistence, including a checksum wrapper. */
     private Favorite packFavorite(Cursor c) {
         Favorite favorite = new Favorite();
@@ -749,30 +773,16 @@
         favorite.spanX = c.getInt(SPANX_INDEX);
         favorite.spanY = c.getInt(SPANY_INDEX);
         favorite.iconType = c.getInt(ICON_TYPE_INDEX);
-        if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) {
-            String iconPackage = c.getString(ICON_PACKAGE_INDEX);
-            if (!TextUtils.isEmpty(iconPackage)) {
-                favorite.iconPackage = iconPackage;
-            }
-            String iconResource = c.getString(ICON_RESOURCE_INDEX);
-            if (!TextUtils.isEmpty(iconResource)) {
-                favorite.iconResource = iconResource;
-            }
-        }
-        if (favorite.iconType == Favorites.ICON_TYPE_BITMAP) {
-            byte[] blob = c.getBlob(ICON_INDEX);
-            if (blob != null && blob.length > 0) {
-                favorite.icon = blob;
-            }
-        }
+
         String title = c.getString(TITLE_INDEX);
         if (!TextUtils.isEmpty(title)) {
             favorite.title = title;
         }
         String intentDescription = c.getString(INTENT_INDEX);
+        Intent intent = null;
         if (!TextUtils.isEmpty(intentDescription)) {
             try {
-                Intent intent = Intent.parseUri(intentDescription, 0);
+                intent = Intent.parseUri(intentDescription, 0);
                 intent.removeExtra(ItemInfo.EXTRA_PROFILE);
                 favorite.intent = intent.toUri(0);
             } catch (URISyntaxException e) {
@@ -786,6 +796,47 @@
             if (!TextUtils.isEmpty(appWidgetProvider)) {
                 favorite.appWidgetProvider = appWidgetProvider;
             }
+        } else if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+            if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) {
+                String iconPackage = c.getString(ICON_PACKAGE_INDEX);
+                if (!TextUtils.isEmpty(iconPackage)) {
+                    favorite.iconPackage = iconPackage;
+                }
+                String iconResource = c.getString(ICON_RESOURCE_INDEX);
+                if (!TextUtils.isEmpty(iconResource)) {
+                    favorite.iconResource = iconResource;
+                }
+            }
+
+            byte[] blob = c.getBlob(ICON_INDEX);
+            if (blob != null && blob.length > 0) {
+                favorite.icon = blob;
+            }
+        }
+
+        if (isReplaceableHotseatItem(favorite)) {
+            if (intent != null && intent.getComponent() != null) {
+                PackageManager pm = mContext.getPackageManager();
+                ActivityInfo activity = null;;
+                try {
+                    activity = pm.getActivityInfo(intent.getComponent(), 0);
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Target not found", e);
+                }
+                if (activity == null) {
+                    return favorite;
+                }
+                for (int i = 0; i < mItemTypeMatchers.length; i++) {
+                    if (mItemTypeMatchers[i] == null) {
+                        mItemTypeMatchers[i] = new ItemTypeMatcher(
+                                CommonAppTypeParser.getResourceForItemType(i));
+                    }
+                    if (mItemTypeMatchers[i].matches(activity, pm)) {
+                        favorite.targetType = i;
+                        break;
+                    }
+                }
+            }
         }
 
         return favorite;
@@ -795,6 +846,7 @@
     private ContentValues unpackFavorite(byte[] buffer, int dataSize)
             throws IOException {
         Favorite favorite = unpackProto(new Favorite(), buffer, dataSize);
+
         ContentValues values = new ContentValues();
         values.put(Favorites._ID, favorite.id);
         values.put(Favorites.SCREEN, favorite.screen);
@@ -803,14 +855,16 @@
         values.put(Favorites.CELLY, favorite.cellY);
         values.put(Favorites.SPANX, favorite.spanX);
         values.put(Favorites.SPANY, favorite.spanY);
-        values.put(Favorites.ICON_TYPE, favorite.iconType);
-        if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) {
-            values.put(Favorites.ICON_PACKAGE, favorite.iconPackage);
-            values.put(Favorites.ICON_RESOURCE, favorite.iconResource);
-        }
-        if (favorite.iconType == Favorites.ICON_TYPE_BITMAP) {
+
+        if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) {
+            values.put(Favorites.ICON_TYPE, favorite.iconType);
+            if (favorite.iconType == Favorites.ICON_TYPE_RESOURCE) {
+                values.put(Favorites.ICON_PACKAGE, favorite.iconPackage);
+                values.put(Favorites.ICON_RESOURCE, favorite.iconResource);
+            }
             values.put(Favorites.ICON, favorite.icon);
         }
+
         if (!TextUtils.isEmpty(favorite.title)) {
             values.put(Favorites.TITLE, favorite.title);
         } else {
@@ -826,7 +880,7 @@
                 UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle);
         values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber);
 
-        DeviceProfieData currentProfile = getDeviceProfieData();
+        DeviceProfieData currentProfile = mDeviceProfileData;
 
         if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) {
             if (!TextUtils.isEmpty(favorite.appWidgetProvider)) {
@@ -845,8 +899,17 @@
                 throw new InvalidBackupException("Widget not in screen bounds, aborting restore");
             }
         } else {
-            // Let LauncherModel know we've been here.
-            values.put(LauncherSettings.Favorites.RESTORED, 1);
+            // Check if it is an hotseat item, that can be replaced.
+            if (isReplaceableHotseatItem(favorite)
+                    && favorite.targetType != Favorite.TARGET_NONE
+                    && favorite.targetType < CommonAppTypeParser.SUPPORTED_TYPE_COUNT) {
+                Log.e(TAG, "Added item type flag");
+                values.put(LauncherSettings.Favorites.RESTORED,
+                        1 | CommonAppTypeParser.encodeItemTypeToFlag(favorite.targetType));
+            } else {
+                // Let LauncherModel know we've been here.
+                values.put(LauncherSettings.Favorites.RESTORED, 1);
+            }
 
             // Verify placement
             if (favorite.container == Favorites.CONTAINER_HOTSEAT) {
@@ -889,40 +952,35 @@
     private Resource packIcon(int dpi, Bitmap icon) {
         Resource res = new Resource();
         res.dpi = dpi;
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-            res.data = os.toByteArray();
-        }
+        res.data = Utilities.flattenBitmap(icon);
         return res;
     }
 
     /** Serialize a widget for persistence, including a checksum wrapper. */
-    private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache,
-            ComponentName provider) {
-        final AppWidgetProviderInfo info = findAppWidgetProviderInfo(provider);
+    private Widget packWidget(int dpi, ComponentName provider, UserHandleCompat user) {
+        final LauncherAppWidgetProviderInfo info =
+                LauncherModel.getProviderInfo(mContext, provider, user);
         Widget widget = new Widget();
         widget.provider = provider.flattenToShortString();
         widget.label = info.label;
         widget.configure = info.configure != null;
         if (info.icon != 0) {
             widget.icon = new Resource();
-            Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon);
+            Drawable fullResIcon = mIconCache.getFullResIcon(provider.getPackageName(), info.icon);
             Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-                widget.icon.data = os.toByteArray();
-                widget.icon.dpi = dpi;
-            }
+            widget.icon.data = Utilities.flattenBitmap(icon);
+            widget.icon.dpi = dpi;
         }
-        if (info.previewImage != 0) {
-            widget.preview = new Resource();
-            Bitmap preview = previewLoader.generateWidgetPreview(info, null);
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            if (preview.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
-                widget.preview.data = os.toByteArray();
-                widget.preview.dpi = dpi;
-            }
-        }
+
+        // Calculate the spans corresponding to any one of the orientations as it should not change
+        // based on orientation.
+        int[] minSpans = CellLayout.rectToCell(
+                mIdp.portraitProfile, mContext, info.minResizeWidth, info.minResizeHeight, null);
+        widget.minSpanX = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0
+                ? minSpans[0] : -1;
+        widget.minSpanY = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_VERTICAL) != 0
+                ? minSpans[1] : -1;
+
         return widget;
     }
 
@@ -1019,6 +1077,7 @@
         byte[] blob = writeCheckedBytes(proto);
         data.writeEntityHeader(backupKey, blob.length);
         data.writeEntityData(blob, blob.length);
+        mBackupDataWasUpdated = true;
         if (VERBOSE) Log.v(TAG, "Writing New entry " + backupKey);
     }
 
@@ -1067,36 +1126,6 @@
         return wrapper.payload;
     }
 
-    private AppWidgetProviderInfo findAppWidgetProviderInfo(ComponentName component) {
-        if (mWidgetMap == null) {
-            List<AppWidgetProviderInfo> widgets =
-                    AppWidgetManager.getInstance(mContext).getInstalledProviders();
-            mWidgetMap = new HashMap<ComponentName, AppWidgetProviderInfo>(widgets.size());
-            for (AppWidgetProviderInfo info : widgets) {
-                mWidgetMap.put(info.provider, info);
-            }
-        }
-        return mWidgetMap.get(component);
-    }
-
-
-    private boolean initializeIconCache() {
-        if (mIconCache != null) {
-            return true;
-        }
-
-        final LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
-        if (appState == null) {
-            Throwable stackTrace = new Throwable();
-            stackTrace.fillInStackTrace();
-            Log.w(TAG, "Failed to get app state during backup/restore", stackTrace);
-            return false;
-        }
-        mIconCache = appState.getIconCache();
-        return mIconCache != null;
-    }
-
-
     /**
      * @return true if the launcher is in a state to support backup
      */
@@ -1109,9 +1138,8 @@
         }
         cursor.close();
 
-        if (!initializeIconCache()) {
+        if (LauncherAppState.getInstanceNoCreate() == null) {
             // launcher services are unavailable, try again later
-            dataChanged();
             return false;
         }
 
@@ -1123,13 +1151,66 @@
                 .getSerialNumberForUser(UserHandleCompat.myUserHandle());
     }
 
-    private class InvalidBackupException extends IOException {
-        private InvalidBackupException(Throwable cause) {
+    @Thunk class InvalidBackupException extends IOException {
+
+        private static final long serialVersionUID = 8931456637211665082L;
+
+        @Thunk InvalidBackupException(Throwable cause) {
             super(cause);
         }
 
-        public InvalidBackupException(String reason) {
+        @Thunk InvalidBackupException(String reason) {
             super(reason);
         }
     }
+
+    /**
+     * A class to check if an activity can handle one of the intents from a list of
+     * predefined intents.
+     */
+    private class ItemTypeMatcher {
+
+        private final ArrayList<Intent> mIntents;
+
+        ItemTypeMatcher(int xml_res) {
+            mIntents = xml_res == 0 ? new ArrayList<Intent>() : parseIntents(xml_res);
+        }
+
+        private ArrayList<Intent> parseIntents(int xml_res) {
+            ArrayList<Intent> intents = new ArrayList<Intent>();
+            XmlResourceParser parser = mContext.getResources().getXml(xml_res);
+            try {
+                DefaultLayoutParser.beginDocument(parser, DefaultLayoutParser.TAG_RESOLVE);
+                final int depth = parser.getDepth();
+                int type;
+                while (((type = parser.next()) != XmlPullParser.END_TAG ||
+                        parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+                    if (type != XmlPullParser.START_TAG) {
+                        continue;
+                    } else if (DefaultLayoutParser.TAG_FAVORITE.equals(parser.getName())) {
+                        final String uri = DefaultLayoutParser.getAttributeValue(
+                                parser, DefaultLayoutParser.ATTR_URI);
+                        intents.add(Intent.parseUri(uri, 0));
+                    }
+                }
+            } catch (URISyntaxException | XmlPullParserException | IOException e) {
+                Log.e(TAG, "Unable to parse " + xml_res, e);
+            } finally {
+                parser.close();
+            }
+            return intents;
+        }
+
+        public boolean matches(ActivityInfo activity, PackageManager pm) {
+            for (Intent intent : mIntents) {
+                intent.setPackage(activity.packageName);
+                ResolveInfo info = pm.resolveActivity(intent, 0);
+                if (info != null && (info.activityInfo.name.equals(activity.name)
+                        || info.activityInfo.name.equals(activity.targetActivity))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index a1f4e0b..6618cca 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -7,10 +7,13 @@
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
+import com.android.launcher3.allapps.AllAppsSearchBarController;
+import com.android.launcher3.util.ComponentKey;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * LauncherCallbacks is an interface used to extend the Launcher activity. It includes many hooks
@@ -37,11 +40,14 @@
     public void onPostCreate(Bundle savedInstanceState);
     public void onNewIntent(Intent intent);
     public void onActivityResult(int requestCode, int resultCode, Intent data);
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults);
     public void onWindowFocusChanged(boolean hasFocus);
     public boolean onPrepareOptionsMenu(Menu menu);
     public void dump(String prefix, FileDescriptor fd, PrintWriter w, String[] args);
     public void onHomeIntent();
     public boolean handleBackPressed();
+    public void onTrimMemory(int level);
 
     /*
      * Extension points for providing custom behavior on certain user interactions.
@@ -52,6 +58,7 @@
     public void bindAllApplications(ArrayList<AppInfo> apps);
     public void onClickFolderIcon(View v);
     public void onClickAppShortcut(View v);
+    @Deprecated
     public void onClickPagedViewIcon(View v);
     public void onClickWallpaperPicker(View v);
     public void onClickSettingsButton(View v);
@@ -65,10 +72,12 @@
     /*
      * Extension points for replacing the search experience
      */
+    @Deprecated
     public boolean forceDisableVoiceButtonProxy();
     public boolean providesSearch();
     public boolean startSearch(String initialQuery, boolean selectInitialQuery,
             Bundle appSearchData, Rect sourceBounds);
+    @Deprecated
     public void startVoice();
     public boolean hasCustomContentToLeft();
     public void populateCustomContentContainer();
@@ -83,9 +92,12 @@
     public View getIntroScreen();
     public boolean shouldMoveToDefaultScreenOnHomeIntent();
     public boolean hasSettings();
+    @Deprecated
     public ComponentName getWallpaperPickerComponent();
     public boolean overrideWallpaperDimensions();
     public boolean isLauncherPreinstalled();
+    public AllAppsSearchBarController getAllAppsSearchBarController();
+    public List<ComponentKey> getPredictedApps();
 
     /**
      * Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
@@ -105,4 +117,11 @@
     public Launcher.LauncherOverlay setLauncherOverlayView(InsettableFrameLayout container,
             Launcher.LauncherOverlayCallbacks callbacks);
 
+    /**
+     * Sets the callbacks to allow reacting the actions of search overlays of the launcher.
+     *
+     * @param callbacks A set of callbacks to the Launcher, is actually a LauncherSearchCallback,
+     *                  but for implementation purposes is passed around as an object.
+     */
+    public void setLauncherSearchCallback(Object callbacks);
 }
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
index ef8e8ab..c13752c 100644
--- a/src/com/android/launcher3/LauncherClings.java
+++ b/src/com/android/launcher3/LauncherClings.java
@@ -20,10 +20,12 @@
 import android.accounts.AccountManager;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -34,6 +36,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.util.Thunk;
 
 class LauncherClings implements OnClickListener {
     private static final String MIGRATION_CLING_DISMISSED_KEY = "cling_gel.migration.dismissed";
@@ -49,7 +52,7 @@
     // New Secure Setting in L
     private static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
 
-    private Launcher mLauncher;
+    @Thunk Launcher mLauncher;
     private LayoutInflater mInflater;
 
     /** Ctor */
@@ -68,7 +71,7 @@
             // Copy the shortcuts from the old database
             LauncherModel model = mLauncher.getModel();
             model.resetLoadedState(false, true);
-            model.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
+            model.startLoader(PagedView.INVALID_RESTORE_PAGE,
                     LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
                             | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
             // Set the flag to skip the folder cling
@@ -124,7 +127,7 @@
 
             @Override
             public boolean onLongClick(View v) {
-                mLauncher.getWorkspace().enterOverviewMode();
+                mLauncher.showOverviewMode(true);
                 dismissLongPressCling();
                 return true;
             }
@@ -174,7 +177,7 @@
         });
     }
 
-    private void dismissLongPressCling() {
+    @Thunk void dismissLongPressCling() {
         Runnable dismissCb = new Runnable() {
             public void run() {
                 dismissCling(mLauncher.findViewById(R.id.longpress_cling), null,
@@ -185,7 +188,7 @@
     }
 
     /** Hides the specified Cling */
-    private void dismissCling(final View cling, final Runnable postAnimationCb,
+    @Thunk void dismissCling(final View cling, final Runnable postAnimationCb,
                               final String flag, int duration) {
         // To catch cases where siblings of top-level views are made invisible, just check whether
         // the cling is directly set to GONE before dismissing it.
@@ -210,6 +213,7 @@
     }
 
     /** Returns whether the clings are enabled or should be shown */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
     private boolean areClingsEnabled() {
         if (DISABLE_CLINGS) {
             return false;
diff --git a/src/com/android/launcher3/LauncherFiles.java b/src/com/android/launcher3/LauncherFiles.java
index fa05365..c08cd0b 100644
--- a/src/com/android/launcher3/LauncherFiles.java
+++ b/src/com/android/launcher3/LauncherFiles.java
@@ -17,24 +17,30 @@
     public static final String DEFAULT_WALLPAPER_THUMBNAIL = "default_thumb2.jpg";
     public static final String DEFAULT_WALLPAPER_THUMBNAIL_OLD = "default_thumb.jpg";
     public static final String LAUNCHER_DB = "launcher.db";
-    public static final String LAUNCHER_PREFERENCES = "launcher.preferences";
-    public static final String LAUNCHES_LOG = "launches.log";
     public static final String SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs";
-    public static final String STATS_LOG = "stats.log";
     public static final String WALLPAPER_CROP_PREFERENCES_KEY =
-            WallpaperCropActivity.class.getName();
+            "com.android.launcher3.WallpaperCropActivity";
+    public static final String MANAGED_USER_PREFERENCES_KEY = "com.android.launcher3.managedusers.prefs";
+
     public static final String WALLPAPER_IMAGES_DB = "saved_wallpaper_images.db";
     public static final String WIDGET_PREVIEWS_DB = "widgetpreviews.db";
+    public static final String APP_ICONS_DB = "app_icons.db";
 
     public static final List<String> ALL_FILES = Collections.unmodifiableList(Arrays.asList(
             DEFAULT_WALLPAPER_THUMBNAIL,
             DEFAULT_WALLPAPER_THUMBNAIL_OLD,
             LAUNCHER_DB,
-            LAUNCHER_PREFERENCES,
-            LAUNCHES_LOG,
             SHARED_PREFERENCES_KEY + XML,
-            STATS_LOG,
             WALLPAPER_CROP_PREFERENCES_KEY + XML,
             WALLPAPER_IMAGES_DB,
-            WIDGET_PREVIEWS_DB));
+            WIDGET_PREVIEWS_DB,
+            MANAGED_USER_PREFERENCES_KEY,
+            APP_ICONS_DB));
+
+    // TODO: Delete these files on upgrade
+    public static final List<String> OBSOLETE_FILES = Collections.unmodifiableList(Arrays.asList(
+            "launches.log",
+            "stats.log",
+            "launcher.preferences",
+            "com.android.launcher3.compat.PackageInstallerCompatV16.queue"));
 }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 954887d..b60477f 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -17,11 +17,9 @@
 package com.android.launcher3;
 
 import android.app.SearchManager;
-import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
-import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -29,27 +27,25 @@
 import android.content.Intent;
 import android.content.Intent.ShortcutIconResource;
 import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.LauncherApps.Callback;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.TransactionTooLargeException;
 import android.provider.BaseColumns;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.LongSparseArray;
 import android.util.Pair;
 
 import com.android.launcher3.compat.AppWidgetManagerCompat;
@@ -59,11 +55,16 @@
 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.CursorIconInfo;
+import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.ManagedProfileHeuristic;
+import com.android.launcher3.util.Thunk;
 
 import java.lang.ref.WeakReference;
 import java.net.URISyntaxException;
 import java.security.InvalidParameterException;
-import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -75,7 +76,6 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.TreeMap;
 
 /**
  * Maintains in-memory state of the Launcher. It is expected that there should be only one
@@ -87,13 +87,9 @@
     static final boolean DEBUG_LOADERS = false;
     private static final boolean DEBUG_RECEIVER = false;
     private static final boolean REMOVE_UNRESTORED_ICONS = true;
-    private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;
 
     static final String TAG = "Launcher.Model";
 
-    // true = use a "More Apps" folder for non-workspace apps on upgrade
-    // false = strew non-workspace apps across the workspace on upgrade
-    public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;
     public static final int LOADER_FLAG_NONE = 0;
     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;
     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;
@@ -101,39 +97,29 @@
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
     private static final long INVALID_SCREEN_ID = -1L;
 
-    private final boolean mAppsCanBeOnRemoveableStorage;
+    @Thunk final boolean mAppsCanBeOnRemoveableStorage;
     private final boolean mOldContentProviderExists;
 
-    private final LauncherAppState mApp;
-    private final Object mLock = new Object();
-    private DeferredHandler mHandler = new DeferredHandler();
-    private LoaderTask mLoaderTask;
-    private boolean mIsLoaderTaskRunning;
-    private volatile boolean mFlushingWorkerThread;
-
-    /**
-     * Maintain a set of packages per user, for which we added a shortcut on the workspace.
-     */
-    private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";
-
-    // Specific runnable types that are run on the main thread deferred handler, this allows us to
-    // clear all queued binding runnables when the Launcher activity is destroyed.
-    private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
-    private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;
+    @Thunk final LauncherAppState mApp;
+    @Thunk final Object mLock = new Object();
+    @Thunk DeferredHandler mHandler = new DeferredHandler();
+    @Thunk LoaderTask mLoaderTask;
+    @Thunk boolean mIsLoaderTaskRunning;
+    @Thunk boolean mHasLoaderCompletedOnce;
 
     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
 
-    private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
+    @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
     static {
         sWorkerThread.start();
     }
-    private static final Handler sWorker = new Handler(sWorkerThread.getLooper());
+    @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());
 
     // We start off with everything not loaded.  After that, we assume that
     // our monitoring of the package manager provides all updates and we never
     // need to do a requery.  These are only ever touched from the loader thread.
-    private boolean mWorkspaceLoaded;
-    private boolean mAllAppsLoaded;
+    @Thunk boolean mWorkspaceLoaded;
+    @Thunk boolean mAllAppsLoaded;
 
     // When we are loading pages synchronously, we can't just post the binding of items on the side
     // pages as this delays the rotation process.  Instead, we wait for a callback from the first
@@ -141,10 +127,18 @@
     // a normal load, we also clear this set of Runnables.
     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();
 
-    private WeakReference<Callbacks> mCallbacks;
+    /**
+     * Set of runnables to be called on the background thread after the workspace binding
+     * is complete.
+     */
+    static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();
+
+    @Thunk WeakReference<Callbacks> mCallbacks;
 
     // < only access in worker thread >
     AllAppsList mBgAllAppsList;
+    // Entire list of widgets.
+    WidgetsModel mBgWidgetsModel;
 
     // The lock that must be acquired before referencing any static bg data structures.  Unlike
     // other locks, this one can generally be held long-term because we never expect any of these
@@ -154,7 +148,7 @@
 
     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
     // LauncherModel to their ids
-    static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
+    static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();
 
     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
     //       created by LauncherModel that are directly on the home screen (however, no widgets or
@@ -166,26 +160,24 @@
         new ArrayList<LauncherAppWidgetInfo>();
 
     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
-    static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
-
-    // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database
-    static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();
+    static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();
 
     // sBgWorkspaceScreens is the ordered set of workspace screens.
     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
 
+    // sBgWidgetProviders is the set of widget providers including custom internal widgets
+    public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;
+
     // sPendingPackages is a set of packages which could be on sdcard and are not available yet
     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =
             new HashMap<UserHandleCompat, HashSet<String>>();
 
     // </ only access in worker thread >
 
-    private IconCache mIconCache;
+    @Thunk IconCache mIconCache;
 
-    protected int mPreviousConfigMcc;
-
-    private final LauncherAppsCompat mLauncherApps;
-    private final UserManagerCompat mUserManager;
+    @Thunk final LauncherAppsCompat mLauncherApps;
+    @Thunk final UserManagerCompat mUserManager;
 
     public interface Callbacks {
         public boolean setLoadOnResume();
@@ -195,8 +187,8 @@
                               boolean forceAnimateIcons);
         public void bindScreens(ArrayList<Long> orderedScreenIds);
         public void bindAddScreens(ArrayList<Long> orderedScreenIds);
-        public void bindFolders(HashMap<Long,FolderInfo> folders);
-        public void finishBindingItems(boolean upgradePath);
+        public void bindFolders(LongArrayMap<FolderInfo> folders);
+        public void finishBindingItems();
         public void bindAppWidget(LauncherAppWidgetInfo info);
         public void bindAllApplications(ArrayList<AppInfo> apps);
         public void bindAppsAdded(ArrayList<Long> newScreens,
@@ -207,11 +199,10 @@
         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,
                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);
         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
-        public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);
-        public void updatePackageBadge(String packageName);
+        public void bindRestoreItemsChange(HashSet<ItemInfo> updates);
         public void bindComponentsRemoved(ArrayList<String> packageNames,
                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);
-        public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
+        public void bindAllPackages(WidgetsModel model);
         public void bindSearchablesChanged();
         public boolean isAllAppsButtonRank(int rank);
         public void onPageBoundSynchronously(int page);
@@ -246,21 +237,16 @@
 
         mApp = app;
         mBgAllAppsList = new AllAppsList(iconCache, appFilter);
+        mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);
         mIconCache = iconCache;
 
-        final Resources res = context.getResources();
-        Configuration config = res.getConfiguration();
-        mPreviousConfigMcc = config.mcc;
         mLauncherApps = LauncherAppsCompat.getInstance(context);
         mUserManager = UserManagerCompat.getInstance(context);
     }
 
     /** Runs the specified runnable immediately if called from the main thread, otherwise it is
      * posted on the main thread handler. */
-    private void runOnMainThread(Runnable r) {
-        runOnMainThread(r, 0);
-    }
-    private void runOnMainThread(Runnable r, int type) {
+    @Thunk void runOnMainThread(Runnable r) {
         if (sWorkerThread.getThreadId() == Process.myTid()) {
             // If we are on the worker thread, post onto the main handler
             mHandler.post(r);
@@ -280,95 +266,127 @@
         }
     }
 
+    /**
+     * Runs the specified runnable after the loader is complete
+     */
+    @Thunk void runAfterBindCompletes(Runnable r) {
+        if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) {
+            synchronized (mBindCompleteRunnables) {
+                mBindCompleteRunnables.add(r);
+            }
+        } else {
+            runOnWorkerThread(r);
+        }
+    }
+
     boolean canMigrateFromOldLauncherDb(Launcher launcher) {
         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;
     }
 
-    static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,
-                                 long screen) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        final int xCount = (int) grid.numColumns;
-        final int yCount = (int) grid.numRows;
-        boolean[][] occupied = new boolean[xCount][yCount];
+    public void setPackageState(final PackageInstallInfo installInfo) {
+        Runnable updateRunnable = new Runnable() {
 
-        int cellX, cellY, spanX, spanY;
-        for (int i = 0; i < items.size(); ++i) {
-            final ItemInfo item = items.get(i);
-            if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
-                if (item.screenId == screen) {
-                    cellX = item.cellX;
-                    cellY = item.cellY;
-                    spanX = item.spanX;
-                    spanY = item.spanY;
-                    for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {
-                        for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {
-                            occupied[x][y] = true;
+            @Override
+            public void run() {
+                synchronized (sBgLock) {
+                    final HashSet<ItemInfo> updates = new HashSet<>();
+
+                    if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
+                        // Ignore install success events as they are handled by Package add events.
+                        return;
+                    }
+
+                    for (ItemInfo info : sBgItemsIdMap) {
+                        if (info instanceof ShortcutInfo) {
+                            ShortcutInfo si = (ShortcutInfo) info;
+                            ComponentName cn = si.getTargetComponent();
+                            if (si.isPromise() && (cn != null)
+                                    && installInfo.packageName.equals(cn.getPackageName())) {
+                                si.setInstallProgress(installInfo.progress);
+
+                                if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {
+                                    // Mark this info as broken.
+                                    si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+                                }
+                                updates.add(si);
+                            }
                         }
                     }
+
+                    for (LauncherAppWidgetInfo widget : sBgAppWidgets) {
+                        if (widget.providerName.getPackageName().equals(installInfo.packageName)) {
+                            widget.installProgress = installInfo.progress;
+                            updates.add(widget);
+                        }
+                    }
+
+                    if (!updates.isEmpty()) {
+                        // Push changes to the callback.
+                        Runnable r = new Runnable() {
+                            public void run() {
+                                Callbacks callbacks = getCallback();
+                                if (callbacks != null) {
+                                    callbacks.bindRestoreItemsChange(updates);
+                                }
+                            }
+                        };
+                        mHandler.post(r);
+                    }
                 }
             }
-        }
-
-        return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);
-    }
-    static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,
-                                                        Intent launchIntent,
-                                                        int firstScreenIndex,
-                                                        ArrayList<Long> workspaceScreens) {
-        // Lock on the app so that we don't try and get the items while apps are being added
-        LauncherAppState app = LauncherAppState.getInstance();
-        LauncherModel model = app.getModel();
-        boolean found = false;
-        synchronized (app) {
-            if (sWorkerThread.getThreadId() != Process.myTid()) {
-                // Flush the LauncherModel worker thread, so that if we just did another
-                // processInstallShortcut, we give it time for its shortcut to get added to the
-                // database (getItemsInLocalCoordinates reads the database)
-                model.flushWorkerThread();
-            }
-            final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
-
-            // Try adding to the workspace screens incrementally, starting at the default or center
-            // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
-            firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());
-            int count = workspaceScreens.size();
-            for (int screen = firstScreenIndex; screen < count && !found; screen++) {
-                int[] tmpCoordinates = new int[2];
-                if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,
-                        workspaceScreens.get(screen))) {
-                    // Update the Launcher db
-                    return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);
-                }
-            }
-        }
-        return null;
+        };
+        runOnWorkerThread(updateRunnable);
     }
 
-    public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {
-        // Process the updated package state
-        Runnable r = new Runnable() {
+    /**
+     * Updates the icons and label of all pending icons for the provided package name.
+     */
+    public void updateSessionDisplayInfo(final String packageName) {
+        Runnable updateRunnable = new Runnable() {
+
+            @Override
             public void run() {
-                Callbacks callbacks = getCallback();
-                if (callbacks != null) {
-                    callbacks.updatePackageState(installInfo);
+                synchronized (sBgLock) {
+                    final ArrayList<ShortcutInfo> updates = new ArrayList<>();
+                    final UserHandleCompat user = UserHandleCompat.myUserHandle();
+
+                    for (ItemInfo info : sBgItemsIdMap) {
+                        if (info instanceof ShortcutInfo) {
+                            ShortcutInfo si = (ShortcutInfo) info;
+                            ComponentName cn = si.getTargetComponent();
+                            if (si.isPromise() && (cn != null)
+                                    && packageName.equals(cn.getPackageName())) {
+                                if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
+                                    // For auto install apps update the icon as well as label.
+                                    mIconCache.getTitleAndIcon(si,
+                                            si.promisedIntent, user,
+                                            si.shouldUseLowResIcon());
+                                } else {
+                                    // Only update the icon for restored apps.
+                                    si.updateIcon(mIconCache);
+                                }
+                                updates.add(si);
+                            }
+                        }
+                    }
+
+                    if (!updates.isEmpty()) {
+                        // Push changes to the callback.
+                        Runnable r = new Runnable() {
+                            public void run() {
+                                Callbacks callbacks = getCallback();
+                                if (callbacks != null) {
+                                    callbacks.bindShortcutsChanged(updates,
+                                            new ArrayList<ShortcutInfo>(), user);
+                                }
+                            }
+                        };
+                        mHandler.post(r);
+                    }
                 }
             }
         };
-        mHandler.post(r);
-    }
-
-    public void updatePackageBadge(final String packageName) {
-        // Process the updated package badge
-        Runnable r = new Runnable() {
-            public void run() {
-                Callbacks callbacks = getCallback();
-                if (callbacks != null) {
-                    callbacks.updatePackageBadge(packageName);
-                }
-            }
-        };
-        mHandler.post(r);
+        runOnWorkerThread(updateRunnable);
     }
 
     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {
@@ -397,13 +415,103 @@
         runOnWorkerThread(r);
     }
 
-    public void addAndBindAddedWorkspaceApps(final Context context,
-            final ArrayList<ItemInfo> workspaceApps) {
-        final Callbacks callbacks = getCallback();
-
-        if (workspaceApps == null) {
-            throw new RuntimeException("workspaceApps and allAppsApps must not be null");
+    private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,
+            int[] xy, int spanX, int spanY) {
+        LauncherAppState app = LauncherAppState.getInstance();
+        InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+        final int xCount = (int) profile.numColumns;
+        final int yCount = (int) profile.numRows;
+        boolean[][] occupied = new boolean[xCount][yCount];
+        if (occupiedPos != null) {
+            for (ItemInfo r : occupiedPos) {
+                int right = r.cellX + r.spanX;
+                int bottom = r.cellY + r.spanY;
+                for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {
+                    for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {
+                        occupied[x][y] = true;
+                    }
+                }
+            }
         }
+        return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
+    }
+
+    /**
+     * Find a position on the screen for the given size or adds a new screen.
+     * @return screenId and the coordinates for the item.
+     */
+    @Thunk Pair<Long, int[]> findSpaceForItem(
+            Context context,
+            ArrayList<Long> workspaceScreens,
+            ArrayList<Long> addedWorkspaceScreensFinal,
+            int spanX, int spanY) {
+        LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();
+
+        // Use sBgItemsIdMap as all the items are already loaded.
+        assertWorkspaceLoaded();
+        synchronized (sBgLock) {
+            for (ItemInfo info : sBgItemsIdMap) {
+                if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+                    ArrayList<ItemInfo> items = screenItems.get(info.screenId);
+                    if (items == null) {
+                        items = new ArrayList<>();
+                        screenItems.put(info.screenId, items);
+                    }
+                    items.add(info);
+                }
+            }
+        }
+
+        // Find appropriate space for the item.
+        long screenId = 0;
+        int[] cordinates = new int[2];
+        boolean found = false;
+
+        int screenCount = workspaceScreens.size();
+        // First check the preferred screen.
+        int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;
+        if (preferredScreenIndex < screenCount) {
+            screenId = workspaceScreens.get(preferredScreenIndex);
+            found = findNextAvailableIconSpaceInScreen(
+                    screenItems.get(screenId), cordinates, spanX, spanY);
+        }
+
+        if (!found) {
+            // Search on any of the screens starting from the first screen.
+            for (int screen = 1; screen < screenCount; screen++) {
+                screenId = workspaceScreens.get(screen);
+                if (findNextAvailableIconSpaceInScreen(
+                        screenItems.get(screenId), cordinates, spanX, spanY)) {
+                    // We found a space for it
+                    found = true;
+                    break;
+                }
+            }
+        }
+
+        if (!found) {
+            // Still no position found. Add a new screen to the end.
+            screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();
+
+            // Save the screen id for binding in the workspace
+            workspaceScreens.add(screenId);
+            addedWorkspaceScreensFinal.add(screenId);
+
+            // If we still can't find an empty space, then God help us all!!!
+            if (!findNextAvailableIconSpaceInScreen(
+                    screenItems.get(screenId), cordinates, spanX, spanY)) {
+                throw new RuntimeException("Can't find space to add the item");
+            }
+        }
+        return Pair.create(screenId, cordinates);
+    }
+
+    /**
+     * Adds the provided items to the workspace.
+     */
+    public void addAndBindAddedWorkspaceItems(final Context context,
+            final ArrayList<? extends ItemInfo> workspaceApps) {
+        final Callbacks callbacks = getCallback();
         if (workspaceApps.isEmpty()) {
             return;
         }
@@ -416,71 +524,38 @@
                 // Get the list of workspace screens.  We need to append to this list and
                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been
                 // called.
-                ArrayList<Long> workspaceScreens = new ArrayList<Long>();
-                TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);
-                for (Integer i : orderedScreens.keySet()) {
-                    long screenId = orderedScreens.get(i);
-                    workspaceScreens.add(screenId);
-                }
-
+                ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);
                 synchronized(sBgLock) {
-                    Iterator<ItemInfo> iter = workspaceApps.iterator();
-                    while (iter.hasNext()) {
-                        ItemInfo a = iter.next();
-                        final String name = a.title.toString();
-                        final Intent launchIntent = a.getIntent();
-
-                        // Short-circuit this logic if the icon exists somewhere on the workspace
-                        if (shortcutExists(context, name, launchIntent, a.user)) {
-                            continue;
-                        }
-
-                        // Add this icon to the db, creating a new page if necessary.  If there
-                        // is only the empty page then we just add items to the first page.
-                        // Otherwise, we add them to the next pages.
-                        int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;
-                        Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,
-                                name, launchIntent, startSearchPageIndex, workspaceScreens);
-                        if (coords == null) {
-                            LauncherProvider lp = LauncherAppState.getLauncherProvider();
-
-                            // If we can't find a valid position, then just add a new screen.
-                            // This takes time so we need to re-queue the add until the new
-                            // page is added.  Create as many screens as necessary to satisfy
-                            // the startSearchPageIndex.
-                            int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -
-                                    workspaceScreens.size());
-                            while (numPagesToAdd > 0) {
-                                long screenId = lp.generateNewScreenId();
-                                // Save the screen id for binding in the workspace
-                                workspaceScreens.add(screenId);
-                                addedWorkspaceScreensFinal.add(screenId);
-                                numPagesToAdd--;
+                    for (ItemInfo item : workspaceApps) {
+                        if (item instanceof ShortcutInfo) {
+                            // Short-circuit this logic if the icon exists somewhere on the workspace
+                            if (shortcutExists(context, item.getIntent(), item.user)) {
+                                continue;
                             }
-
-                            // Find the coordinate again
-                            coords = LauncherModel.findNextAvailableIconSpace(context,
-                                    name, launchIntent, startSearchPageIndex, workspaceScreens);
-                        }
-                        if (coords == null) {
-                            throw new RuntimeException("Coordinates should not be null");
                         }
 
-                        ShortcutInfo shortcutInfo;
-                        if (a instanceof ShortcutInfo) {
-                            shortcutInfo = (ShortcutInfo) a;
-                        } else if (a instanceof AppInfo) {
-                            shortcutInfo = ((AppInfo) a).makeShortcut();
+                        // Find appropriate space for the item.
+                        Pair<Long, int[]> coords = findSpaceForItem(context,
+                                workspaceScreens, addedWorkspaceScreensFinal,
+                                1, 1);
+                        long screenId = coords.first;
+                        int[] cordinates = coords.second;
+
+                        ItemInfo itemInfo;
+                        if (item instanceof ShortcutInfo || item instanceof FolderInfo) {
+                            itemInfo = item;
+                        } else if (item instanceof AppInfo) {
+                            itemInfo = ((AppInfo) item).makeShortcut();
                         } else {
                             throw new RuntimeException("Unexpected info type");
                         }
 
                         // Add the shortcut to the db
-                        addItemToDatabase(context, shortcutInfo,
+                        addItemToDatabase(context, itemInfo,
                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                                coords.first, coords.second[0], coords.second[1], false);
+                                screenId, cordinates[0], cordinates[1]);
                         // Save the ShortcutInfo for binding in the workspace
-                        addedShortcutsFinal.add(shortcutInfo);
+                        addedShortcutsFinal.add(itemInfo);
                     }
                 }
 
@@ -516,7 +591,7 @@
         runOnWorkerThread(r);
     }
 
-    public void unbindItemInfosAndClearQueuedBindRunnables() {
+    private void unbindItemInfosAndClearQueuedBindRunnables() {
         if (sWorkerThread.getThreadId() == Process.myTid()) {
             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
                     "main thread");
@@ -526,8 +601,9 @@
         synchronized (mDeferredBindRunnables) {
             mDeferredBindRunnables.clear();
         }
-        // Remove any queued bind runnables
-        mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);
+
+        // Remove any queued UI runnables
+        mHandler.cancelAll();
         // Unbind all the workspace items
         unbindWorkspaceItemsOnMainThread();
     }
@@ -536,19 +612,15 @@
     void unbindWorkspaceItemsOnMainThread() {
         // Ensure that we don't use the same workspace items data structure on the main thread
         // by making a copy of workspace items first.
-        final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();
-        final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();
+        final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();
         synchronized (sBgLock) {
-            tmpWorkspaceItems.addAll(sBgWorkspaceItems);
-            tmpAppWidgets.addAll(sBgAppWidgets);
+            tmpItems.addAll(sBgWorkspaceItems);
+            tmpItems.addAll(sBgAppWidgets);
         }
         Runnable r = new Runnable() {
                 @Override
                 public void run() {
-                   for (ItemInfo item : tmpWorkspaceItems) {
-                       item.unbind();
-                   }
-                   for (ItemInfo item : tmpAppWidgets) {
+                   for (ItemInfo item : tmpItems) {
                        item.unbind();
                    }
                 }
@@ -564,7 +636,7 @@
             long screenId, int cellX, int cellY) {
         if (item.container == ItemInfo.NO_ID) {
             // From all apps
-            addItemToDatabase(context, item, container, screenId, cellX, cellY, false);
+            addItemToDatabase(context, item, container, screenId, cellX, cellY);
         } else {
             // From somewhere else
             moveItemInDatabase(context, item, container, screenId, cellX, cellY);
@@ -630,7 +702,7 @@
     static void updateItemInDatabaseHelper(Context context, final ContentValues values,
             final ItemInfo item, final String callingFunction) {
         final long itemId = item.id;
-        final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);
+        final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);
         final ContentResolver cr = context.getContentResolver();
 
         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
@@ -656,7 +728,7 @@
                 for (int i = 0; i < count; i++) {
                     ItemInfo item = items.get(i);
                     final long itemId = item.id;
-                    final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);
+                    final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);
                     ContentValues values = valuesList.get(i);
 
                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());
@@ -714,39 +786,10 @@
         }
     }
 
-    public void flushWorkerThread() {
-        mFlushingWorkerThread = true;
-        Runnable waiter = new Runnable() {
-                public void run() {
-                    synchronized (this) {
-                        notifyAll();
-                        mFlushingWorkerThread = false;
-                    }
-                }
-            };
-
-        synchronized(waiter) {
-            runOnWorkerThread(waiter);
-            if (mLoaderTask != null) {
-                synchronized(mLoaderTask) {
-                    mLoaderTask.notify();
-                }
-            }
-            boolean success = false;
-            while (!success) {
-                try {
-                    waiter.wait();
-                    success = true;
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-    }
-
     /**
      * Move an item in the DB to a new <container, screen, cellX, cellY>
      */
-    static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
+    public static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
             final long screenId, final int cellX, final int cellY) {
         item.container = container;
         item.cellX = cellX;
@@ -765,6 +808,7 @@
         values.put(LauncherSettings.Favorites.CONTAINER, item.container);
         values.put(LauncherSettings.Favorites.CELLX, item.cellX);
         values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+        values.put(LauncherSettings.Favorites.RANK, item.rank);
         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);
 
         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");
@@ -798,6 +842,7 @@
             values.put(LauncherSettings.Favorites.CONTAINER, item.container);
             values.put(LauncherSettings.Favorites.CELLX, item.cellX);
             values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+            values.put(LauncherSettings.Favorites.RANK, item.rank);
             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);
 
             contentValues.add(values);
@@ -829,6 +874,7 @@
         values.put(LauncherSettings.Favorites.CONTAINER, item.container);
         values.put(LauncherSettings.Favorites.CELLX, item.cellX);
         values.put(LauncherSettings.Favorites.CELLY, item.cellY);
+        values.put(LauncherSettings.Favorites.RANK, item.rank);
         values.put(LauncherSettings.Favorites.SPANX, item.spanX);
         values.put(LauncherSettings.Favorites.SPANY, item.spanY);
         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);
@@ -839,104 +885,63 @@
     /**
      * Update an item to the database in a specified container.
      */
-    static void updateItemInDatabase(Context context, final ItemInfo item) {
+    public static void updateItemInDatabase(Context context, final ItemInfo item) {
         final ContentValues values = new ContentValues();
         item.onAddToDatabase(context, values);
-        item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");
     }
 
-    /**
-     * Returns true if the shortcuts already exists in the database.
-     * we identify a shortcut by its title and intent.
-     */
-    static boolean shortcutExists(Context context, String title, Intent intent,
-            UserHandleCompat user) {
-        final ContentResolver cr = context.getContentResolver();
-        final Intent intentWithPkg, intentWithoutPkg;
-
-        if (intent.getComponent() != null) {
-            // If component is not null, an intent with null package will produce
-            // the same result and should also be a match.
-            if (intent.getPackage() != null) {
-                intentWithPkg = intent;
-                intentWithoutPkg = new Intent(intent).setPackage(null);
-            } else {
-                intentWithPkg = new Intent(intent).setPackage(
-                        intent.getComponent().getPackageName());
-                intentWithoutPkg = intent;
-            }
-        } else {
-            intentWithPkg = intent;
-            intentWithoutPkg = intent;
-        }
-        String userSerial = Long.toString(UserManagerCompat.getInstance(context)
-                .getSerialNumberForUser(user));
-        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
-            new String[] { "title", "intent", "profileId" },
-            "title=? and (intent=? or intent=?) and profileId=?",
-            new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },
-            null);
-        try {
-            return c.moveToFirst();
-        } finally {
-            c.close();
+    private void assertWorkspaceLoaded() {
+        if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) {
+            throw new RuntimeException("Trying to add shortcut while loader is running");
         }
     }
 
     /**
-     * Returns an ItemInfo array containing all the items in the LauncherModel.
-     * The ItemInfo.id is not set through this function.
+     * Returns true if the shortcuts already exists on the workspace. This must be called after
+     * the workspace has been loaded. We identify a shortcut by its intent.
      */
-    static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {
-        ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
-        final ContentResolver cr = context.getContentResolver();
-        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {
-                LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,
-                LauncherSettings.Favorites.SCREEN,
-                LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY,
-                LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY,
-                LauncherSettings.Favorites.PROFILE_ID }, null, null, null);
-
-        final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
-        final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
-        final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
-        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
-        final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
-        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
-        try {
-            while (c.moveToNext()) {
-                ItemInfo item = new ItemInfo();
-                item.cellX = c.getInt(cellXIndex);
-                item.cellY = c.getInt(cellYIndex);
-                item.spanX = Math.max(1, c.getInt(spanXIndex));
-                item.spanY = Math.max(1, c.getInt(spanYIndex));
-                item.container = c.getInt(containerIndex);
-                item.itemType = c.getInt(itemTypeIndex);
-                item.screenId = c.getInt(screenIndex);
-                long serialNumber = c.getInt(profileIdIndex);
-                item.user = userManager.getUserForSerialNumber(serialNumber);
-                // Skip if user has been deleted.
-                if (item.user != null) {
-                    items.add(item);
-                }
+    @Thunk boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {
+        assertWorkspaceLoaded();
+        final String intentWithPkg, intentWithoutPkg;
+        if (intent.getComponent() != null) {
+            // If component is not null, an intent with null package will produce
+            // the same result and should also be a match.
+            String packageName = intent.getComponent().getPackageName();
+            if (intent.getPackage() != null) {
+                intentWithPkg = intent.toUri(0);
+                intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);
+            } else {
+                intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);
+                intentWithoutPkg = intent.toUri(0);
             }
-        } catch (Exception e) {
-            items.clear();
-        } finally {
-            c.close();
+        } else {
+            intentWithPkg = intent.toUri(0);
+            intentWithoutPkg = intent.toUri(0);
         }
 
-        return items;
+        synchronized (sBgLock) {
+            for (ItemInfo item : sBgItemsIdMap) {
+                if (item instanceof ShortcutInfo) {
+                    ShortcutInfo info = (ShortcutInfo) item;
+                    Intent targetIntent = info.promisedIntent == null
+                            ? info.intent : info.promisedIntent;
+                    if (targetIntent != null && info.user.equals(user)) {
+                        String s = targetIntent.toUri(0);
+                        if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /**
      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
      */
-    FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
+    FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {
         final ContentResolver cr = context.getContentResolver();
         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
                 "_id=? and (itemType=? or itemType=?)",
@@ -951,6 +956,7 @@
                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+                final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);
 
                 FolderInfo folderInfo = null;
                 switch (c.getInt(itemTypeIndex)) {
@@ -959,12 +965,14 @@
                         break;
                 }
 
+                // Do not trim the folder label, as is was set by the user.
                 folderInfo.title = c.getString(titleIndex);
                 folderInfo.id = id;
                 folderInfo.container = c.getInt(containerIndex);
                 folderInfo.screenId = c.getInt(screenIndex);
                 folderInfo.cellX = c.getInt(cellXIndex);
                 folderInfo.cellY = c.getInt(cellYIndex);
+                folderInfo.options = c.getInt(optionsIndex);
 
                 return folderInfo;
             }
@@ -979,8 +987,8 @@
      * Add an item to the database in a specified container. Sets the container, screen, cellX and
      * cellY fields of the item. Also assigns an ID to the item.
      */
-    static void addItemToDatabase(Context context, final ItemInfo item, final long container,
-            final long screenId, final int cellX, final int cellY, final boolean notify) {
+    public static void addItemToDatabase(Context context, final ItemInfo item, final long container,
+            final long screenId, final int cellX, final int cellY) {
         item.container = container;
         item.cellX = cellX;
         item.cellY = cellY;
@@ -999,13 +1007,11 @@
 
         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();
         values.put(LauncherSettings.Favorites._ID, item.id);
-        item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
 
         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
         Runnable r = new Runnable() {
             public void run() {
-                cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
-                        LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
+                cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);
 
                 // Lock on mBgLock *after* the db operation
                 synchronized (sBgLock) {
@@ -1056,7 +1062,7 @@
                 return cn.getPackageName().equals(pn) && info.user.equals(user);
             }
         };
-        return filterItemInfos(sBgItemsIdMap.values(), filter);
+        return filterItemInfos(sBgItemsIdMap, filter);
     }
 
     /**
@@ -1072,7 +1078,7 @@
      * @param context
      * @param item
      */
-    static void deleteItemFromDatabase(Context context, final ItemInfo item) {
+    public static void deleteItemFromDatabase(Context context, final ItemInfo item) {
         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
         items.add(item);
         deleteItemsFromDatabase(context, items);
@@ -1085,11 +1091,10 @@
      */
     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {
         final ContentResolver cr = context.getContentResolver();
-
         Runnable r = new Runnable() {
             public void run() {
                 for (ItemInfo item : items) {
-                    final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);
+                    final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);
                     cr.delete(uri, null, null);
 
                     // Lock on mBgLock *after* the db operation
@@ -1097,7 +1102,7 @@
                         switch (item.itemType) {
                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                                 sBgFolders.remove(item.id);
-                                for (ItemInfo info: sBgItemsIdMap.values()) {
+                                for (ItemInfo info: sBgItemsIdMap) {
                                     if (info.container == item.id) {
                                         // We are deleting a folder which still contains items that
                                         // think they are contained by that folder.
@@ -1117,7 +1122,6 @@
                                 break;
                         }
                         sBgItemsIdMap.remove(item.id);
-                        sBgDbIconCache.remove(item);
                     }
                 }
             }
@@ -1130,10 +1134,6 @@
      * a list of screen ids in the order that they should appear.
      */
     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);
-        Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);
-
         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);
         final ContentResolver cr = context.getContentResolver();
         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
@@ -1180,27 +1180,25 @@
     /**
      * Remove the contents of the specified folder from the database
      */
-    static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
+    public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {
         final ContentResolver cr = context.getContentResolver();
 
         Runnable r = new Runnable() {
             public void run() {
-                cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
+                cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
                 // Lock on mBgLock *after* the db operation
                 synchronized (sBgLock) {
                     sBgItemsIdMap.remove(info.id);
                     sBgFolders.remove(info.id);
-                    sBgDbIconCache.remove(info);
                     sBgWorkspaceItems.remove(info);
                 }
 
-                cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
+                cr.delete(LauncherSettings.Favorites.CONTENT_URI,
                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
                 // Lock on mBgLock *after* the db operation
                 synchronized (sBgLock) {
                     for (ItemInfo childInfo : info.contents) {
                         sBgItemsIdMap.remove(childInfo.id);
-                        sBgDbIconCache.remove(childInfo);
                     }
                 }
             }
@@ -1213,6 +1211,9 @@
      */
     public void initialize(Callbacks callbacks) {
         synchronized (mLock) {
+            // Disconnect any of the callbacks and drawables associated with ItemInfos on the
+            // workspace to prevent leaking Launcher activities on orientation change.
+            unbindItemInfosAndClearQueuedBindRunnables();
             mCallbacks = new WeakReference<Callbacks>(callbacks);
         }
     }
@@ -1265,7 +1266,6 @@
                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,
                     user));
         }
-
     }
 
     /**
@@ -1280,24 +1280,15 @@
         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
             // If we have changed locale we need to clear out the labels in all apps/workspace.
             forceReload();
-        } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-             // Check if configuration change was an mcc/mnc change which would affect app resources
-             // and we would need to clear out the labels in all apps/workspace. Same handling as
-             // above for ACTION_LOCALE_CHANGED
-             Configuration currentConfig = context.getResources().getConfiguration();
-             if (mPreviousConfigMcc != currentConfig.mcc) {
-                   Log.d(TAG, "Reload apps on config change. curr_mcc:"
-                       + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);
-                   forceReload();
-             }
-             // Update previousConfig
-             mPreviousConfigMcc = currentConfig.mcc;
         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||
                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {
             Callbacks callbacks = getCallback();
             if (callbacks != null) {
                 callbacks.bindSearchablesChanged();
             }
+        } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)
+                || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+            forceReload();
         }
     }
 
@@ -1336,38 +1327,32 @@
             }
         }
         if (runLoader) {
-            startLoader(false, PagedView.INVALID_RESTORE_PAGE);
+            startLoader(PagedView.INVALID_RESTORE_PAGE);
         }
     }
 
-    // If there is already a loader task running, tell it to stop.
-    // returns true if isLaunching() was true on the old task
-    private boolean stopLoaderLocked() {
-        boolean isLaunching = false;
+    /**
+     * If there is already a loader task running, tell it to stop.
+     */
+    private void stopLoaderLocked() {
         LoaderTask oldTask = mLoaderTask;
         if (oldTask != null) {
-            if (oldTask.isLaunching()) {
-                isLaunching = true;
-            }
             oldTask.stopLocked();
         }
-        return isLaunching;
     }
 
     public boolean isCurrentCallbacks(Callbacks callbacks) {
         return (mCallbacks != null && mCallbacks.get() == callbacks);
     }
 
-    public void startLoader(boolean isLaunching, int synchronousBindPage) {
-        startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);
+    public void startLoader(int synchronousBindPage) {
+        startLoader(synchronousBindPage, LOADER_FLAG_NONE);
     }
 
-    public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
+    public void startLoader(int synchronousBindPage, int loadFlags) {
+        // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems
+        InstallShortcutReceiver.enableInstallQueue();
         synchronized (mLock) {
-            if (DEBUG_LOADERS) {
-                Log.d(TAG, "startLoader isLaunching=" + isLaunching);
-            }
-
             // Clear any deferred bind-runnables from the synchronized load process
             // We must do this before any loading/binding is scheduled below.
             synchronized (mDeferredBindRunnables) {
@@ -1377,11 +1362,10 @@
             // Don't bother to start the thread if we know it's not going to do anything
             if (mCallbacks != null && mCallbacks.get() != null) {
                 // If there is already one running, tell it to stop.
-                // also, don't downgrade isLaunching if we're already running
-                isLaunching = isLaunching || stopLoaderLocked();
-                mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
+                stopLoaderLocked();
+                mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);
                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
-                        && mAllAppsLoaded && mWorkspaceLoaded) {
+                        && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {
                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);
                 } else {
                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);
@@ -1401,7 +1385,17 @@
                 mDeferredBindRunnables.clear();
             }
             for (final Runnable r : deferredBindRunnables) {
-                mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);
+                mHandler.post(r);
+            }
+        }
+
+        // Run all the bind complete runnables after workspace is bound.
+        if (!mBindCompleteRunnables.isEmpty()) {
+            synchronized (mBindCompleteRunnables) {
+                for (final Runnable r : mBindCompleteRunnables) {
+                    runOnWorkerThread(r);
+                }
+                mBindCompleteRunnables.clear();
             }
         }
     }
@@ -1414,40 +1408,31 @@
         }
     }
 
-    /** Loads the workspace screens db into a map of Rank -> ScreenId */
-    private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {
+    /**
+     * Loads the workspace screen ids in an ordered list.
+     */
+    @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) {
         final ContentResolver contentResolver = context.getContentResolver();
         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
-        final Cursor sc = contentResolver.query(screensUri, null, null, null, null);
-        TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();
 
+        // Get screens ordered by rank.
+        final Cursor sc = contentResolver.query(screensUri, null, null, null,
+                LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+        ArrayList<Long> screenIds = new ArrayList<Long>();
         try {
-            final int idIndex = sc.getColumnIndexOrThrow(
-                    LauncherSettings.WorkspaceScreens._ID);
-            final int rankIndex = sc.getColumnIndexOrThrow(
-                    LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+            final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);
             while (sc.moveToNext()) {
                 try {
-                    long screenId = sc.getLong(idIndex);
-                    int rank = sc.getInt(rankIndex);
-                    orderedScreens.put(rank, screenId);
+                    screenIds.add(sc.getLong(idIndex));
                 } catch (Exception e) {
-                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);
+                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted"
+                            + " - invalid screens: " + e, true);
                 }
             }
         } finally {
             sc.close();
         }
-
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);
-        ArrayList<String> orderedScreensPairs= new ArrayList<String>();
-        for (Integer i : orderedScreens.keySet()) {
-            orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");
-        }
-        Launcher.addDumpLog(TAG, "11683562 -   screens: " +
-                TextUtils.join(", ", orderedScreensPairs), true);
-        return orderedScreens;
+        return screenIds;
     }
 
     public boolean isAllAppsLoaded() {
@@ -1471,31 +1456,21 @@
      */
     private class LoaderTask implements Runnable {
         private Context mContext;
-        private boolean mIsLaunching;
-        private boolean mIsLoadingAndBindingWorkspace;
+        @Thunk boolean mIsLoadingAndBindingWorkspace;
         private boolean mStopped;
-        private boolean mLoadAndBindStepFinished;
+        @Thunk boolean mLoadAndBindStepFinished;
         private int mFlags;
 
-        private HashMap<Object, CharSequence> mLabelCache;
-
-        LoaderTask(Context context, boolean isLaunching, int flags) {
+        LoaderTask(Context context, int flags) {
             mContext = context;
-            mIsLaunching = isLaunching;
-            mLabelCache = new HashMap<Object, CharSequence>();
             mFlags = flags;
         }
 
-        boolean isLaunching() {
-            return mIsLaunching;
-        }
-
         boolean isLoadingWorkspace() {
             return mIsLoadingAndBindingWorkspace;
         }
 
-        /** Returns whether this is an upgrade path */
-        private boolean loadAndBindWorkspace() {
+        private void loadAndBindWorkspace() {
             mIsLoadingAndBindingWorkspace = true;
 
             // Load the workspace
@@ -1503,20 +1478,18 @@
                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);
             }
 
-            boolean isUpgradePath = false;
             if (!mWorkspaceLoaded) {
-                isUpgradePath = loadWorkspace();
+                loadWorkspace();
                 synchronized (LoaderTask.this) {
                     if (mStopped) {
-                        return isUpgradePath;
+                        return;
                     }
                     mWorkspaceLoaded = true;
                 }
             }
 
             // Bind the workspace
-            bindWorkspace(-1, isUpgradePath);
-            return isUpgradePath;
+            bindWorkspace(-1);
         }
 
         private void waitForIdle() {
@@ -1538,7 +1511,7 @@
                         }
                     });
 
-                while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {
+                while (!mStopped && !mLoadAndBindStepFinished) {
                     try {
                         // Just in case mFlushingWorkerThread changes but we aren't woken up,
                         // wait no longer than 1sec at a time
@@ -1585,72 +1558,35 @@
 
             // Divide the set of loaded items into those that we are binding synchronously, and
             // everything else that is to be bound normally (asynchronously).
-            bindWorkspace(synchronousBindPage, false);
+            bindWorkspace(synchronousBindPage);
             // XXX: For now, continue posting the binding of AllApps as there are other issues that
             //      arise from that.
             onlyBindAllApps();
         }
 
         public void run() {
-            boolean isUpgrade = false;
-
             synchronized (mLock) {
+                if (mStopped) {
+                    return;
+                }
                 mIsLoaderTaskRunning = true;
             }
             // Optimize for end-user experience: if the Launcher is up and // running with the
             // All Apps interface in the foreground, load All Apps first. Otherwise, load the
             // workspace first (default).
             keep_running: {
-                // Elevate priority when Home launches for the first time to avoid
-                // starving at boot time. Staring at a blank home is not cool.
-                synchronized (mLock) {
-                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +
-                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));
-                    android.os.Process.setThreadPriority(mIsLaunching
-                            ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
-                }
                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
-                isUpgrade = loadAndBindWorkspace();
+                loadAndBindWorkspace();
 
                 if (mStopped) {
                     break keep_running;
                 }
 
-                // Whew! Hard work done.  Slow us down, and wait until the UI thread has
-                // settled down.
-                synchronized (mLock) {
-                    if (mIsLaunching) {
-                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");
-                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                    }
-                }
                 waitForIdle();
 
                 // second step
                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
                 loadAndBindAllApps();
-
-                // Restore the default thread priority after we are done loading items
-                synchronized (mLock) {
-                    android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-                }
-            }
-
-            // Update the saved icons if necessary
-            if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
-            synchronized (sBgLock) {
-                for (Object key : sBgDbIconCache.keySet()) {
-                    updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));
-                }
-                sBgDbIconCache.clear();
-            }
-
-            if (LauncherAppState.isDisableAllApps()) {
-                // Ensure that all the applications that are in the system are
-                // represented on the home screen.
-                if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {
-                    verifyApplications();
-                }
             }
 
             // Clear out this reference, otherwise we end up holding it until all of the
@@ -1663,6 +1599,7 @@
                     mLoaderTask = null;
                 }
                 mIsLoaderTaskRunning = false;
+                mHasLoaderCompletedOnce = true;
             }
         }
 
@@ -1703,34 +1640,12 @@
             }
         }
 
-        private void verifyApplications() {
-            final Context context = mApp.getContext();
-
-            // Cross reference all the applications in our apps list with items in the workspace
-            ArrayList<ItemInfo> tmpInfos;
-            ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();
-            synchronized (sBgLock) {
-                for (AppInfo app : mBgAllAppsList.data) {
-                    tmpInfos = getItemInfoForComponentName(app.componentName, app.user);
-                    if (tmpInfos.isEmpty()) {
-                        // We are missing an application icon, so add this to the workspace
-                        added.add(app);
-                        // This is a rare event, so lets log it
-                        Log.e(TAG, "Missing Application on load: " + app);
-                    }
-                }
-            }
-            if (!added.isEmpty()) {
-                addAndBindAddedWorkspaceApps(context, added);
-            }
-        }
-
         // check & update map of what's occupied; used to discard overlapping/invalid items
-        private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {
+        private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {
             LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            final int countX = (int) grid.numColumns;
-            final int countY = (int) grid.numRows;
+            InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+            final int countX = (int) profile.numColumns;
+            final int countY = (int) profile.numRows;
 
             long containerIndex = item.screenId;
             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
@@ -1746,10 +1661,10 @@
                 final ItemInfo[][] hotseatItems =
                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
 
-                if (item.screenId >= grid.numHotseatIcons) {
+                if (item.screenId >= profile.numHotseatIcons) {
                     Log.e(TAG, "Error loading shortcut " + item
                             + " into hotseat position " + item.screenId
-                            + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)
+                            + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1)
                             + ")");
                     return false;
                 }
@@ -1767,7 +1682,7 @@
                         return true;
                     }
                 } else {
-                    final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];
+                    final ItemInfo[][] items = new ItemInfo[(int) profile.numHotseatIcons][1];
                     items[(int) item.screenId][0] = item;
                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);
                     return true;
@@ -1822,31 +1737,25 @@
                 sBgAppWidgets.clear();
                 sBgFolders.clear();
                 sBgItemsIdMap.clear();
-                sBgDbIconCache.clear();
                 sBgWorkspaceScreens.clear();
             }
         }
 
-        /** Returns whether this is an upgrade path */
-        private boolean loadWorkspace() {
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);
-
+        private void loadWorkspace() {
             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
 
             final Context context = mContext;
             final ContentResolver contentResolver = context.getContentResolver();
             final PackageManager manager = context.getPackageManager();
-            final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
             final boolean isSafeMode = manager.isSafeMode();
             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
             final boolean isSdCardReady = context.registerReceiver(null,
                     new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;
 
             LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            int countX = (int) grid.numColumns;
-            int countY = (int) grid.numRows;
+            InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+            int countX = (int) profile.numColumns;
+            int countY = (int) profile.numRows;
 
             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {
                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);
@@ -1863,27 +1772,21 @@
                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();
             }
 
-            // This code path is for our old migration code and should no longer be exercised
-            boolean loadedOldDb = false;
-
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);
-
             synchronized (sBgLock) {
                 clearSBgDataStructures();
-                final HashSet<String> installingPkgs = PackageInstallerCompat
+                final HashMap<String, Integer> installingPkgs = PackageInstallerCompat
                         .getInstance(mContext).updateAndGetActiveSessionCache();
 
                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
                 final ArrayList<Long> restoredRows = new ArrayList<Long>();
-                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;
+                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);
 
                 // +1 for the hotseat (it can be larger than the workspace)
                 // Load workspace in reverse order to ensure that latest items are loaded first (and
                 // before any earlier duplicates)
-                final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();
+                final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();
 
                 try {
                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -1891,13 +1794,6 @@
                             (LauncherSettings.Favorites.INTENT);
                     final int titleIndex = c.getColumnIndexOrThrow
                             (LauncherSettings.Favorites.TITLE);
-                    final int iconTypeIndex = c.getColumnIndexOrThrow(
-                            LauncherSettings.Favorites.ICON_TYPE);
-                    final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
-                    final int iconPackageIndex = c.getColumnIndexOrThrow(
-                            LauncherSettings.Favorites.ICON_PACKAGE);
-                    final int iconResourceIndex = c.getColumnIndexOrThrow(
-                            LauncherSettings.Favorites.ICON_RESOURCE);
                     final int containerIndex = c.getColumnIndexOrThrow(
                             LauncherSettings.Favorites.CONTAINER);
                     final int itemTypeIndex = c.getColumnIndexOrThrow(
@@ -1916,19 +1812,27 @@
                             (LauncherSettings.Favorites.SPANX);
                     final int spanYIndex = c.getColumnIndexOrThrow(
                             LauncherSettings.Favorites.SPANY);
+                    final int rankIndex = c.getColumnIndexOrThrow(
+                            LauncherSettings.Favorites.RANK);
                     final int restoredIndex = c.getColumnIndexOrThrow(
                             LauncherSettings.Favorites.RESTORED);
                     final int profileIdIndex = c.getColumnIndexOrThrow(
                             LauncherSettings.Favorites.PROFILE_ID);
-                    //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
-                    //final int displayModeIndex = c.getColumnIndexOrThrow(
-                    //        LauncherSettings.Favorites.DISPLAY_MODE);
+                    final int optionsIndex = c.getColumnIndexOrThrow(
+                            LauncherSettings.Favorites.OPTIONS);
+                    final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);
+
+                    final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();
+                    for (UserHandleCompat user : mUserManager.getUserProfiles()) {
+                        allUsers.put(mUserManager.getSerialNumberForUser(user), user);
+                    }
 
                     ShortcutInfo info;
                     String intentDescription;
                     LauncherAppWidgetInfo appWidgetInfo;
                     int container;
                     long id;
+                    long serialNumber;
                     Intent intent;
                     UserHandleCompat user;
 
@@ -1937,16 +1841,18 @@
                             int itemType = c.getInt(itemTypeIndex);
                             boolean restored = 0 != c.getInt(restoredIndex);
                             boolean allowMissingTarget = false;
+                            container = c.getInt(containerIndex);
 
                             switch (itemType) {
                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                                 id = c.getLong(idIndex);
                                 intentDescription = c.getString(intentIndex);
-                                long serialNumber = c.getInt(profileIdIndex);
-                                user = mUserManager.getUserForSerialNumber(serialNumber);
+                                serialNumber = c.getInt(profileIdIndex);
+                                user = allUsers.get(serialNumber);
                                 int promiseType = c.getInt(restoredIndex);
                                 int disabledState = 0;
+                                boolean itemReplaced = false;
                                 if (user == null) {
                                     // User has been deleted remove the item.
                                     itemsToRemove.add(id);
@@ -1978,9 +1884,7 @@
                                                     ContentValues values = new ContentValues();
                                                     values.put(LauncherSettings.Favorites.INTENT,
                                                             intent.toUri(0));
-                                                    String where = BaseColumns._ID + "= ?";
-                                                    String[] args = {Long.toString(id)};
-                                                    contentResolver.update(contentUri, values, where, args);
+                                                    updateItem(id, values);
                                                 }
                                             }
 
@@ -2004,16 +1908,33 @@
 
                                             if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
                                                 // Restore has started once.
-                                            } else if (installingPkgs.contains(cn.getPackageName())) {
+                                            } else if (installingPkgs.containsKey(cn.getPackageName())) {
                                                 // App restore has started. Update the flag
                                                 promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;
                                                 ContentValues values = new ContentValues();
                                                 values.put(LauncherSettings.Favorites.RESTORED,
                                                         promiseType);
-                                                String where = BaseColumns._ID + "= ?";
-                                                String[] args = {Long.toString(id)};
-                                                contentResolver.update(contentUri, values, where, args);
+                                                updateItem(id, values);
+                                            } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
+                                                // This is a common app. Try to replace this.
+                                                int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseType);
+                                                CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, context);
+                                                if (parser.findDefaultApp()) {
+                                                    // Default app found. Replace it.
+                                                    intent = parser.parsedIntent;
+                                                    cn = intent.getComponent();
+                                                    ContentValues values = parser.parsedValues;
+                                                    values.put(LauncherSettings.Favorites.RESTORED, 0);
+                                                    updateItem(id, values);
+                                                    restored = false;
+                                                    itemReplaced = true;
 
+                                                } else if (REMOVE_UNRESTORED_ICONS) {
+                                                    Launcher.addDumpLog(TAG,
+                                                            "Unrestored package removed: " + cn, true);
+                                                    itemsToRemove.add(id);
+                                                    continue;
+                                                }
                                             } else if (REMOVE_UNRESTORED_ICONS) {
                                                 Launcher.addDumpLog(TAG,
                                                         "Unrestored package removed: " + cn, true);
@@ -2059,12 +1980,26 @@
                                     continue;
                                 }
 
-                                if (restored) {
+                                boolean useLowResIcon = container >= 0 &&
+                                        c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
+
+                                if (itemReplaced) {
+                                    if (user.equals(UserHandleCompat.myUserHandle())) {
+                                        info = getAppShortcutInfo(manager, intent, user, context, null,
+                                                cursorIconInfo.iconIndex, titleIndex,
+                                                false, useLowResIcon);
+                                    } else {
+                                        // Don't replace items for other profiles.
+                                        itemsToRemove.add(id);
+                                        continue;
+                                    }
+                                } else if (restored) {
                                     if (user.equals(UserHandleCompat.myUserHandle())) {
                                         Launcher.addDumpLog(TAG,
                                                 "constructing info for partially restored package",
                                                 true);
-                                        info = getRestoredItemInfo(c, titleIndex, intent, promiseType);
+                                        info = getRestoredItemInfo(c, titleIndex, intent,
+                                                promiseType, itemType, cursorIconInfo, context);
                                         intent = getRestoredItemIntent(c, context, intent);
                                     } else {
                                         // Don't restore items for other profiles.
@@ -2073,12 +2008,11 @@
                                     }
                                 } else if (itemType ==
                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                                    info = getShortcutInfo(manager, intent, user, context, c,
-                                            iconIndex, titleIndex, mLabelCache, allowMissingTarget);
+                                    info = getAppShortcutInfo(manager, intent, user, context, c,
+                                            cursorIconInfo.iconIndex, titleIndex,
+                                            allowMissingTarget, useLowResIcon);
                                 } else {
-                                    info = getShortcutInfo(c, context, iconTypeIndex,
-                                            iconPackageIndex, iconResourceIndex, iconIndex,
-                                            titleIndex);
+                                    info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);
 
                                     // App shortcuts that used to be automatically added to Launcher
                                     // didn't always have the correct intent flags set, so do that
@@ -2096,14 +2030,17 @@
                                 if (info != null) {
                                     info.id = id;
                                     info.intent = intent;
-                                    container = c.getInt(containerIndex);
                                     info.container = container;
                                     info.screenId = c.getInt(screenIndex);
                                     info.cellX = c.getInt(cellXIndex);
                                     info.cellY = c.getInt(cellYIndex);
+                                    info.rank = c.getInt(rankIndex);
                                     info.spanX = 1;
                                     info.spanY = 1;
                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+                                    if (info.promisedIntent != null) {
+                                        info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+                                    }
                                     info.isDisabled = disabledState;
                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
@@ -2115,6 +2052,18 @@
                                         break;
                                     }
 
+                                    if (restored) {
+                                        ComponentName cn = info.getTargetComponent();
+                                        if (cn != null) {
+                                            Integer progress = installingPkgs.get(cn.getPackageName());
+                                            if (progress != null) {
+                                                info.setInstallProgress(progress);
+                                            } else {
+                                                info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+                                            }
+                                        }
+                                    }
+
                                     switch (container) {
                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:
                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
@@ -2128,10 +2077,6 @@
                                         break;
                                     }
                                     sBgItemsIdMap.put(info.id, info);
-
-                                    // now that we've loaded everthing re-save it with the
-                                    // icon in case it disappears somehow.
-                                    queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);
                                 } else {
                                     throw new RuntimeException("Unexpected null ShortcutInfo");
                                 }
@@ -2141,15 +2086,16 @@
                                 id = c.getLong(idIndex);
                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
 
+                                // Do not trim the folder label, as is was set by the user.
                                 folderInfo.title = c.getString(titleIndex);
                                 folderInfo.id = id;
-                                container = c.getInt(containerIndex);
                                 folderInfo.container = container;
                                 folderInfo.screenId = c.getInt(screenIndex);
                                 folderInfo.cellX = c.getInt(cellXIndex);
                                 folderInfo.cellY = c.getInt(cellYIndex);
                                 folderInfo.spanX = 1;
                                 folderInfo.spanY = 1;
+                                folderInfo.options = c.getInt(optionsIndex);
 
                                 // check & update map of what's occupied
                                 if (!checkItemPlacement(occupied, folderInfo)) {
@@ -2174,28 +2120,41 @@
                                 break;
 
                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+                            case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
                                 // Read all Launcher-specific widget details
+                                boolean customWidget = itemType ==
+                                    LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
                                 int appWidgetId = c.getInt(appWidgetIdIndex);
+                                serialNumber = c.getLong(profileIdIndex);
                                 String savedProvider = c.getString(appWidgetProviderIndex);
                                 id = c.getLong(idIndex);
+                                user = allUsers.get(serialNumber);
+                                if (user == null) {
+                                    itemsToRemove.add(id);
+                                    continue;
+                                }
+
                                 final ComponentName component =
                                         ComponentName.unflattenFromString(savedProvider);
 
                                 final int restoreStatus = c.getInt(restoredIndex);
                                 final boolean isIdValid = (restoreStatus &
                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;
-
                                 final boolean wasProviderReady = (restoreStatus &
                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;
 
-                                final AppWidgetProviderInfo provider = isIdValid
-                                        ? widgets.getAppWidgetInfo(appWidgetId)
-                                        : findAppWidgetProviderInfoWithComponent(context, component);
+                                final LauncherAppWidgetProviderInfo provider =
+                                        LauncherModel.getProviderInfo(context,
+                                                ComponentName.unflattenFromString(savedProvider),
+                                                user);
 
                                 final boolean isProviderReady = isValidProvider(provider);
-                                if (!isSafeMode && wasProviderReady && !isProviderReady) {
+                                if (!isSafeMode && !customWidget &&
+                                        wasProviderReady && !isProviderReady) {
                                     String log = "Deleting widget that isn't installed anymore: "
                                             + "id=" + id + " appWidgetId=" + appWidgetId;
+
                                     Log.e(TAG, log);
                                     Launcher.addDumpLog(TAG, log, false);
                                     itemsToRemove.add(id);
@@ -2203,10 +2162,6 @@
                                     if (isProviderReady) {
                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
                                                 provider.provider);
-                                        int[] minSpan =
-                                                Launcher.getMinSpanForWidget(context, provider);
-                                        appWidgetInfo.minSpanX = minSpan[0];
-                                        appWidgetInfo.minSpanY = minSpan[1];
 
                                         int status = restoreStatus;
                                         if (!wasProviderReady) {
@@ -2229,10 +2184,11 @@
                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
                                                 component);
                                         appWidgetInfo.restoreStatus = restoreStatus;
+                                        Integer installProgress = installingPkgs.get(component.getPackageName());
 
                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {
                                             // Restore has started once.
-                                        } else if (installingPkgs.contains(component.getPackageName())) {
+                                        } else if (installProgress != null) {
                                             // App restore has started. Update the flag
                                             appWidgetInfo.restoreStatus |=
                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
@@ -2242,6 +2198,9 @@
                                             itemsToRemove.add(id);
                                             continue;
                                         }
+
+                                        appWidgetInfo.installProgress =
+                                                installProgress == null ? 0 : installProgress;
                                     }
 
                                     appWidgetInfo.id = id;
@@ -2250,8 +2209,8 @@
                                     appWidgetInfo.cellY = c.getInt(cellYIndex);
                                     appWidgetInfo.spanX = c.getInt(spanXIndex);
                                     appWidgetInfo.spanY = c.getInt(spanYIndex);
+                                    appWidgetInfo.user = user;
 
-                                    container = c.getInt(containerIndex);
                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
                                         Log.e(TAG, "Widget found where container != " +
@@ -2259,24 +2218,26 @@
                                         continue;
                                     }
 
-                                    appWidgetInfo.container = c.getInt(containerIndex);
+                                    appWidgetInfo.container = container;
                                     // check & update map of what's occupied
                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {
                                         itemsToRemove.add(id);
                                         break;
                                     }
 
-                                    String providerName = appWidgetInfo.providerName.flattenToString();
-                                    if (!providerName.equals(savedProvider) ||
-                                            (appWidgetInfo.restoreStatus != restoreStatus)) {
-                                        ContentValues values = new ContentValues();
-                                        values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
-                                                providerName);
-                                        values.put(LauncherSettings.Favorites.RESTORED,
-                                                appWidgetInfo.restoreStatus);
-                                        String where = BaseColumns._ID + "= ?";
-                                        String[] args = {Long.toString(id)};
-                                        contentResolver.update(contentUri, values, where, args);
+                                    if (!customWidget) {
+                                        String providerName =
+                                                appWidgetInfo.providerName.flattenToString();
+                                        if (!providerName.equals(savedProvider) ||
+                                                (appWidgetInfo.restoreStatus != restoreStatus)) {
+                                            ContentValues values = new ContentValues();
+                                            values.put(
+                                                    LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+                                                    providerName);
+                                            values.put(LauncherSettings.Favorites.RESTORED,
+                                                    appWidgetInfo.restoreStatus);
+                                            updateItem(id, values);
+                                        }
                                     }
                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
                                     sBgAppWidgets.add(appWidgetInfo);
@@ -2296,44 +2257,35 @@
                 // Break early if we've stopped loading
                 if (mStopped) {
                     clearSBgDataStructures();
-                    return false;
+                    return;
                 }
 
                 if (itemsToRemove.size() > 0) {
-                    ContentProviderClient client = contentResolver.acquireContentProviderClient(
-                            contentUri);
                     // Remove dead items
-                    for (long id : itemsToRemove) {
-                        if (DEBUG_LOADERS) {
-                            Log.d(TAG, "Removed id = " + id);
-                        }
-                        // Don't notify content observers
-                        try {
-                            client.delete(LauncherSettings.Favorites.getContentUri(id, false),
-                                    null, null);
-                        } catch (RemoteException e) {
-                            Log.w(TAG, "Could not remove id = " + id);
-                        }
+                    contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI,
+                            Utilities.createDbSelectionQuery(
+                                    LauncherSettings.Favorites._ID, itemsToRemove), null);
+                    if (DEBUG_LOADERS) {
+                        Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(
+                                LauncherSettings.Favorites._ID, itemsToRemove));
+                    }
+
+                    // Remove any empty folder
+                    for (long folderId : LauncherAppState.getLauncherProvider()
+                            .deleteEmptyFolders()) {
+                        sBgWorkspaceItems.remove(sBgFolders.get(folderId));
+                        sBgFolders.remove(folderId);
+                        sBgItemsIdMap.remove(folderId);
                     }
                 }
 
                 if (restoredRows.size() > 0) {
-                    ContentProviderClient updater = contentResolver.acquireContentProviderClient(
-                            contentUri);
                     // Update restored items that no longer require special handling
-                    try {
-                        StringBuilder selectionBuilder = new StringBuilder();
-                        selectionBuilder.append(LauncherSettings.Favorites._ID);
-                        selectionBuilder.append(" IN (");
-                        selectionBuilder.append(TextUtils.join(", ", restoredRows));
-                        selectionBuilder.append(")");
-                        ContentValues values = new ContentValues();
-                        values.put(LauncherSettings.Favorites.RESTORED, 0);
-                        updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
-                                values, selectionBuilder.toString(), null);
-                    } catch (RemoteException e) {
-                        Log.w(TAG, "Could not update restored rows");
-                    }
+                    ContentValues values = new ContentValues();
+                    values.put(LauncherSettings.Favorites.RESTORED, 0);
+                    contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values,
+                            Utilities.createDbSelectionQuery(
+                                    LauncherSettings.Favorites._ID, restoredRows), null);
                 }
 
                 if (!isSdCardReady && !sPendingPackages.isEmpty()) {
@@ -2342,63 +2294,22 @@
                             null, sWorker);
                 }
 
-                if (loadedOldDb) {
-                    long maxScreenId = 0;
-                    // If we're importing we use the old screen order.
-                    for (ItemInfo item: sBgItemsIdMap.values()) {
-                        long screenId = item.screenId;
-                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
-                                !sBgWorkspaceScreens.contains(screenId)) {
-                            sBgWorkspaceScreens.add(screenId);
-                            if (screenId > maxScreenId) {
-                                maxScreenId = screenId;
-                            }
-                        }
-                    }
-                    Collections.sort(sBgWorkspaceScreens);
-                    // Log to disk
-                    Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);
-                    Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +
-                            TextUtils.join(", ", sBgWorkspaceScreens), true);
+                sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
 
-                    LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);
+                // Remove any empty screens
+                ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
+                for (ItemInfo item: sBgItemsIdMap) {
+                    long screenId = item.screenId;
+                    if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+                            unusedScreens.contains(screenId)) {
+                        unusedScreens.remove(screenId);
+                    }
+                }
+
+                // If there are any empty screens remove them, and update.
+                if (unusedScreens.size() != 0) {
+                    sBgWorkspaceScreens.removeAll(unusedScreens);
                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
-
-                    // Update the max item id after we load an old db
-                    long maxItemId = 0;
-                    // If we're importing we use the old screen order.
-                    for (ItemInfo item: sBgItemsIdMap.values()) {
-                        maxItemId = Math.max(maxItemId, item.id);
-                    }
-                    LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);
-                } else {
-                    TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);
-                    for (Integer i : orderedScreens.keySet()) {
-                        sBgWorkspaceScreens.add(orderedScreens.get(i));
-                    }
-                    // Log to disk
-                    Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +
-                            TextUtils.join(", ", sBgWorkspaceScreens), true);
-
-                    // Remove any empty screens
-                    ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
-                    for (ItemInfo item: sBgItemsIdMap.values()) {
-                        long screenId = item.screenId;
-                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
-                                unusedScreens.contains(screenId)) {
-                            unusedScreens.remove(screenId);
-                        }
-                    }
-
-                    // If there are any empty screens remove them, and update.
-                    if (unusedScreens.size() != 0) {
-                        // Log to disk
-                        Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +
-                                TextUtils.join(", ", unusedScreens), true);
-
-                        sBgWorkspaceScreens.removeAll(unusedScreens);
-                        updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
-                    }
                 }
 
                 if (DEBUG_LOADERS) {
@@ -2408,14 +2319,13 @@
                     for (int y = 0; y < countY; y++) {
                         String line = "";
 
-                        Iterator<Long> iter = occupied.keySet().iterator();
-                        while (iter.hasNext()) {
-                            long screenId = iter.next();
+                        for (int i = 0; i < nScreens; i++) {
+                            long screenId = occupied.keyAt(i);
                             if (screenId > 0) {
                                 line += " | ";
                             }
+                            ItemInfo[][] screen = occupied.valueAt(i);
                             for (int x = 0; x < countX; x++) {
-                                ItemInfo[][] screen = occupied.get(screenId);
                                 if (x < screen.length && y < screen[x].length) {
                                     line += (screen[x][y] != null) ? "#" : ".";
                                 } else {
@@ -2427,7 +2337,17 @@
                     }
                 }
             }
-            return loadedOldDb;
+        }
+
+        /**
+         * Partially updates the item without any notification. Must be called on the worker thread.
+         */
+        private void updateItem(long itemId, ContentValues update) {
+            mContext.getContentResolver().update(
+                    LauncherSettings.Favorites.CONTENT_URI,
+                    update,
+                    BaseColumns._ID + "= ?",
+                    new String[]{Long.toString(itemId)});
         }
 
         /** Filters the set of items who are directly or indirectly (via another container) on the
@@ -2496,14 +2416,17 @@
 
         /** Filters the set of folders which are on the specified screen. */
         private void filterCurrentFolders(long currentScreenId,
-                HashMap<Long, ItemInfo> itemsIdMap,
-                HashMap<Long, FolderInfo> folders,
-                HashMap<Long, FolderInfo> currentScreenFolders,
-                HashMap<Long, FolderInfo> otherScreenFolders) {
+                LongArrayMap<ItemInfo> itemsIdMap,
+                LongArrayMap<FolderInfo> folders,
+                LongArrayMap<FolderInfo> currentScreenFolders,
+                LongArrayMap<FolderInfo> otherScreenFolders) {
 
-            for (long id : folders.keySet()) {
+            int total = folders.size();
+            for (int i = 0; i < total; i++) {
+                long id = folders.keyAt(i);
+                FolderInfo folder = folders.valueAt(i);
+
                 ItemInfo info = itemsIdMap.get(id);
-                FolderInfo folder = folders.get(id);
                 if (info == null || folder == null) continue;
                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
                         info.screenId == currentScreenId) {
@@ -2518,13 +2441,13 @@
          * right) */
         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
             final LauncherAppState app = LauncherAppState.getInstance();
-            final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+            final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
             // XXX: review this
             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {
                 @Override
                 public int compare(ItemInfo lhs, ItemInfo rhs) {
-                    int cellCountX = (int) grid.numColumns;
-                    int cellCountY = (int) grid.numRows;
+                    int cellCountX = (int) profile.numColumns;
+                    int cellCountY = (int) profile.numRows;
                     int screenOffset = cellCountX * cellCountY;
                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat
                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +
@@ -2547,13 +2470,13 @@
                     }
                 }
             };
-            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+            runOnMainThread(r);
         }
 
         private void bindWorkspaceItems(final Callbacks oldCallbacks,
                 final ArrayList<ItemInfo> workspaceItems,
                 final ArrayList<LauncherAppWidgetInfo> appWidgets,
-                final HashMap<Long, FolderInfo> folders,
+                final LongArrayMap<FolderInfo> folders,
                 ArrayList<Runnable> deferredBindRunnables) {
 
             final boolean postOnMainThread = (deferredBindRunnables != null);
@@ -2578,7 +2501,7 @@
                         deferredBindRunnables.add(r);
                     }
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
 
@@ -2597,7 +2520,7 @@
                         deferredBindRunnables.add(r);
                     }
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
 
@@ -2616,7 +2539,7 @@
                 if (postOnMainThread) {
                     deferredBindRunnables.add(r);
                 } else {
-                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                    runOnMainThread(r);
                 }
             }
         }
@@ -2624,7 +2547,7 @@
         /**
          * Binds all loaded data to actual views on the main thread.
          */
-        private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {
+        private void bindWorkspace(int synchronizeBindPage) {
             final long t = SystemClock.uptimeMillis();
             Runnable r;
 
@@ -2641,15 +2564,18 @@
             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
             ArrayList<LauncherAppWidgetInfo> appWidgets =
                     new ArrayList<LauncherAppWidgetInfo>();
-            HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();
-            HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();
             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();
+
+            final LongArrayMap<FolderInfo> folders;
+            final LongArrayMap<ItemInfo> itemsIdMap;
+
             synchronized (sBgLock) {
                 workspaceItems.addAll(sBgWorkspaceItems);
                 appWidgets.addAll(sBgAppWidgets);
-                folders.putAll(sBgFolders);
-                itemsIdMap.putAll(sBgItemsIdMap);
                 orderedScreenIds.addAll(sBgWorkspaceScreens);
+
+                folders = sBgFolders.clone();
+                itemsIdMap = sBgItemsIdMap.clone();
             }
 
             final boolean isLoadingSynchronously =
@@ -2675,8 +2601,8 @@
                     new ArrayList<LauncherAppWidgetInfo>();
             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
                     new ArrayList<LauncherAppWidgetInfo>();
-            HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();
-            HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();
+            LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();
+            LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();
 
             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
                     otherWorkspaceItems);
@@ -2696,7 +2622,7 @@
                     }
                 }
             };
-            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+            runOnMainThread(r);
 
             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
 
@@ -2712,7 +2638,7 @@
                         }
                     }
                 };
-                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                runOnMainThread(r);
             }
 
             // Load all the remaining pages (if we are loading synchronously, we want to defer this
@@ -2728,7 +2654,7 @@
                 public void run() {
                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
-                        callbacks.finishBindingItems(isUpgradePath);
+                        callbacks.finishBindingItems();
                     }
 
                     // If we're profiling, ensure this is the last thing in the queue.
@@ -2745,7 +2671,7 @@
                     mDeferredBindRunnables.add(r);
                 }
             } else {
-                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+                runOnMainThread(r);
             }
         }
 
@@ -2759,6 +2685,12 @@
                     if (mStopped) {
                         return;
                     }
+                }
+                updateIconCache();
+                synchronized (LoaderTask.this) {
+                    if (mStopped) {
+                        return;
+                    }
                     mAllAppsLoaded = true;
                 }
             } else {
@@ -2766,6 +2698,27 @@
             }
         }
 
+        private void updateIconCache() {
+            // Ignore packages which have a promise icon.
+            HashSet<String> packagesToIgnore = new HashSet<>();
+            synchronized (sBgLock) {
+                for (ItemInfo info : sBgItemsIdMap) {
+                    if (info instanceof ShortcutInfo) {
+                        ShortcutInfo si = (ShortcutInfo) info;
+                        if (si.isPromise() && si.getTargetComponent() != null) {
+                            packagesToIgnore.add(si.getTargetComponent().getPackageName());
+                        }
+                    } else if (info instanceof LauncherAppWidgetInfo) {
+                        LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;
+                        if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
+                            packagesToIgnore.add(lawi.providerName.getPackageName());
+                        }
+                    }
+                }
+            }
+            mIconCache.updateDbIcons(packagesToIgnore);
+        }
+
         private void onlyBindAllApps() {
             final Callbacks oldCallbacks = mCallbacks.get();
             if (oldCallbacks == null) {
@@ -2778,12 +2731,14 @@
             @SuppressWarnings("unchecked")
             final ArrayList<AppInfo> list
                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();
+            final WidgetsModel widgetList = mBgWidgetsModel.clone();
             Runnable r = new Runnable() {
                 public void run() {
                     final long t = SystemClock.uptimeMillis();
                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
                         callbacks.bindAllApplications(list);
+                        callbacks.bindAllPackages(widgetList);
                     }
                     if (DEBUG_LOADERS) {
                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "
@@ -2809,19 +2764,14 @@
                 return;
             }
 
-            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
-            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();
 
             // Clear the list of apps
             mBgAllAppsList.clear();
-            SharedPreferences prefs = mContext.getSharedPreferences(
-                    LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
             for (UserHandleCompat user : profiles) {
                 // Query for the set of apps
                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-                List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+                final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
                 if (DEBUG_LOADERS) {
                     Log.d(TAG, "getActivityList took "
                             + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
@@ -2832,39 +2782,23 @@
                 if (apps == null || apps.isEmpty()) {
                     return;
                 }
-                // Sort the applications by name
-                final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-                Collections.sort(apps,
-                        new LauncherModel.ShortcutNameComparator(mLabelCache));
-                if (DEBUG_LOADERS) {
-                    Log.d(TAG, "sort took "
-                            + (SystemClock.uptimeMillis()-sortTime) + "ms");
-                }
 
                 // Create the ApplicationInfos
                 for (int i = 0; i < apps.size(); i++) {
                     LauncherActivityInfoCompat app = apps.get(i);
                     // This builds the icon bitmaps.
-                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));
+                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));
                 }
 
-                if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {
-                    // Add shortcuts for packages which were installed while launcher was dead.
-                    String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
-                            + mUserManager.getSerialNumberForUser(user);
-                    Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);
-                    HashSet<String> newPackageSet = new HashSet<String>();
+                final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
+                if (heuristic != null) {
+                    runAfterBindCompletes(new Runnable() {
 
-                    for (LauncherActivityInfoCompat info : apps) {
-                        String packageName = info.getComponentName().getPackageName();
-                        if (!packagesAdded.contains(packageName)
-                                && !newPackageSet.contains(packageName)) {
-                            InstallShortcutReceiver.queueInstallShortcut(info, mContext);
+                        @Override
+                        public void run() {
+                            heuristic.processUserApps(apps);
                         }
-                        newPackageSet.add(packageName);
-                    }
-
-                    prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();
+                    });
                 }
             }
             // Huh? Shouldn't this be inside the Runnable below?
@@ -2874,6 +2808,7 @@
             // Post callback on main thread
             mHandler.post(new Runnable() {
                 public void run() {
+
                     final long bindTime = SystemClock.uptimeMillis();
                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
@@ -2887,7 +2822,11 @@
                     }
                 }
             });
+            // Cleanup any data stored for a deleted user.
+            ManagedProfileHeuristic.processAllUsers(profiles, mContext);
 
+            loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks),
+                    true /* refresh */);
             if (DEBUG_LOADERS) {
                 Log.d(TAG, "Icons processed in "
                         + (SystemClock.uptimeMillis() - loadTime) + "ms");
@@ -2897,7 +2836,6 @@
         public void dumpState() {
             synchronized (sBgLock) {
                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);
-                Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());
@@ -2905,11 +2843,66 @@
         }
     }
 
+    /**
+     * Called when the icons for packages have been updated in the icon cache.
+     */
+    public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {
+        final Callbacks callbacks = getCallback();
+        final ArrayList<AppInfo> updatedApps = new ArrayList<>();
+        final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
+
+        // If any package icon has changed (app was updated while launcher was dead),
+        // update the corresponding shortcuts.
+        synchronized (sBgLock) {
+            for (ItemInfo info : sBgItemsIdMap) {
+                if (info instanceof ShortcutInfo && user.equals(info.user)
+                        && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+                    ShortcutInfo si = (ShortcutInfo) info;
+                    ComponentName cn = si.getTargetComponent();
+                    if (cn != null && updatedPackages.contains(cn.getPackageName())) {
+                        si.updateIcon(mIconCache);
+                        updatedShortcuts.add(si);
+                    }
+                }
+            }
+            mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);
+        }
+
+        if (!updatedShortcuts.isEmpty()) {
+            final UserHandleCompat userFinal = user;
+            mHandler.post(new Runnable() {
+
+                public void run() {
+                    Callbacks cb = getCallback();
+                    if (cb != null && callbacks == cb) {
+                        cb.bindShortcutsChanged(updatedShortcuts,
+                                new ArrayList<ShortcutInfo>(), userFinal);
+                    }
+                }
+            });
+        }
+
+        if (!updatedApps.isEmpty()) {
+            mHandler.post(new Runnable() {
+
+                public void run() {
+                    Callbacks cb = getCallback();
+                    if (cb != null && callbacks == cb) {
+                        cb.bindAppsUpdated(updatedApps);
+                    }
+                }
+            });
+        }
+
+        // Reload widget list. No need to refresh, as we only want to update the icons and labels.
+        loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);
+    }
+
     void enqueuePackageUpdated(PackageUpdatedTask task) {
         sWorker.post(task);
     }
 
-    private class AppsAvailabilityCheck extends BroadcastReceiver {
+    @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -2969,73 +2962,52 @@
         }
 
         public void run() {
+            if (!mHasLoaderCompletedOnce) {
+                // Loader has not yet run.
+                return;
+            }
             final Context context = mApp.getContext();
 
             final String[] packages = mPackages;
             final int N = packages.length;
             switch (mOp) {
-                case OP_ADD:
+                case OP_ADD: {
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
-                        mIconCache.remove(packages[i], mUser);
+                        mIconCache.updateIconsForPkg(packages[i], mUser);
                         mBgAllAppsList.addPackage(context, packages[i], mUser);
                     }
 
-                    // Auto add shortcuts for added packages.
-                    if (ADD_MANAGED_PROFILE_SHORTCUTS
-                            && !UserHandleCompat.myUserHandle().equals(mUser)) {
-                        SharedPreferences prefs = context.getSharedPreferences(
-                                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
-                        String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
-                                + mUserManager.getSerialNumberForUser(mUser);
-                        Set<String> shortcutSet = new HashSet<String>(
-                                prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));
-
-                        for (int i=0; i<N; i++) {
-                            if (!shortcutSet.contains(packages[i])) {
-                                shortcutSet.add(packages[i]);
-                                List<LauncherActivityInfoCompat> activities =
-                                        mLauncherApps.getActivityList(packages[i], mUser);
-                                if (activities != null && !activities.isEmpty()) {
-                                    InstallShortcutReceiver.queueInstallShortcut(
-                                            activities.get(0), context);
-                                }
-                            }
-                        }
-
-                        prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();
+                    ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
+                    if (heuristic != null) {
+                        heuristic.processPackageAdd(mPackages);
                     }
                     break;
+                }
                 case OP_UPDATE:
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
+                        mIconCache.updateIconsForPkg(packages[i], mUser);
                         mBgAllAppsList.updatePackage(context, packages[i], mUser);
-                        WidgetPreviewLoader.removePackageFromDb(
-                                mApp.getWidgetPreviewCacheDb(), packages[i]);
+                        mApp.getWidgetCache().removePackage(packages[i], mUser);
                     }
                     break;
-                case OP_REMOVE:
-                    // Remove the packageName for the set of auto-installed shortcuts. This
-                    // will ensure that the shortcut when the app is installed again.
-                    if (ADD_MANAGED_PROFILE_SHORTCUTS
-                            && !UserHandleCompat.myUserHandle().equals(mUser)) {
-                        SharedPreferences prefs = context.getSharedPreferences(
-                                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
-                        String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX
-                                + mUserManager.getSerialNumberForUser(mUser);
-                        HashSet<String> shortcutSet = new HashSet<String>(
-                                prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));
-                        shortcutSet.removeAll(Arrays.asList(mPackages));
-                        prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();
+                case OP_REMOVE: {
+                    ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
+                    if (heuristic != null) {
+                        heuristic.processPackageRemoved(mPackages);
                     }
-                    // Fall through
-                case OP_UNAVAILABLE:
-                    boolean clearCache = mOp == OP_REMOVE;
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
-                        mBgAllAppsList.removePackage(packages[i], mUser, clearCache);
-                        WidgetPreviewLoader.removePackageFromDb(
-                                mApp.getWidgetPreviewCacheDb(), packages[i]);
+                        mIconCache.removeIconsForPkg(packages[i], mUser);
+                    }
+                    // Fall through
+                }
+                case OP_UNAVAILABLE:
+                    for (int i=0; i<N; i++) {
+                        if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
+                        mBgAllAppsList.removePackage(packages[i], mUser);
+                        mApp.getWidgetCache().removePackage(packages[i], mUser);
                     }
                     break;
             }
@@ -3067,13 +3039,7 @@
                     new HashMap<ComponentName, AppInfo>();
 
             if (added != null) {
-                // Ensure that we add all the workspace applications to the db
-                if (LauncherAppState.isDisableAllApps()) {
-                    final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);
-                    addAndBindAddedWorkspaceApps(context, addedInfos);
-                } else {
-                    addAppsToAllApps(context, added);
-                }
+                addAppsToAllApps(context, added);
                 for (AppInfo ai : added) {
                     addedOrUpdatedApps.put(ai.componentName, ai);
                 }
@@ -3103,7 +3069,7 @@
 
                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));
                 synchronized (sBgLock) {
-                    for (ItemInfo info : sBgItemsIdMap.values()) {
+                    for (ItemInfo info : sBgItemsIdMap) {
                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
                             ShortcutInfo si = (ShortcutInfo) info;
                             boolean infoUpdated = false;
@@ -3112,8 +3078,9 @@
                             // Update shortcuts which use iconResource.
                             if ((si.iconResource != null)
                                     && packageSet.contains(si.iconResource.packageName)) {
-                                Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,
-                                        si.iconResource.resourceName, mIconCache, context);
+                                Bitmap icon = Utilities.createIconBitmap(
+                                        si.iconResource.packageName,
+                                        si.iconResource.resourceName, context);
                                 if (icon != null) {
                                     si.setIcon(icon);
                                     si.usingFallbackIcon = false;
@@ -3126,7 +3093,6 @@
                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);
 
                                 if (si.isPromise()) {
-                                    mIconCache.deletePreloadedIcon(cn, mUser);
                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
                                         // Auto install icon
                                         PackageManager pm = context.getPackageManager();
@@ -3152,12 +3118,13 @@
                                     }
 
                                     // Restore the shortcut.
+                                    if (appInfo != null) {
+                                        si.flags = appInfo.flags;
+                                    }
+
                                     si.intent = si.promisedIntent;
                                     si.promisedIntent = null;
-                                    si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON
-                                            & ~ShortcutInfo.FLAG_AUTOINTALL_ICON
-                                            & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
-
+                                    si.status = ShortcutInfo.DEFAULT;
                                     infoUpdated = true;
                                     si.updateIcon(mIconCache);
                                 }
@@ -3165,7 +3132,7 @@
                                 if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())
                                         && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                                     si.updateIcon(mIconCache);
-                                    si.title = appInfo.title.toString();
+                                    si.title = Utilities.trim(appInfo.title);
                                     si.contentDescription = appInfo.contentDescription;
                                     infoUpdated = true;
                                 }
@@ -3268,17 +3235,8 @@
                 });
             }
 
-            final ArrayList<Object> widgetsAndShortcuts =
-                    getSortedWidgetsAndShortcuts(context);
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    Callbacks cb = getCallback();
-                    if (callbacks == cb && cb != null) {
-                        callbacks.bindPackagesUpdated(widgetsAndShortcuts);
-                    }
-                }
-            });
+            // onProvidersChanged method (API >= 17) already refreshed the widget list
+            loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17);
 
             // Write all the logs to disk
             mHandler.post(new Runnable() {
@@ -3292,19 +3250,106 @@
         }
     }
 
-    // Returns a list of ResolveInfos/AppWindowInfos in sorted order
-    public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {
-        PackageManager packageManager = context.getPackageManager();
-        final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
-        widgetsAndShortcuts.addAll(AppWidgetManagerCompat.getInstance(context).getAllProviders());
+    public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,
+            boolean refresh) {
+        ArrayList<LauncherAppWidgetProviderInfo> results =
+                new ArrayList<LauncherAppWidgetProviderInfo>();
+        try {
+            synchronized (sBgLock) {
+                if (sBgWidgetProviders == null || refresh) {
+                    HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders
+                            = new HashMap<>();
+                    AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);
+                    LauncherAppWidgetProviderInfo info;
 
-        Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
-        widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
-        Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));
-        return widgetsAndShortcuts;
+                    List<AppWidgetProviderInfo> widgets = wm.getAllProviders();
+                    for (AppWidgetProviderInfo pInfo : widgets) {
+                        info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);
+                        UserHandleCompat user = wm.getUser(info);
+                        tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                    }
+
+                    Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();
+                    for (CustomAppWidget widget : customWidgets) {
+                        info = new LauncherAppWidgetProviderInfo(context, widget);
+                        UserHandleCompat user = wm.getUser(info);
+                        tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);
+                    }
+                    // Replace the global list at the very end, so that if there is an exception,
+                    // previously loaded provider list is used.
+                    sBgWidgetProviders = tmpWidgetProviders;
+                }
+                results.addAll(sBgWidgetProviders.values());
+                return results;
+            }
+        } catch (Exception e) {
+            if (e.getCause() instanceof TransactionTooLargeException) {
+                // the returned value may be incomplete and will not be refreshed until the next
+                // time Launcher starts.
+                // TODO: after figuring out a repro step, introduce a dirty bit to check when
+                // onResume is called to refresh the widget provider list.
+                synchronized (sBgLock) {
+                    if (sBgWidgetProviders != null) {
+                        results.addAll(sBgWidgetProviders.values());
+                    }
+                    return results;
+                }
+            } else {
+                throw e;
+            }
+        }
     }
 
-    private static boolean isPackageDisabled(Context context, String packageName,
+    public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,
+            UserHandleCompat user) {
+        synchronized (sBgLock) {
+            if (sBgWidgetProviders == null) {
+                getWidgetProviders(ctx, false /* refresh */);
+            }
+            return sBgWidgetProviders.get(new ComponentKey(name, user));
+        }
+    }
+
+    public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks,
+            final boolean refresh) {
+
+        runOnWorkerThread(new Runnable() {
+            @Override
+            public void run() {
+                updateWidgetsModel(context, refresh);
+                final WidgetsModel model = mBgWidgetsModel.clone();
+
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        Callbacks cb = getCallback();
+                        if (callbacks == cb && cb != null) {
+                            callbacks.bindAllPackages(model);
+                        }
+                    }
+                });
+                // update the Widget entries inside DB on the worker thread.
+                LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(
+                        model.getRawList());
+            }
+        });
+    }
+
+    /**
+     * Returns a list of ResolveInfos/AppWidgetInfos.
+     *
+     * @see #loadAndBindWidgetsAndShortcuts
+     */
+    @Thunk void updateWidgetsModel(Context context, boolean refresh) {
+        PackageManager packageManager = context.getPackageManager();
+        final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();
+        widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));
+        Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+        widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));
+        mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);
+    }
+
+    @Thunk static boolean isPackageDisabled(Context context, String packageName,
             UserHandleCompat user) {
         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
         return !launcherApps.isPackageEnabledForProfile(packageName, user);
@@ -3335,31 +3380,36 @@
      * Make an ShortcutInfo object for a restored application or shortcut item that points
      * to a package that is not yet installed on the system.
      */
-    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,
-            int promiseType) {
+    public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent,
+            int promiseType, int itemType, CursorIconInfo iconInfo, Context context) {
         final ShortcutInfo info = new ShortcutInfo();
         info.user = UserHandleCompat.myUserHandle();
-        mIconCache.getTitleAndIcon(info, intent, info.user, true);
+
+        Bitmap icon = iconInfo.loadIcon(c, info, context);
+        // the fallback icon
+        if (icon == null) {
+            mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);
+        } else {
+            info.setIcon(icon);
+        }
 
         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
-            String title = (cursor != null) ? cursor.getString(titleIndex) : null;
+            String title = (c != null) ? c.getString(titleIndex) : null;
             if (!TextUtils.isEmpty(title)) {
-                info.title = title;
+                info.title = Utilities.trim(title);
             }
-            info.status = ShortcutInfo.FLAG_RESTORED_ICON;
         } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
             if (TextUtils.isEmpty(info.title)) {
-                info.title = (cursor != null) ? cursor.getString(titleIndex) : "";
+                info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";
             }
-            info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;
         } else {
             throw new InvalidParameterException("Invalid restoreType " + promiseType);
         }
 
-        info.contentDescription = mUserManager.getBadgedLabelForUser(
-                info.title.toString(), info.user);
-        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+        info.itemType = itemType;
         info.promisedIntent = intent;
+        info.status = promiseType;
         return info;
     }
 
@@ -3367,7 +3417,7 @@
      * Make an Intent object for a restored application or shortcut item that points
      * to the market page for the item.
      */
-    private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
+    @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
         ComponentName componentName = intent.getComponent();
         return getMarketIntent(componentName.getPackageName());
     }
@@ -3382,22 +3432,13 @@
     }
 
     /**
-     * This is called from the code that adds shortcuts from the intent receiver.  This
-     * doesn't have a Cursor, but
-     */
-    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
-            UserHandleCompat user, Context context) {
-        return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);
-    }
-
-    /**
      * Make an ShortcutInfo object for a shortcut that is an application.
      *
      * If c is not null, then it will be used to fill in missing data like the title and icon.
      */
-    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,
+    public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,
             UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,
-            HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {
+            boolean allowMissingTarget, boolean useLowResIcon) {
         if (user == null) {
             Log.d(TAG, "Null user found in getShortcutInfo");
             return null;
@@ -3419,56 +3460,32 @@
         }
 
         final ShortcutInfo info = new ShortcutInfo();
-
-        // the resource -- This may implicitly give us back the fallback icon,
-        // but don't worry about that.  All we're doing with usingFallbackIcon is
-        // to avoid saving lots of copies of that in the database, and most apps
-        // have icons anyway.
-        Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);
-
-        // the db
-        if (icon == null) {
-            if (c != null) {
-                icon = getIconFromCursor(c, iconIndex, context);
-            }
-        }
-        // the fallback icon
-        if (icon == null) {
-            icon = mIconCache.getDefaultIcon(user);
-            info.usingFallbackIcon = true;
-        }
-        info.setIcon(icon);
-
-        // From the cache.
-        if (labelCache != null) {
-            info.title = labelCache.get(componentName);
+        mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);
+        if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {
+            Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);
+            info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);
         }
 
-        // from the resource
-        if (info.title == null && lai != null) {
-            info.title = lai.getLabel();
-            if (labelCache != null) {
-                labelCache.put(componentName, info.title);
-            }
-        }
         // from the db
-        if (info.title == null) {
-            if (c != null) {
-                info.title =  c.getString(titleIndex);
-            }
+        if (TextUtils.isEmpty(info.title) && c != null) {
+            info.title =  Utilities.trim(c.getString(titleIndex));
         }
+
         // fall back to the class name of the activity
         if (info.title == null) {
             info.title = componentName.getClassName();
         }
+
         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
         info.user = user;
-        info.contentDescription = mUserManager.getBadgedLabelForUser(
-                info.title.toString(), info.user);
+        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+        if (lai != null) {
+            info.flags = AppInfo.initFlags(lai);
+        }
         return info;
     }
 
-    static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,
+    static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,
             ItemInfoFilter f) {
         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
         for (ItemInfo i : infos) {
@@ -3497,7 +3514,7 @@
         return new ArrayList<ItemInfo>(filtered);
     }
 
-    private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
+    @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,
             final UserHandleCompat user) {
         ItemInfoFilter filter  = new ItemInfoFilter() {
             @Override
@@ -3509,17 +3526,14 @@
                 }
             }
         };
-        return filterItemInfos(sBgItemsIdMap.values(), filter);
+        return filterItemInfos(sBgItemsIdMap, filter);
     }
 
     /**
      * Make an ShortcutInfo object for a shortcut that isn't an application.
      */
-    private ShortcutInfo getShortcutInfo(Cursor c, Context context,
-            int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,
-            int titleIndex) {
-
-        Bitmap icon = null;
+    @Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,
+            int titleIndex, CursorIconInfo iconInfo) {
         final ShortcutInfo info = new ShortcutInfo();
         // Non-app shortcuts are only supported for current user.
         info.user = UserHandleCompat.myUserHandle();
@@ -3527,77 +3541,18 @@
 
         // TODO: If there's an explicit component and we can't install that, delete it.
 
-        info.title = c.getString(titleIndex);
+        info.title = Utilities.trim(c.getString(titleIndex));
 
-        int iconType = c.getInt(iconTypeIndex);
-        switch (iconType) {
-        case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
-            String packageName = c.getString(iconPackageIndex);
-            String resourceName = c.getString(iconResourceIndex);
-            info.customIcon = false;
-            // the resource
-            icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);
-            // the db
-            if (icon == null) {
-                icon = getIconFromCursor(c, iconIndex, context);
-            }
-            // the fallback icon
-            if (icon == null) {
-                icon = mIconCache.getDefaultIcon(info.user);
-                info.usingFallbackIcon = true;
-            }
-            break;
-        case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
-            icon = getIconFromCursor(c, iconIndex, context);
-            if (icon == null) {
-                icon = mIconCache.getDefaultIcon(info.user);
-                info.customIcon = false;
-                info.usingFallbackIcon = true;
-            } else {
-                info.customIcon = true;
-            }
-            break;
-        default:
+        Bitmap icon = iconInfo.loadIcon(c, info, context);
+        // the fallback icon
+        if (icon == null) {
             icon = mIconCache.getDefaultIcon(info.user);
             info.usingFallbackIcon = true;
-            info.customIcon = false;
-            break;
         }
         info.setIcon(icon);
         return info;
     }
 
-    Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {
-        @SuppressWarnings("all") // suppress dead code warning
-        final boolean debug = false;
-        if (debug) {
-            Log.d(TAG, "getIconFromCursor app="
-                    + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));
-        }
-        byte[] data = c.getBlob(iconIndex);
-        try {
-            return Utilities.createIconBitmap(
-                    BitmapFactory.decodeByteArray(data, 0, data.length), context);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    /**
-     * Attempts to find an AppWidgetProviderInfo that matches the given component.
-     */
-    static AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,
-            ComponentName component) {
-        List<AppWidgetProviderInfo> widgets =
-            AppWidgetManager.getInstance(context).getInstalledProviders();
-        for (AppWidgetProviderInfo info : widgets) {
-            if (info.provider.equals(component)) {
-                return info;
-            }
-        }
-        return null;
-    }
-
     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
@@ -3621,7 +3576,7 @@
             if (extra instanceof ShortcutIconResource) {
                 iconResource = (ShortcutIconResource) extra;
                 icon = Utilities.createIconBitmap(iconResource.packageName,
-                        iconResource.resourceName, mIconCache, context);
+                        iconResource.resourceName, context);
             }
         }
 
@@ -3636,9 +3591,8 @@
         }
         info.setIcon(icon);
 
-        info.title = name;
-        info.contentDescription = mUserManager.getBadgedLabelForUser(
-                info.title.toString(), info.user);
+        info.title = Utilities.trim(name);
+        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
         info.intent = intent;
         info.customIcon = customIcon;
         info.iconResource = iconResource;
@@ -3646,50 +3600,11 @@
         return info;
     }
 
-    boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,
-            int iconIndex) {
-        // If apps can't be on SD, don't even bother.
-        if (!mAppsCanBeOnRemoveableStorage) {
-            return false;
-        }
-        // If this icon doesn't have a custom icon, check to see
-        // what's stored in the DB, and if it doesn't match what
-        // we're going to show, store what we are going to show back
-        // into the DB.  We do this so when we're loading, if the
-        // package manager can't find an icon (for example because
-        // the app is on SD) then we can use that instead.
-        if (!info.customIcon && !info.usingFallbackIcon) {
-            cache.put(info, c.getBlob(iconIndex));
-            return true;
-        }
-        return false;
-    }
-    void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {
-        boolean needSave = false;
-        try {
-            if (data != null) {
-                Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);
-                Bitmap loaded = info.getIcon(mIconCache);
-                needSave = !saved.sameAs(loaded);
-            } else {
-                needSave = true;
-            }
-        } catch (Exception e) {
-            needSave = true;
-        }
-        if (needSave) {
-            Log.d(TAG, "going to save icon bitmap for info=" + info);
-            // This is slower than is ideal, but this only happens once
-            // or when the app is updated with a new icon.
-            updateItemInDatabase(context, info);
-        }
-    }
-
     /**
      * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
+    @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {
         // See if a placeholder was created for us already
         FolderInfo folderInfo = folders.get(id);
         if (folderInfo == null) {
@@ -3700,105 +3615,6 @@
         return folderInfo;
     }
 
-    public static final Comparator<AppInfo> getAppNameComparator() {
-        final Collator collator = Collator.getInstance();
-        return new Comparator<AppInfo>() {
-            public final int compare(AppInfo a, AppInfo b) {
-                if (a.user.equals(b.user)) {
-                    int result = collator.compare(a.title.toString().trim(),
-                            b.title.toString().trim());
-                    if (result == 0) {
-                        result = a.componentName.compareTo(b.componentName);
-                    }
-                    return result;
-                } else {
-                    // TODO Need to figure out rules for sorting
-                    // profiles, this puts work second.
-                    return a.user.toString().compareTo(b.user.toString());
-                }
-            }
-        };
-    }
-    public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR
-            = new Comparator<AppInfo>() {
-        public final int compare(AppInfo a, AppInfo b) {
-            if (a.firstInstallTime < b.firstInstallTime) return 1;
-            if (a.firstInstallTime > b.firstInstallTime) return -1;
-            return 0;
-        }
-    };
-    static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {
-        if (info.activityInfo != null) {
-            return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
-        } else {
-            return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);
-        }
-    }
-    public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {
-        private Collator mCollator;
-        private HashMap<Object, CharSequence> mLabelCache;
-        ShortcutNameComparator(PackageManager pm) {
-            mLabelCache = new HashMap<Object, CharSequence>();
-            mCollator = Collator.getInstance();
-        }
-        ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {
-            mLabelCache = labelCache;
-            mCollator = Collator.getInstance();
-        }
-        public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {
-            String labelA, labelB;
-            ComponentName keyA = a.getComponentName();
-            ComponentName keyB = b.getComponentName();
-            if (mLabelCache.containsKey(keyA)) {
-                labelA = mLabelCache.get(keyA).toString();
-            } else {
-                labelA = a.getLabel().toString().trim();
-
-                mLabelCache.put(keyA, labelA);
-            }
-            if (mLabelCache.containsKey(keyB)) {
-                labelB = mLabelCache.get(keyB).toString();
-            } else {
-                labelB = b.getLabel().toString().trim();
-
-                mLabelCache.put(keyB, labelB);
-            }
-            return mCollator.compare(labelA, labelB);
-        }
-    };
-    public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
-        private final AppWidgetManagerCompat mManager;
-        private final PackageManager mPackageManager;
-        private final HashMap<Object, String> mLabelCache;
-        private final Collator mCollator;
-
-        WidgetAndShortcutNameComparator(Context context) {
-            mManager = AppWidgetManagerCompat.getInstance(context);
-            mPackageManager = context.getPackageManager();
-            mLabelCache = new HashMap<Object, String>();
-            mCollator = Collator.getInstance();
-        }
-        public final int compare(Object a, Object b) {
-            String labelA, labelB;
-            if (mLabelCache.containsKey(a)) {
-                labelA = mLabelCache.get(a);
-            } else {
-                labelA = (a instanceof AppWidgetProviderInfo)
-                        ? mManager.loadLabel((AppWidgetProviderInfo) a)
-                        : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
-                mLabelCache.put(a, labelA);
-            }
-            if (mLabelCache.containsKey(b)) {
-                labelB = mLabelCache.get(b);
-            } else {
-                labelB = (b instanceof AppWidgetProviderInfo)
-                        ? mManager.loadLabel((AppWidgetProviderInfo) b)
-                        : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
-                mLabelCache.put(b, labelB);
-            }
-            return mCollator.compare(labelA, labelB);
-        }
-    };
 
     static boolean isValidProvider(AppWidgetProviderInfo provider) {
         return (provider != null) && (provider.provider != null)
@@ -3821,4 +3637,20 @@
     public Callbacks getCallback() {
         return mCallbacks != null ? mCallbacks.get() : null;
     }
+
+    /**
+     * @return {@link FolderInfo} if its already loaded.
+     */
+    public FolderInfo findFolderById(Long folderId) {
+        synchronized (sBgLock) {
+            return sBgFolders.get(folderId);
+        }
+    }
+
+    /**
+     * @return the looper for the worker thread which can be used to start background tasks.
+     */
+    public static Looper getWorkerLooper() {
+        return sWorkerThread.getLooper();
+    }
 }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 1715b02..cc5e18b 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -16,9 +16,9 @@
 
 package com.android.launcher3;
 
+import android.annotation.TargetApi;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentProviderOperation;
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.OperationApplicationException;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -37,10 +38,13 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.database.sqlite.SQLiteStatement;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
-import android.provider.Settings;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.StrictMode;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -50,52 +54,42 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.config.ProviderConfig;
+import com.android.launcher3.util.ManagedProfileHeuristic;
+import com.android.launcher3.util.Thunk;
 
 import java.io.File;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 
 public class LauncherProvider extends ContentProvider {
     private static final String TAG = "Launcher.LauncherProvider";
     private static final boolean LOGD = false;
 
-    private static final int DATABASE_VERSION = 20;
+    private static final int DATABASE_VERSION = 26;
 
     static final String OLD_AUTHORITY = "com.android.launcher2.settings";
     static final String AUTHORITY = ProviderConfig.AUTHORITY;
 
-    // Should we attempt to load anything from the com.android.launcher2 provider?
-    static final boolean IMPORT_LAUNCHER2_DATABASE = false;
-
-    static final String TABLE_FAVORITES = "favorites";
-    static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens";
-    static final String PARAMETER_NOTIFY = "notify";
-    static final String UPGRADED_FROM_OLD_DATABASE =
-            "UPGRADED_FROM_OLD_DATABASE";
-    static final String EMPTY_DATABASE_CREATED =
-            "EMPTY_DATABASE_CREATED";
+    static final String TABLE_FAVORITES = LauncherSettings.Favorites.TABLE_NAME;
+    static final String TABLE_WORKSPACE_SCREENS = LauncherSettings.WorkspaceScreens.TABLE_NAME;
+    static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
 
     private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd";
 
-    private LauncherProviderChangeListener mListener;
+    private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name";
 
-    /**
-     * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
-     * {@link AppWidgetHost#deleteHost()} is called during database creation.
-     * Use this to recall {@link AppWidgetHost#startListening()} if needed.
-     */
-    static final Uri CONTENT_APPWIDGET_RESET_URI =
-            Uri.parse("content://" + AUTHORITY + "/appWidgetReset");
-
-    private DatabaseHelper mOpenHelper;
-    private static boolean sJustLoadedFromOldDb;
+    @Thunk LauncherProviderChangeListener mListener;
+    @Thunk DatabaseHelper mOpenHelper;
 
     @Override
     public boolean onCreate() {
         final Context context = getContext();
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         mOpenHelper = new DatabaseHelper(context);
+        StrictMode.setThreadPolicy(oldPolicy);
         LauncherAppState.setLauncherProvider(this);
         return true;
     }
@@ -106,6 +100,7 @@
 
     public void setLauncherProviderChangeListener(LauncherProviderChangeListener listener) {
         mListener = listener;
+        mOpenHelper.mListener = mListener;
     }
 
     @Override
@@ -133,7 +128,7 @@
         return result;
     }
 
-    private static long dbInsertAndCheck(DatabaseHelper helper,
+    @Thunk static long dbInsertAndCheck(DatabaseHelper helper,
             SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
         if (values == null) {
             throw new RuntimeException("Error: attempting to insert null values");
@@ -151,7 +146,8 @@
 
         // In very limited cases, we support system|signature permission apps to add to the db
         String externalAdd = uri.getQueryParameter(URI_PARAM_IS_EXTERNAL_ADD);
-        if (externalAdd != null && "true".equals(externalAdd)) {
+        final boolean isExternalAll = externalAdd != null && "true".equals(externalAdd);
+        if (isExternalAll) {
             if (!mOpenHelper.initializeExternalAdd(initialValues)) {
                 return null;
             }
@@ -160,10 +156,17 @@
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         addModifiedTime(initialValues);
         final long rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues);
-        if (rowId <= 0) return null;
+        if (rowId < 0) return null;
 
         uri = ContentUris.withAppendedId(uri, rowId);
-        sendNotify(uri);
+        notifyListeners();
+
+        if (isExternalAll) {
+            LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+            if (app != null) {
+                app.reloadWorkspace();
+            }
+        }
 
         return uri;
     }
@@ -188,7 +191,7 @@
             db.endTransaction();
         }
 
-        sendNotify(uri);
+        notifyListeners();
         return values.length;
     }
 
@@ -212,7 +215,7 @@
 
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         int count = db.delete(args.table, args.where, args.args);
-        if (count > 0) sendNotify(uri);
+        if (count > 0) notifyListeners();
 
         return count;
     }
@@ -224,17 +227,80 @@
         addModifiedTime(values);
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         int count = db.update(args.table, values, args.where, args.args);
-        if (count > 0) sendNotify(uri);
+        if (count > 0) notifyListeners();
 
         return count;
     }
 
-    private void sendNotify(Uri uri) {
-        String notify = uri.getQueryParameter(PARAMETER_NOTIFY);
-        if (notify == null || "true".equals(notify)) {
-            getContext().getContentResolver().notifyChange(uri, null);
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        if (Binder.getCallingUid() != Process.myUid()) {
+            return null;
         }
 
+        switch (method) {
+            case LauncherSettings.Settings.METHOD_GET_BOOLEAN: {
+                Bundle result = new Bundle();
+                result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
+                        getContext().getSharedPreferences(
+                                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE)
+                                .getBoolean(arg, extras.getBoolean(
+                                        LauncherSettings.Settings.EXTRA_DEFAULT_VALUE)));
+                return result;
+            }
+            case LauncherSettings.Settings.METHOD_SET_BOOLEAN: {
+                boolean value = extras.getBoolean(LauncherSettings.Settings.EXTRA_VALUE);
+                getContext().getSharedPreferences(
+                        LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE)
+                        .edit().putBoolean(arg, value).apply();
+                if (mListener != null) {
+                    mListener.onSettingsChanged(arg, value);
+                }
+                Bundle result = new Bundle();
+                result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, value);
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Deletes any empty folder from the DB.
+     * @return Ids of deleted folders.
+     */
+    public List<Long> deleteEmptyFolders() {
+        ArrayList<Long> folderIds = new ArrayList<Long>();
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        db.beginTransaction();
+        try {
+            // Select folders whose id do not match any container value.
+            String selection = LauncherSettings.Favorites.ITEM_TYPE + " = "
+                    + LauncherSettings.Favorites.ITEM_TYPE_FOLDER + " AND "
+                    + LauncherSettings.Favorites._ID +  " NOT IN (SELECT " +
+                            LauncherSettings.Favorites.CONTAINER + " FROM "
+                                + TABLE_FAVORITES + ")";
+            Cursor c = db.query(TABLE_FAVORITES,
+                    new String[] {LauncherSettings.Favorites._ID},
+                    selection, null, null, null, null);
+            while (c.moveToNext()) {
+                folderIds.add(c.getLong(0));
+            }
+            c.close();
+            if (folderIds.size() > 0) {
+                db.delete(TABLE_FAVORITES, Utilities.createDbSelectionQuery(
+                        LauncherSettings.Favorites._ID, folderIds), null);
+            }
+            db.setTransactionSuccessful();
+        } catch (SQLException ex) {
+            Log.e(TAG, ex.getMessage(), ex);
+            folderIds.clear();
+        } finally {
+            db.endTransaction();
+        }
+        return folderIds;
+    }
+
+    private void notifyListeners() {
         // always notify the backup agent
         LauncherBackupAgentHelper.dataChanged(getContext());
         if (mListener != null) {
@@ -242,7 +308,7 @@
         }
     }
 
-    private void addModifiedTime(ContentValues values) {
+    @Thunk static void addModifiedTime(ContentValues values) {
         values.put(LauncherSettings.ChangeLogColumns.MODIFIED, System.currentTimeMillis());
     }
 
@@ -258,32 +324,6 @@
         return mOpenHelper.generateNewScreenId();
     }
 
-    // This is only required one time while loading the workspace during the
-    // upgrade path, and should never be called from anywhere else.
-    public void updateMaxScreenId(long maxScreenId) {
-        mOpenHelper.updateMaxScreenId(maxScreenId);
-    }
-
-    /**
-     * @param Should we load the old db for upgrade? first run only.
-     */
-    synchronized public boolean justLoadedOldDb() {
-        String spKey = LauncherAppState.getSharedPreferencesKey();
-        SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
-
-        boolean loadedOldDb = false || sJustLoadedFromOldDb;
-
-        sJustLoadedFromOldDb = false;
-        if (sp.getBoolean(UPGRADED_FROM_OLD_DATABASE, false)) {
-
-            SharedPreferences.Editor editor = sp.edit();
-            editor.remove(UPGRADED_FROM_OLD_DATABASE);
-            editor.commit();
-            loadedOldDb = true;
-        }
-        return loadedOldDb;
-    }
-
     /**
      * Clears all the data for a fresh start.
      */
@@ -301,9 +341,10 @@
 
     /**
      * Loads the default workspace based on the following priority scheme:
-     *   1) From a package provided by play store
-     *   2) From a partner configuration APK, already in the system image
-     *   3) The default configuration for the particular device
+     *   1) From the app restrictions
+     *   2) From a package provided by play store
+     *   3) From a partner configuration APK, already in the system image
+     *   4) The default configuration for the particular device
      */
     synchronized public void loadDefaultFavoritesIfNecessary() {
         String spKey = LauncherAppState.getSharedPreferencesKey();
@@ -312,9 +353,11 @@
         if (sp.getBoolean(EMPTY_DATABASE_CREATED, false)) {
             Log.d(TAG, "loading default workspace");
 
-            AutoInstallsLayout loader = AutoInstallsLayout.get(getContext(),
-                    mOpenHelper.mAppWidgetHost, mOpenHelper);
-
+            AutoInstallsLayout loader = createWorkspaceLoaderFromAppRestriction();
+            if (loader == null) {
+                loader = AutoInstallsLayout.get(getContext(),
+                        mOpenHelper.mAppWidgetHost, mOpenHelper);
+            }
             if (loader == null) {
                 final Partner partner = Partner.get(getContext().getPackageManager());
                 if (partner != null && partner.hasDefaultLayout()) {
@@ -332,6 +375,10 @@
             if (loader == null) {
                 loader = getDefaultLayoutParser();
             }
+
+            // There might be some partially restored DB items, due to buggy restore logic in
+            // previous versions of launcher.
+            createEmptyDB();
             // Populate favorites table with initial favorites
             if ((mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), loader) <= 0)
                     && usingExternallyProvidedLayout) {
@@ -344,9 +391,43 @@
         }
     }
 
+    /**
+     * Creates workspace loader from an XML resource listed in the app restrictions.
+     *
+     * @return the loader if the restrictions are set and the resource exists; null otherwise.
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+    private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction() {
+        // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18
+        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            return null;
+        }
+
+        Context ctx = getContext();
+        UserManager um = (UserManager) ctx.getSystemService(Context.USER_SERVICE);
+        Bundle bundle = um.getApplicationRestrictions(ctx.getPackageName());
+        if (bundle == null) {
+            return null;
+        }
+
+        String packageName = bundle.getString(RESTRICTION_PACKAGE_NAME);
+        if (packageName != null) {
+            try {
+                Resources targetResources = ctx.getPackageManager()
+                        .getResourcesForApplication(packageName);
+                return AutoInstallsLayout.get(ctx, packageName, targetResources,
+                        mOpenHelper.mAppWidgetHost, mOpenHelper);
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "Target package for restricted profile not found", e);
+                return null;
+            }
+        }
+        return null;
+    }
+
     private DefaultLayoutParser getDefaultLayoutParser() {
         int defaultLayout = LauncherAppState.getInstance()
-                .getDynamicGrid().getDeviceProfile().defaultLayoutId;
+                .getInvariantDeviceProfile().defaultLayoutId;
         return new DefaultLayoutParser(getContext(), mOpenHelper.mAppWidgetHost,
                 mOpenHelper, getContext().getResources(), defaultLayout);
     }
@@ -356,17 +437,15 @@
                 Uri.parse(getContext().getString(R.string.old_launcher_provider_uri)));
     }
 
-    private static interface ContentValuesCallback {
-        public void onRow(ContentValues values);
+    public void updateFolderItemsRank() {
+        mOpenHelper.updateFolderItemsRank(mOpenHelper.getWritableDatabase(), false);
     }
 
-    private static boolean shouldImportLauncher2Database(Context context) {
-        boolean isTablet = context.getResources().getBoolean(R.bool.is_tablet);
-
-        // We don't import the old databse for tablets, as the grid size has changed.
-        return !isTablet && IMPORT_LAUNCHER2_DATABASE;
+    public void convertShortcutsToLauncherActivities() {
+        mOpenHelper.convertShortcutsToLauncherActivities(mOpenHelper.getWritableDatabase());
     }
 
+
     public void deleteDatabase() {
         // Are you sure? (y/n)
         final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -376,16 +455,19 @@
             SQLiteDatabase.deleteDatabase(dbFile);
         }
         mOpenHelper = new DatabaseHelper(getContext());
+        mOpenHelper.mListener = mListener;
     }
 
     private static class DatabaseHelper extends SQLiteOpenHelper implements LayoutParserCallback {
         private final Context mContext;
-        private final AppWidgetHost mAppWidgetHost;
+        @Thunk final AppWidgetHost mAppWidgetHost;
         private long mMaxItemId = -1;
         private long mMaxScreenId = -1;
 
         private boolean mNewDbCreated = false;
 
+        @Thunk LauncherProviderChangeListener mListener;
+
         DatabaseHelper(Context context) {
             super(context, LauncherFiles.LAUNCHER_DB, null, DATABASE_VERSION);
             mContext = context;
@@ -405,17 +487,6 @@
             return mNewDbCreated;
         }
 
-        /**
-         * Send notification that we've deleted the {@link AppWidgetHost},
-         * probably as part of the initial database creation. The receiver may
-         * want to re-call {@link AppWidgetHost#startListening()} to ensure
-         * callbacks are correctly set.
-         */
-        private void sendAppWidgetResetNotify() {
-            final ContentResolver resolver = mContext.getContentResolver();
-            resolver.notifyChange(CONTENT_APPWIDGET_RESET_URI, null);
-        }
-
         @Override
         public void onCreate(SQLiteDatabase db) {
             if (LOGD) Log.d(TAG, "creating new launcher database");
@@ -450,53 +521,44 @@
                     "appWidgetProvider TEXT," +
                     "modified INTEGER NOT NULL DEFAULT 0," +
                     "restored INTEGER NOT NULL DEFAULT 0," +
-                    "profileId INTEGER DEFAULT " + userSerialNumber +
+                    "profileId INTEGER DEFAULT " + userSerialNumber + "," +
+                    "rank INTEGER NOT NULL DEFAULT 0," +
+                    "options INTEGER NOT NULL DEFAULT 0" +
                     ");");
             addWorkspacesTable(db);
 
             // Database was just created, so wipe any previous widgets
             if (mAppWidgetHost != null) {
                 mAppWidgetHost.deleteHost();
-                sendAppWidgetResetNotify();
-            }
 
-            if (shouldImportLauncher2Database(mContext)) {
-                // Try converting the old database
-                ContentValuesCallback permuteScreensCb = new ContentValuesCallback() {
-                    public void onRow(ContentValues values) {
-                        int container = values.getAsInteger(LauncherSettings.Favorites.CONTAINER);
-                        if (container == Favorites.CONTAINER_DESKTOP) {
-                            int screen = values.getAsInteger(LauncherSettings.Favorites.SCREEN);
-                            screen = (int) upgradeLauncherDb_permuteScreens(screen);
-                            values.put(LauncherSettings.Favorites.SCREEN, screen);
+                /**
+                 * Send notification that we've deleted the {@link AppWidgetHost},
+                 * probably as part of the initial database creation. The receiver may
+                 * want to re-call {@link AppWidgetHost#startListening()} to ensure
+                 * callbacks are correctly set.
+                 */
+                new MainThreadExecutor().execute(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        if (mListener != null) {
+                            mListener.onAppWidgetHostReset();
                         }
                     }
-                };
-                Uri uri = Uri.parse("content://" + Settings.AUTHORITY +
-                        "/old_favorites?notify=true");
-                if (!convertDatabase(db, uri, permuteScreensCb, true)) {
-                    // Try and upgrade from the Launcher2 db
-                    uri = Uri.parse(mContext.getString(R.string.old_launcher_provider_uri));
-                    if (!convertDatabase(db, uri, permuteScreensCb, false)) {
-                        // If we fail, then set a flag to load the default workspace
-                        setFlagEmptyDbCreated();
-                        return;
-                    }
-                }
-                // Right now, in non-default workspace cases, we want to run the final
-                // upgrade code (ie. to fix workspace screen indices -> ids, etc.), so
-                // set that flag too.
-                setFlagJustLoadedOldDb();
-            } else {
-                // Fresh and clean launcher DB.
-                mMaxItemId = initializeMaxItemId(db);
-                setFlagEmptyDbCreated();
+                });
             }
+
+            // Fresh and clean launcher DB.
+            mMaxItemId = initializeMaxItemId(db);
+            setFlagEmptyDbCreated();
+
+            // When a new DB is created, remove all previously stored managed profile information.
+            ManagedProfileHeuristic.processAllUsers(Collections.<UserHandleCompat>emptyList(), mContext);
         }
 
         private void addWorkspacesTable(SQLiteDatabase db) {
             db.execSQL("CREATE TABLE " + TABLE_WORKSPACE_SCREENS + " (" +
-                    LauncherSettings.WorkspaceScreens._ID + " INTEGER," +
+                    LauncherSettings.WorkspaceScreens._ID + " INTEGER PRIMARY KEY," +
                     LauncherSettings.WorkspaceScreens.SCREEN_RANK + " INTEGER," +
                     LauncherSettings.ChangeLogColumns.MODIFIED + " INTEGER NOT NULL DEFAULT 0" +
                     ");");
@@ -536,333 +598,120 @@
         private void setFlagJustLoadedOldDb() {
             String spKey = LauncherAppState.getSharedPreferencesKey();
             SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
-            SharedPreferences.Editor editor = sp.edit();
-            editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, true);
-            editor.putBoolean(EMPTY_DATABASE_CREATED, false);
-            editor.commit();
+            sp.edit().putBoolean(EMPTY_DATABASE_CREATED, false).commit();
         }
 
         private void setFlagEmptyDbCreated() {
             String spKey = LauncherAppState.getSharedPreferencesKey();
             SharedPreferences sp = mContext.getSharedPreferences(spKey, Context.MODE_PRIVATE);
-            SharedPreferences.Editor editor = sp.edit();
-            editor.putBoolean(EMPTY_DATABASE_CREATED, true);
-            editor.putBoolean(UPGRADED_FROM_OLD_DATABASE, false);
-            editor.commit();
-        }
-
-        // We rearrange the screens from the old launcher
-        // 12345 -> 34512
-        private long upgradeLauncherDb_permuteScreens(long screen) {
-            if (screen >= 2) {
-                return screen - 2;
-            } else {
-                return screen + 3;
-            }
-        }
-
-        private boolean convertDatabase(SQLiteDatabase db, Uri uri,
-                                        ContentValuesCallback cb, boolean deleteRows) {
-            if (LOGD) Log.d(TAG, "converting database from an older format, but not onUpgrade");
-            boolean converted = false;
-
-            final ContentResolver resolver = mContext.getContentResolver();
-            Cursor cursor = null;
-
-            try {
-                cursor = resolver.query(uri, null, null, null, null);
-            } catch (Exception e) {
-                // Ignore
-            }
-
-            // We already have a favorites database in the old provider
-            if (cursor != null) {
-                try {
-                     if (cursor.getCount() > 0) {
-                        converted = copyFromCursor(db, cursor, cb) > 0;
-                        if (converted && deleteRows) {
-                            resolver.delete(uri, null, null);
-                        }
-                    }
-                } finally {
-                    cursor.close();
-                }
-            }
-
-            if (converted) {
-                // Convert widgets from this import into widgets
-                if (LOGD) Log.d(TAG, "converted and now triggering widget upgrade");
-                convertWidgets(db);
-
-                // Update max item id
-                mMaxItemId = initializeMaxItemId(db);
-                if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId);
-            }
-
-            return converted;
-        }
-
-        private int copyFromCursor(SQLiteDatabase db, Cursor c, ContentValuesCallback cb) {
-            final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
-            final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
-            final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
-            final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
-            final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
-            final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
-            final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
-            final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
-            final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
-            final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-            final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-            final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-            final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
-            final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
-
-            ContentValues[] rows = new ContentValues[c.getCount()];
-            int i = 0;
-            while (c.moveToNext()) {
-                ContentValues values = new ContentValues(c.getColumnCount());
-                values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
-                values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
-                values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
-                values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
-                values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
-                values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex));
-                values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
-                values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
-                values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
-                values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
-                values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
-                values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
-                values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
-                values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
-                values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex));
-                if (cb != null) {
-                    cb.onRow(values);
-                }
-                rows[i++] = values;
-            }
-
-            int total = 0;
-            if (i > 0) {
-                db.beginTransaction();
-                try {
-                    int numValues = rows.length;
-                    for (i = 0; i < numValues; i++) {
-                        if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i]) < 0) {
-                            return 0;
-                        } else {
-                            total++;
-                        }
-                    }
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-            return total;
+            sp.edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit();
         }
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             if (LOGD) Log.d(TAG, "onUpgrade triggered: " + oldVersion);
-
-            int version = oldVersion;
-            if (version < 3) {
-                // upgrade 1,2 -> 3 added appWidgetId column
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding appWidgetIds
-                    db.execSQL("ALTER TABLE favorites " +
-                        "ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
-                    db.setTransactionSuccessful();
-                    version = 3;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
+            switch (oldVersion) {
+                // The version cannot be lower that 12, as Launcher3 never supported a lower
+                // version of the DB.
+                case 12: {
+                    // With the new shrink-wrapped and re-orderable workspaces, it makes sense
+                    // to persist workspace screens and their relative order.
+                    mMaxScreenId = 0;
+                    addWorkspacesTable(db);
                 }
-
-                // Convert existing widgets only if table upgrade was successful
-                if (version == 3) {
-                    convertWidgets(db);
+                case 13: {
+                    db.beginTransaction();
+                    try {
+                        // Insert new column for holding widget provider name
+                        db.execSQL("ALTER TABLE favorites " +
+                                "ADD COLUMN appWidgetProvider TEXT;");
+                        db.setTransactionSuccessful();
+                    } catch (SQLException ex) {
+                        Log.e(TAG, ex.getMessage(), ex);
+                        // Old version remains, which means we wipe old data
+                        break;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                case 14: {
+                    db.beginTransaction();
+                    try {
+                        // Insert new column for holding update timestamp
+                        db.execSQL("ALTER TABLE favorites " +
+                                "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+                        db.execSQL("ALTER TABLE workspaceScreens " +
+                                "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
+                        db.setTransactionSuccessful();
+                    } catch (SQLException ex) {
+                        Log.e(TAG, ex.getMessage(), ex);
+                        // Old version remains, which means we wipe old data
+                        break;
+                    } finally {
+                        db.endTransaction();
+                    }
+                }
+                case 15: {
+                    if (!addIntegerColumn(db, Favorites.RESTORED, 0)) {
+                        // Old version remains, which means we wipe old data
+                        break;
+                    }
+                }
+                case 16: {
+                    // We use the db version upgrade here to identify users who may not have seen
+                    // clings yet (because they weren't available), but for whom the clings are now
+                    // available (tablet users). Because one of the possible cling flows (migration)
+                    // is very destructive (wipes out workspaces), we want to prevent this from showing
+                    // until clear data. We do so by marking that the clings have been shown.
+                    LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
+                }
+                case 17: {
+                    // No-op
+                }
+                case 18: {
+                    // Due to a data loss bug, some users may have items associated with screen ids
+                    // which no longer exist. Since this can cause other problems, and since the user
+                    // will never see these items anyway, we use database upgrade as an opportunity to
+                    // clean things up.
+                    removeOrphanedItems(db);
+                }
+                case 19: {
+                    // Add userId column
+                    if (!addProfileColumn(db)) {
+                        // Old version remains, which means we wipe old data
+                        break;
+                    }
+                }
+                case 20:
+                    if (!updateFolderItemsRank(db, true)) {
+                        break;
+                    }
+                case 21:
+                    // Recreate workspace table with screen id a primary key
+                    if (!recreateWorkspaceTable(db)) {
+                        break;
+                    }
+                case 22: {
+                    if (!addIntegerColumn(db, Favorites.OPTIONS, 0)) {
+                        // Old version remains, which means we wipe old data
+                        break;
+                    }
+                }
+                case 23:
+                    // No-op
+                case 24:
+                    ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext);
+                case 25:
+                    convertShortcutsToLauncherActivities(db);
+                case 26: {
+                    // DB Upgraded successfully
+                    return;
                 }
             }
 
-            if (version < 4) {
-                version = 4;
-            }
-
-            // Where's version 5?
-            // - Donut and sholes on 2.0 shipped with version 4 of launcher1.
-            // - Passion shipped on 2.1 with version 6 of launcher3
-            // - Sholes shipped on 2.1r1 (aka Mr. 3) with version 5 of launcher 1
-            //   but version 5 on there was the updateContactsShortcuts change
-            //   which was version 6 in launcher 2 (first shipped on passion 2.1r1).
-            // The updateContactsShortcuts change is idempotent, so running it twice
-            // is okay so we'll do that when upgrading the devices that shipped with it.
-            if (version < 6) {
-                // We went from 3 to 5 screens. Move everything 1 to the right
-                db.beginTransaction();
-                try {
-                    db.execSQL("UPDATE favorites SET screen=(screen + 1);");
-                    db.setTransactionSuccessful();
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-
-               // We added the fast track.
-                if (updateContactsShortcuts(db)) {
-                    version = 6;
-                }
-            }
-
-            if (version < 7) {
-                // Version 7 gets rid of the special search widget.
-                convertWidgets(db);
-                version = 7;
-            }
-
-            if (version < 8) {
-                // Version 8 (froyo) has the icons all normalized.  This should
-                // already be the case in practice, but we now rely on it and don't
-                // resample the images each time.
-                normalizeIcons(db);
-                version = 8;
-            }
-
-            if (version < 9) {
-                // The max id is not yet set at this point (onUpgrade is triggered in the ctor
-                // before it gets a change to get set, so we need to read it here when we use it)
-                if (mMaxItemId == -1) {
-                    mMaxItemId = initializeMaxItemId(db);
-                }
-
-                // Add default hotseat icons
-                loadFavorites(db, new DefaultLayoutParser(mContext, mAppWidgetHost, this,
-                        mContext.getResources(), R.xml.update_workspace));
-                version = 9;
-            }
-
-            // We bumped the version three time during JB, once to update the launch flags, once to
-            // update the override for the default launch animation and once to set the mimetype
-            // to improve startup performance
-            if (version < 12) {
-                // Contact shortcuts need a different set of flags to be launched now
-                // The updateContactsShortcuts change is idempotent, so we can keep using it like
-                // back in the Donut days
-                updateContactsShortcuts(db);
-                version = 12;
-            }
-
-            if (version < 13) {
-                // With the new shrink-wrapped and re-orderable workspaces, it makes sense
-                // to persist workspace screens and their relative order.
-                mMaxScreenId = 0;
-
-                // This will never happen in the wild, but when we switch to using workspace
-                // screen ids, redo the import from old launcher.
-                sJustLoadedFromOldDb = true;
-
-                addWorkspacesTable(db);
-                version = 13;
-            }
-
-            if (version < 14) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding widget provider name
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN appWidgetProvider TEXT;");
-                    db.setTransactionSuccessful();
-                    version = 14;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-            if (version < 15) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding update timestamp
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
-                    db.execSQL("ALTER TABLE workspaceScreens " +
-                            "ADD COLUMN modified INTEGER NOT NULL DEFAULT 0;");
-                    db.setTransactionSuccessful();
-                    version = 15;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-
-            if (version < 16) {
-                db.beginTransaction();
-                try {
-                    // Insert new column for holding restore status
-                    db.execSQL("ALTER TABLE favorites " +
-                            "ADD COLUMN restored INTEGER NOT NULL DEFAULT 0;");
-                    db.setTransactionSuccessful();
-                    version = 16;
-                } catch (SQLException ex) {
-                    // Old version remains, which means we wipe old data
-                    Log.e(TAG, ex.getMessage(), ex);
-                } finally {
-                    db.endTransaction();
-                }
-            }
-
-            if (version < 17) {
-                // We use the db version upgrade here to identify users who may not have seen
-                // clings yet (because they weren't available), but for whom the clings are now
-                // available (tablet users). Because one of the possible cling flows (migration)
-                // is very destructive (wipes out workspaces), we want to prevent this from showing
-                // until clear data. We do so by marking that the clings have been shown.
-                LauncherClings.synchonouslyMarkFirstRunClingDismissed(mContext);
-                version = 17;
-            }
-
-            if (version < 18) {
-                // No-op
-                version = 18;
-            }
-
-            if (version < 19) {
-                // Due to a data loss bug, some users may have items associated with screen ids
-                // which no longer exist. Since this can cause other problems, and since the user
-                // will never see these items anyway, we use database upgrade as an opportunity to
-                // clean things up.
-                removeOrphanedItems(db);
-                version = 19;
-            }
-
-            if (version < 20) {
-                // Add userId column
-                if (addProfileColumn(db)) {
-                    version = 20;
-                }
-                // else old version remains, which means we wipe old data
-            }
-
-            if (version != DATABASE_VERSION) {
-                Log.w(TAG, "Destroying all old data.");
-                db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
-                db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS);
-
-                onCreate(db);
-            }
+            // DB was not upgraded
+            Log.w(TAG, "Destroying all old data.");
+            createEmptyDB(db);
         }
 
         @Override
@@ -873,7 +722,6 @@
             createEmptyDB(db);
         }
 
-
         /**
          * Clears all the data for a fresh start.
          */
@@ -883,18 +731,132 @@
             onCreate(db);
         }
 
-        private boolean addProfileColumn(SQLiteDatabase db) {
+        /**
+         * Replaces all shortcuts of type {@link Favorites#ITEM_TYPE_SHORTCUT} which have a valid
+         * launcher activity target with {@link Favorites#ITEM_TYPE_APPLICATION}.
+         */
+        @Thunk void convertShortcutsToLauncherActivities(SQLiteDatabase db) {
+            db.beginTransaction();
+            Cursor c = null;
+            SQLiteStatement updateStmt = null;
+
+            try {
+                // Only consider the primary user as other users can't have a shortcut.
+                long userSerial = UserManagerCompat.getInstance(mContext)
+                        .getSerialNumberForUser(UserHandleCompat.myUserHandle());
+                c = db.query(TABLE_FAVORITES, new String[] {
+                        Favorites._ID,
+                        Favorites.INTENT,
+                    }, "itemType=" + Favorites.ITEM_TYPE_SHORTCUT + " AND profileId=" + userSerial,
+                    null, null, null, null);
+
+                updateStmt = db.compileStatement("UPDATE favorites SET itemType="
+                        + Favorites.ITEM_TYPE_APPLICATION + " WHERE _id=?");
+
+                final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
+                final int intentIndex = c.getColumnIndexOrThrow(Favorites.INTENT);
+
+                while (c.moveToNext()) {
+                    String intentDescription = c.getString(intentIndex);
+                    Intent intent;
+                    try {
+                        intent = Intent.parseUri(intentDescription, 0);
+                    } catch (URISyntaxException e) {
+                        Log.e(TAG, "Unable to parse intent", e);
+                        continue;
+                    }
+
+                    if (!Utilities.isLauncherAppTarget(intent)) {
+                        continue;
+                    }
+
+                    long id = c.getLong(idIndex);
+                    updateStmt.bindLong(1, id);
+                    updateStmt.executeUpdateDelete();
+                }
+                db.setTransactionSuccessful();
+            } catch (SQLException ex) {
+                Log.w(TAG, "Error deduping shortcuts", ex);
+            } finally {
+                db.endTransaction();
+                if (c != null) {
+                    c.close();
+                }
+                if (updateStmt != null) {
+                    updateStmt.close();
+                }
+            }
+        }
+
+        /**
+         * Recreates workspace table and migrates data to the new table.
+         */
+        public boolean recreateWorkspaceTable(SQLiteDatabase db) {
             db.beginTransaction();
             try {
-                UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
-                // Default to the serial number of this user, for older
-                // shortcuts.
-                long userSerialNumber = userManager.getSerialNumberForUser(
-                        UserHandleCompat.myUserHandle());
-                // Insert new column for holding user serial number
-                db.execSQL("ALTER TABLE favorites " +
-                        "ADD COLUMN profileId INTEGER DEFAULT "
-                                        + userSerialNumber + ";");
+                Cursor c = db.query(TABLE_WORKSPACE_SCREENS,
+                        new String[] {LauncherSettings.WorkspaceScreens._ID},
+                        null, null, null, null,
+                        LauncherSettings.WorkspaceScreens.SCREEN_RANK);
+                ArrayList<Long> sortedIDs = new ArrayList<Long>();
+                long maxId = 0;
+                try {
+                    while (c.moveToNext()) {
+                        Long id = c.getLong(0);
+                        if (!sortedIDs.contains(id)) {
+                            sortedIDs.add(id);
+                            maxId = Math.max(maxId, id);
+                        }
+                    }
+                } finally {
+                    c.close();
+                }
+
+                db.execSQL("DROP TABLE IF EXISTS " + TABLE_WORKSPACE_SCREENS);
+                addWorkspacesTable(db);
+
+                // Add all screen ids back
+                int total = sortedIDs.size();
+                for (int i = 0; i < total; i++) {
+                    ContentValues values = new ContentValues();
+                    values.put(LauncherSettings.WorkspaceScreens._ID, sortedIDs.get(i));
+                    values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
+                    addModifiedTime(values);
+                    db.insertOrThrow(TABLE_WORKSPACE_SCREENS, null, values);
+                }
+                db.setTransactionSuccessful();
+                mMaxScreenId = maxId;
+            } catch (SQLException ex) {
+                // Old version remains, which means we wipe old data
+                Log.e(TAG, ex.getMessage(), ex);
+                return false;
+            } finally {
+                db.endTransaction();
+            }
+            return true;
+        }
+
+        @Thunk boolean updateFolderItemsRank(SQLiteDatabase db, boolean addRankColumn) {
+            db.beginTransaction();
+            try {
+                if (addRankColumn) {
+                    // Insert new column for holding rank
+                    db.execSQL("ALTER TABLE favorites ADD COLUMN rank INTEGER NOT NULL DEFAULT 0;");
+                }
+
+                // Get a map for folder ID to folder width
+                Cursor c = db.rawQuery("SELECT container, MAX(cellX) FROM favorites"
+                        + " WHERE container IN (SELECT _id FROM favorites WHERE itemType = ?)"
+                        + " GROUP BY container;",
+                        new String[] {Integer.toString(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)});
+
+                while (c.moveToNext()) {
+                    db.execSQL("UPDATE favorites SET rank=cellX+(cellY*?) WHERE "
+                            + "container=? AND cellX IS NOT NULL AND cellY IS NOT NULL;",
+                            new Object[] {c.getLong(1) + 1, c.getLong(0)});
+                }
+
+                c.close();
                 db.setTransactionSuccessful();
             } catch (SQLException ex) {
                 // Old version remains, which means we wipe old data
@@ -906,142 +868,30 @@
             return true;
         }
 
-        private boolean updateContactsShortcuts(SQLiteDatabase db) {
-            final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE,
-                    new int[] { Favorites.ITEM_TYPE_SHORTCUT });
+        private boolean addProfileColumn(SQLiteDatabase db) {
+            UserManagerCompat userManager = UserManagerCompat.getInstance(mContext);
+            // Default to the serial number of this user, for older
+            // shortcuts.
+            long userSerialNumber = userManager.getSerialNumberForUser(
+                    UserHandleCompat.myUserHandle());
+            return addIntegerColumn(db, Favorites.PROFILE_ID, userSerialNumber);
+        }
 
-            Cursor c = null;
-            final String actionQuickContact = "com.android.contacts.action.QUICK_CONTACT";
+        private boolean addIntegerColumn(SQLiteDatabase db, String columnName, long defaultValue) {
             db.beginTransaction();
             try {
-                // Select and iterate through each matching widget
-                c = db.query(TABLE_FAVORITES,
-                        new String[] { Favorites._ID, Favorites.INTENT },
-                        selectWhere, null, null, null, null);
-                if (c == null) return false;
-
-                if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
-
-                final int idIndex = c.getColumnIndex(Favorites._ID);
-                final int intentIndex = c.getColumnIndex(Favorites.INTENT);
-
-                while (c.moveToNext()) {
-                    long favoriteId = c.getLong(idIndex);
-                    final String intentUri = c.getString(intentIndex);
-                    if (intentUri != null) {
-                        try {
-                            final Intent intent = Intent.parseUri(intentUri, 0);
-                            android.util.Log.d("Home", intent.toString());
-                            final Uri uri = intent.getData();
-                            if (uri != null) {
-                                final String data = uri.toString();
-                                if ((Intent.ACTION_VIEW.equals(intent.getAction()) ||
-                                        actionQuickContact.equals(intent.getAction())) &&
-                                        (data.startsWith("content://contacts/people/") ||
-                                        data.startsWith("content://com.android.contacts/" +
-                                                "contacts/lookup/"))) {
-
-                                    final Intent newIntent = new Intent(actionQuickContact);
-                                    // When starting from the launcher, start in a new, cleared task
-                                    // CLEAR_WHEN_TASK_RESET cannot reset the root of a task, so we
-                                    // clear the whole thing preemptively here since
-                                    // QuickContactActivity will finish itself when launching other
-                                    // detail activities.
-                                    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                                            Intent.FLAG_ACTIVITY_CLEAR_TASK);
-                                    newIntent.putExtra(
-                                            Launcher.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
-                                    newIntent.setData(uri);
-                                    // Determine the type and also put that in the shortcut
-                                    // (that can speed up launch a bit)
-                                    newIntent.setDataAndType(uri, newIntent.resolveType(mContext));
-
-                                    final ContentValues values = new ContentValues();
-                                    values.put(LauncherSettings.Favorites.INTENT,
-                                            newIntent.toUri(0));
-
-                                    String updateWhere = Favorites._ID + "=" + favoriteId;
-                                    db.update(TABLE_FAVORITES, values, updateWhere, null);
-                                }
-                            }
-                        } catch (RuntimeException ex) {
-                            Log.e(TAG, "Problem upgrading shortcut", ex);
-                        } catch (URISyntaxException e) {
-                            Log.e(TAG, "Problem upgrading shortcut", e);
-                        }
-                    }
-                }
-
+                db.execSQL("ALTER TABLE favorites ADD COLUMN "
+                        + columnName + " INTEGER NOT NULL DEFAULT " + defaultValue + ";");
                 db.setTransactionSuccessful();
             } catch (SQLException ex) {
-                Log.w(TAG, "Problem while upgrading contacts", ex);
+                Log.e(TAG, ex.getMessage(), ex);
                 return false;
             } finally {
                 db.endTransaction();
-                if (c != null) {
-                    c.close();
-                }
             }
-
             return true;
         }
 
-        private void normalizeIcons(SQLiteDatabase db) {
-            Log.d(TAG, "normalizing icons");
-
-            db.beginTransaction();
-            Cursor c = null;
-            SQLiteStatement update = null;
-            try {
-                boolean logged = false;
-                update = db.compileStatement("UPDATE favorites "
-                        + "SET icon=? WHERE _id=?");
-
-                c = db.rawQuery("SELECT _id, icon FROM favorites WHERE iconType=" +
-                        Favorites.ICON_TYPE_BITMAP, null);
-
-                final int idIndex = c.getColumnIndexOrThrow(Favorites._ID);
-                final int iconIndex = c.getColumnIndexOrThrow(Favorites.ICON);
-
-                while (c.moveToNext()) {
-                    long id = c.getLong(idIndex);
-                    byte[] data = c.getBlob(iconIndex);
-                    try {
-                        Bitmap bitmap = Utilities.createIconBitmap(
-                                BitmapFactory.decodeByteArray(data, 0, data.length),
-                                mContext);
-                        if (bitmap != null) {
-                            update.bindLong(1, id);
-                            data = ItemInfo.flattenBitmap(bitmap);
-                            if (data != null) {
-                                update.bindBlob(2, data);
-                                update.execute();
-                            }
-                            bitmap.recycle();
-                        }
-                    } catch (Exception e) {
-                        if (!logged) {
-                            Log.e(TAG, "Failed normalizing icon " + id, e);
-                        } else {
-                            Log.e(TAG, "Also failed normalizing icon " + id);
-                        }
-                        logged = true;
-                    }
-                }
-                db.setTransactionSuccessful();
-            } catch (SQLException ex) {
-                Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
-            } finally {
-                db.endTransaction();
-                if (update != null) {
-                    update.close();
-                }
-                if (c != null) {
-                    c.close();
-                }
-            }
-        }
-
         // Generates a new ID to use for an object in your database. This method should be only
         // called from the main UI thread. As an exception, we do call it when we call the
         // constructor from the worker thread; however, this doesn't extend until after the
@@ -1075,23 +925,7 @@
         }
 
         private long initializeMaxItemId(SQLiteDatabase db) {
-            Cursor c = db.rawQuery("SELECT MAX(_id) FROM favorites", null);
-
-            // get the result
-            final int maxIdIndex = 0;
-            long id = -1;
-            if (c != null && c.moveToNext()) {
-                id = c.getLong(maxIdIndex);
-            }
-            if (c != null) {
-                c.close();
-            }
-
-            if (id == -1) {
-                throw new RuntimeException("Error: could not query max item id");
-            }
-
-            return id;
+            return getMaxId(db, TABLE_FAVORITES);
         }
 
         // Generates a new ID to use for an workspace screen in your database. This method
@@ -1104,128 +938,14 @@
                 throw new RuntimeException("Error: max screen id was not initialized");
             }
             mMaxScreenId += 1;
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - generateNewScreenId(): " + mMaxScreenId, true);
             return mMaxScreenId;
         }
 
-        public void updateMaxScreenId(long maxScreenId) {
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - updateMaxScreenId(): " + maxScreenId, true);
-            mMaxScreenId = maxScreenId;
-        }
-
         private long initializeMaxScreenId(SQLiteDatabase db) {
-            Cursor c = db.rawQuery("SELECT MAX(" + LauncherSettings.WorkspaceScreens._ID + ") FROM " + TABLE_WORKSPACE_SCREENS, null);
-
-            // get the result
-            final int maxIdIndex = 0;
-            long id = -1;
-            if (c != null && c.moveToNext()) {
-                id = c.getLong(maxIdIndex);
-            }
-            if (c != null) {
-                c.close();
-            }
-
-            if (id == -1) {
-                throw new RuntimeException("Error: could not query max screen id");
-            }
-
-            // Log to disk
-            Launcher.addDumpLog(TAG, "11683562 - initializeMaxScreenId(): " + id, true);
-            return id;
+            return getMaxId(db, TABLE_WORKSPACE_SCREENS);
         }
 
-        /**
-         * Upgrade existing clock and photo frame widgets into their new widget
-         * equivalents.
-         */
-        private void convertWidgets(SQLiteDatabase db) {
-            final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
-            final int[] bindSources = new int[] {
-                    Favorites.ITEM_TYPE_WIDGET_CLOCK,
-                    Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME,
-                    Favorites.ITEM_TYPE_WIDGET_SEARCH,
-            };
-
-            final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
-
-            Cursor c = null;
-
-            db.beginTransaction();
-            try {
-                // Select and iterate through each matching widget
-                c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID, Favorites.ITEM_TYPE },
-                        selectWhere, null, null, null, null);
-
-                if (LOGD) Log.d(TAG, "found upgrade cursor count=" + c.getCount());
-
-                final ContentValues values = new ContentValues();
-                while (c != null && c.moveToNext()) {
-                    long favoriteId = c.getLong(0);
-                    int favoriteType = c.getInt(1);
-
-                    // Allocate and update database with new appWidgetId
-                    try {
-                        int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
-                        if (LOGD) {
-                            Log.d(TAG, "allocated appWidgetId=" + appWidgetId
-                                    + " for favoriteId=" + favoriteId);
-                        }
-                        values.clear();
-                        values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPWIDGET);
-                        values.put(Favorites.APPWIDGET_ID, appWidgetId);
-
-                        // Original widgets might not have valid spans when upgrading
-                        if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
-                            values.put(LauncherSettings.Favorites.SPANX, 4);
-                            values.put(LauncherSettings.Favorites.SPANY, 1);
-                        } else {
-                            values.put(LauncherSettings.Favorites.SPANX, 2);
-                            values.put(LauncherSettings.Favorites.SPANY, 2);
-                        }
-
-                        String updateWhere = Favorites._ID + "=" + favoriteId;
-                        db.update(TABLE_FAVORITES, values, updateWhere, null);
-
-                        if (favoriteType == Favorites.ITEM_TYPE_WIDGET_CLOCK) {
-                            // TODO: check return value
-                            appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
-                                    new ComponentName("com.android.alarmclock",
-                                    "com.android.alarmclock.AnalogAppWidgetProvider"));
-                        } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) {
-                            // TODO: check return value
-                            appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
-                                    new ComponentName("com.android.camera",
-                                    "com.android.camera.PhotoAppWidgetProvider"));
-                        } else if (favoriteType == Favorites.ITEM_TYPE_WIDGET_SEARCH) {
-                            // TODO: check return value
-                            appWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId,
-                                    getSearchWidgetProvider());
-                        }
-                    } catch (RuntimeException ex) {
-                        Log.e(TAG, "Problem allocating appWidgetId", ex);
-                    }
-                }
-
-                db.setTransactionSuccessful();
-            } catch (SQLException ex) {
-                Log.w(TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
-            } finally {
-                db.endTransaction();
-                if (c != null) {
-                    c.close();
-                }
-            }
-
-            // Update max item id
-            mMaxItemId = initializeMaxItemId(db);
-            if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId);
-        }
-
-        private boolean initializeExternalAdd(ContentValues values) {
+        @Thunk boolean initializeExternalAdd(ContentValues values) {
             // 1. Ensure that externally added items have a valid item id
             long id = generateNewItemId();
             values.put(LauncherSettings.Favorites._ID, id);
@@ -1312,7 +1032,7 @@
             return rank;
         }
 
-        private int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
+        @Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
             ArrayList<Long> screenIds = new ArrayList<Long>();
             // TODO: Use multiple loaders with fall-back and transaction.
             int count = loader.loadLayout(db, screenIds);
@@ -1339,12 +1059,7 @@
             return count;
         }
 
-        private ComponentName getSearchWidgetProvider() {
-            AppWidgetProviderInfo searchProvider = Utilities.getSearchWidgetProvider(mContext);
-            return (searchProvider == null) ? null : searchProvider.provider;
-        }
-
-        private void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
+        @Thunk void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
             final ContentResolver resolver = mContext.getContentResolver();
             Cursor c = null;
             int count = 0;
@@ -1395,10 +1110,10 @@
                         int curY = 0;
 
                         final LauncherAppState app = LauncherAppState.getInstance();
-                        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-                        final int width = (int) grid.numColumns;
-                        final int height = (int) grid.numRows;
-                        final int hotseatWidth = (int) grid.numHotseatIcons;
+                        final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+                        final int width = (int) profile.numColumns;
+                        final int height = (int) profile.numRows;
+                        final int hotseatWidth = (int) profile.numHotseatIcons;
 
                         final HashSet<String> seenIntents = new HashSet<String>(c.getCount());
 
@@ -1540,7 +1255,7 @@
                             int hotseatX = hotseat.keyAt(idx);
                             ContentValues values = hotseat.valueAt(idx);
 
-                            if (hotseatX == grid.hotseatAllAppsRank) {
+                            if (hotseatX == profile.hotseatAllAppsRank) {
                                 // let's drop this in the next available hole in the hotseat
                                 while (++hotseatX < hotseatWidth) {
                                     if (hotseat.get(hotseatX) == null) {
@@ -1619,6 +1334,8 @@
                         } finally {
                             db.endTransaction();
                         }
+
+                        updateFolderItemsRank(db, false);
                     }
                 } finally {
                     c.close();
@@ -1639,18 +1356,24 @@
     }
 
     /**
-     * Build a query string that will match any row where the column matches
-     * anything in the values list.
+     * @return the max _id in the provided table.
      */
-    private static String buildOrWhereString(String column, int[] values) {
-        StringBuilder selectWhere = new StringBuilder();
-        for (int i = values.length - 1; i >= 0; i--) {
-            selectWhere.append(column).append("=").append(values[i]);
-            if (i > 0) {
-                selectWhere.append(" OR ");
-            }
+    @Thunk static long getMaxId(SQLiteDatabase db, String table) {
+        Cursor c = db.rawQuery("SELECT MAX(_id) FROM " + table, null);
+        // get the result
+        long id = -1;
+        if (c != null && c.moveToNext()) {
+            id = c.getLong(0);
         }
-        return selectWhere.toString();
+        if (c != null) {
+            c.close();
+        }
+
+        if (id == -1) {
+            throw new RuntimeException("Error: could not query max id in " + table);
+        }
+
+        return id;
     }
 
     static class SqlArguments {
diff --git a/src/com/android/launcher3/LauncherProviderChangeListener.java b/src/com/android/launcher3/LauncherProviderChangeListener.java
index 0de96fb..1b78e9c 100644
--- a/src/com/android/launcher3/LauncherProviderChangeListener.java
+++ b/src/com/android/launcher3/LauncherProviderChangeListener.java
@@ -8,4 +8,8 @@
 public interface LauncherProviderChangeListener {
 
     public void onLauncherProviderChange();
+
+    public void onSettingsChanged(String settings, boolean value);
+
+    public void onAppWidgetHostReset();
 }
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
index 3bd0a78..a9b4955 100644
--- a/src/com/android/launcher3/LauncherScroller.java
+++ b/src/com/android/launcher3/LauncherScroller.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.os.Build;
-import android.util.FloatMath;
 import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -409,7 +408,7 @@
 
             float dx = (float) (mFinalX - mStartX);
             float dy = (float) (mFinalY - mStartY);
-            float hyp = FloatMath.sqrt(dx * dx + dy * dy);
+            float hyp = (float) Math.hypot(dx, dy);
 
             float ndx = dx / hyp;
             float ndy = dy / hyp;
@@ -426,7 +425,7 @@
         mMode = FLING_MODE;
         mFinished = false;
 
-        float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
+        float velocity = (float) Math.hypot(velocityX, velocityY);
 
         mVelocity = velocity;
         mDuration = getSplineFlingDuration(velocity);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 3553702..f2c85a1 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -19,17 +19,19 @@
 import android.net.Uri;
 import android.provider.BaseColumns;
 
+import com.android.launcher3.config.ProviderConfig;
+
 /**
  * Settings related utilities.
  */
-class LauncherSettings {
+public class LauncherSettings {
     /** Columns required on table staht will be subject to backup and restore. */
     static interface ChangeLogColumns extends BaseColumns {
         /**
          * The time of the last update to this row.
          * <P>Type: INTEGER</P>
          */
-        static final String MODIFIED = "modified";
+        public static final String MODIFIED = "modified";
     }
 
     static interface BaseLauncherColumns extends ChangeLogColumns {
@@ -37,7 +39,7 @@
          * Descriptive name of the gesture that can be displayed to the user.
          * <P>Type: TEXT</P>
          */
-        static final String TITLE = "title";
+        public static final String TITLE = "title";
 
         /**
          * The Intent URL of the gesture, describing what it points to. This
@@ -45,58 +47,58 @@
          * an Intent that can be launched.
          * <P>Type: TEXT</P>
          */
-        static final String INTENT = "intent";
+        public static final String INTENT = "intent";
 
         /**
          * The type of the gesture
          *
          * <P>Type: INTEGER</P>
          */
-        static final String ITEM_TYPE = "itemType";
+        public static final String ITEM_TYPE = "itemType";
 
         /**
          * The gesture is an application
          */
-        static final int ITEM_TYPE_APPLICATION = 0;
+        public static final int ITEM_TYPE_APPLICATION = 0;
 
         /**
          * The gesture is an application created shortcut
          */
-        static final int ITEM_TYPE_SHORTCUT = 1;
+        public static final int ITEM_TYPE_SHORTCUT = 1;
 
         /**
          * The icon type.
          * <P>Type: INTEGER</P>
          */
-        static final String ICON_TYPE = "iconType";
+        public static final String ICON_TYPE = "iconType";
 
         /**
          * The icon is a resource identified by a package name and an integer id.
          */
-        static final int ICON_TYPE_RESOURCE = 0;
+        public static final int ICON_TYPE_RESOURCE = 0;
 
         /**
          * The icon is a bitmap.
          */
-        static final int ICON_TYPE_BITMAP = 1;
+        public static final int ICON_TYPE_BITMAP = 1;
 
         /**
          * The icon package name, if icon type is ICON_TYPE_RESOURCE.
          * <P>Type: TEXT</P>
          */
-        static final String ICON_PACKAGE = "iconPackage";
+        public static final String ICON_PACKAGE = "iconPackage";
 
         /**
          * The icon resource id, if icon type is ICON_TYPE_RESOURCE.
          * <P>Type: TEXT</P>
          */
-        static final String ICON_RESOURCE = "iconResource";
+        public static final String ICON_RESOURCE = "iconResource";
 
         /**
          * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
          * <P>Type: BLOB</P>
          */
-        static final String ICON = "icon";
+        public static final String ICON = "icon";
     }
 
     /**
@@ -104,72 +106,59 @@
      *
      * Tracks the order of workspace screens.
      */
-    static final class WorkspaceScreens implements ChangeLogColumns {
+    public static final class WorkspaceScreens implements ChangeLogColumns {
+
+        public static final String TABLE_NAME = "workspaceScreens";
+
         /**
          * The content:// style URL for this table
          */
         static final Uri CONTENT_URI = Uri.parse("content://" +
-                LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_WORKSPACE_SCREENS +
-                "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
+                ProviderConfig.AUTHORITY + "/" + TABLE_NAME);
 
         /**
          * The rank of this screen -- ie. how it is ordered relative to the other screens.
          * <P>Type: INTEGER</P>
          */
-        static final String SCREEN_RANK = "screenRank";
+        public static final String SCREEN_RANK = "screenRank";
     }
 
     /**
      * Favorites.
      */
-    static final class Favorites implements BaseLauncherColumns {
-        /**
-         * The content:// style URL for this table
-         */
-        static final Uri CONTENT_URI = Uri.parse("content://" +
-                LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
-                "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
+    public static final class Favorites implements BaseLauncherColumns {
+
+        public static final String TABLE_NAME = "favorites";
 
         /**
          * The content:// style URL for this table
          */
-        static final Uri OLD_CONTENT_URI = Uri.parse("content://" +
-                LauncherProvider.OLD_AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
-                "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
-
-        /**
-         * The content:// style URL for this table. When this Uri is used, no notification is
-         * sent if the content changes.
-         */
-        static final Uri CONTENT_URI_NO_NOTIFICATION = Uri.parse("content://" +
-                LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
-                "?" + LauncherProvider.PARAMETER_NOTIFY + "=false");
+        public static final Uri CONTENT_URI = Uri.parse("content://" +
+                ProviderConfig.AUTHORITY + "/" + TABLE_NAME);
 
         /**
          * The content:// style URL for a given row, identified by its id.
          *
          * @param id The row id.
-         * @param notify True to send a notification is the content changes.
          *
          * @return The unique content URL for the specified row.
          */
-        static Uri getContentUri(long id, boolean notify) {
-            return Uri.parse("content://" + LauncherProvider.AUTHORITY +
-                    "/" + LauncherProvider.TABLE_FAVORITES + "/" + id + "?" +
-                    LauncherProvider.PARAMETER_NOTIFY + "=" + notify);
+        static Uri getContentUri(long id) {
+            return Uri.parse("content://" + ProviderConfig.AUTHORITY +
+                    "/" + TABLE_NAME + "/" + id);
         }
 
         /**
          * The container holding the favorite
          * <P>Type: INTEGER</P>
          */
-        static final String CONTAINER = "container";
+        public static final String CONTAINER = "container";
 
         /**
          * The icon is a resource identified by a package name and an integer id.
          */
-        static final int CONTAINER_DESKTOP = -100;
-        static final int CONTAINER_HOTSEAT = -101;
+        public static final int CONTAINER_DESKTOP = -100;
+        public static final int CONTAINER_HOTSEAT = -101;
 
         static final String containerToString(int container) {
             switch (container) {
@@ -183,33 +172,33 @@
          * The screen holding the favorite (if container is CONTAINER_DESKTOP)
          * <P>Type: INTEGER</P>
          */
-        static final String SCREEN = "screen";
+        public static final String SCREEN = "screen";
 
         /**
          * The X coordinate of the cell holding the favorite
          * (if container is CONTAINER_HOTSEAT or CONTAINER_HOTSEAT)
          * <P>Type: INTEGER</P>
          */
-        static final String CELLX = "cellX";
+        public static final String CELLX = "cellX";
 
         /**
          * The Y coordinate of the cell holding the favorite
          * (if container is CONTAINER_DESKTOP)
          * <P>Type: INTEGER</P>
          */
-        static final String CELLY = "cellY";
+        public static final String CELLY = "cellY";
 
         /**
          * The X span of the cell holding the favorite
          * <P>Type: INTEGER</P>
          */
-        static final String SPANX = "spanX";
+        public static final String SPANX = "spanX";
 
         /**
          * The Y span of the cell holding the favorite
          * <P>Type: INTEGER</P>
          */
-        static final String SPANY = "spanY";
+        public static final String SPANY = "spanY";
 
         /**
          * The profile id of the item in the cell.
@@ -217,12 +206,12 @@
          * Type: INTEGER
          * </P>
          */
-        static final String PROFILE_ID = "profileId";
+        public static final String PROFILE_ID = "profileId";
 
         /**
          * The favorite is a user created folder
          */
-        static final int ITEM_TYPE_FOLDER = 2;
+        public static final int ITEM_TYPE_FOLDER = 2;
 
         /**
         * The favorite is a live folder
@@ -231,26 +220,35 @@
         * exist within the launcher database will be ignored when loading.  That said, these
         * entries in the database may still exist, and are not automatically stripped.
         */
+        @Deprecated
         static final int ITEM_TYPE_LIVE_FOLDER = 3;
 
         /**
          * The favorite is a widget
          */
-        static final int ITEM_TYPE_APPWIDGET = 4;
+        public static final int ITEM_TYPE_APPWIDGET = 4;
+
+        /**
+         * The favorite is a custom widget provided by the launcher
+         */
+        public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
 
         /**
          * The favorite is a clock
          */
+        @Deprecated
         static final int ITEM_TYPE_WIDGET_CLOCK = 1000;
 
         /**
          * The favorite is a search widget
          */
+        @Deprecated
         static final int ITEM_TYPE_WIDGET_SEARCH = 1001;
 
         /**
          * The favorite is a photo frame
          */
+        @Deprecated
         static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
 
         /**
@@ -258,7 +256,7 @@
          *
          * <P>Type: INTEGER</P>
          */
-        static final String APPWIDGET_ID = "appWidgetId";
+        public static final String APPWIDGET_ID = "appWidgetId";
 
         /**
          * The ComponentName of the widget provider
@@ -281,6 +279,7 @@
          * live folders to find the content provider.
          * <P>Type: TEXT</P>
          */
+        @Deprecated
         static final String URI = "uri";
 
         /**
@@ -290,12 +289,40 @@
          * @see android.provider.LiveFolders#DISPLAY_MODE_GRID
          * @see android.provider.LiveFolders#DISPLAY_MODE_LIST
          */
+        @Deprecated
         static final String DISPLAY_MODE = "displayMode";
 
         /**
          * Boolean indicating that his item was restored and not yet successfully bound.
          * <P>Type: INTEGER</P>
          */
-        static final String RESTORED = "restored";
+        public static final String RESTORED = "restored";
+
+        /**
+         * Indicates the position of the item inside an auto-arranged view like folder or hotseat.
+         * <p>Type: INTEGER</p>
+         */
+        public static final String RANK = "rank";
+
+        /**
+         * Stores general flag based options for {@link ItemInfo}s.
+         * <p>Type: INTEGER</p>
+         */
+        public static final String OPTIONS = "options";
+    }
+
+    /**
+     * Launcher settings
+     */
+    public static final class Settings {
+
+        public static final Uri CONTENT_URI = Uri.parse("content://" +
+                ProviderConfig.AUTHORITY + "/settings");
+
+        public static final String METHOD_GET_BOOLEAN = "get_boolean_setting";
+        public static final String METHOD_SET_BOOLEAN = "set_boolean_setting";
+
+        public static final String EXTRA_VALUE = "value";
+        public static final String EXTRA_DEFAULT_VALUE = "default_value";
     }
 }
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
new file mode 100644
index 0000000..d69b743
--- /dev/null
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -0,0 +1,762 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.allapps.AllAppsContainerView;
+import com.android.launcher3.util.UiThreadCircularReveal;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetsContainerView;
+
+import java.util.HashMap;
+
+/**
+ * TODO: figure out what kind of tests we can write for this
+ *
+ * Things to test when changing the following class.
+ *   - Home from workspace
+ *          - from center screen
+ *          - from other screens
+ *   - Home from all apps
+ *          - from center screen
+ *          - from other screens
+ *   - Back from all apps
+ *          - from center screen
+ *          - from other screens
+ *   - Launch app from workspace and quit
+ *          - with back
+ *          - with home
+ *   - Launch app from all apps and quit
+ *          - with back
+ *          - with home
+ *   - Go to a screen that's not the default, then all
+ *     apps, and launch and app, and go back
+ *          - with back
+ *          -with home
+ *   - On workspace, long press power and go back
+ *          - with back
+ *          - with home
+ *   - On all apps, long press power and go back
+ *          - with back
+ *          - with home
+ *   - On workspace, power off
+ *   - On all apps, power off
+ *   - Launch an app and turn off the screen while in that app
+ *          - Go back with home key
+ *          - Go back with back key  TODO: make this not go to workspace
+ *          - From all apps
+ *          - From workspace
+ *   - Enter and exit car mode (becuase it causes an extra configuration changed)
+ *          - From all apps
+ *          - From the center workspace
+ *          - From another workspace
+ */
+public class LauncherStateTransitionAnimation {
+
+    /**
+     * Callbacks made during the state transition
+     */
+    interface Callbacks {
+        public void onStateTransitionHideSearchBar();
+    }
+
+    /**
+     * Private callbacks made during transition setup.
+     */
+    static abstract class PrivateTransitionCallbacks {
+        float getMaterialRevealViewFinalAlpha(View revealView) {
+            return 0;
+        }
+        float getMaterialRevealViewStartFinalRadius() {
+            return 0;
+        }
+        AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(View revealView,
+                View buttonView) {
+            return null;
+        }
+        void onTransitionComplete() {}
+    }
+
+    public static final String TAG = "LauncherStateTransitionAnimation";
+
+    // Flags to determine how to set the layers on views before the transition animation
+    public static final int BUILD_LAYER = 0;
+    public static final int BUILD_AND_SET_LAYER = 1;
+    public static final int SINGLE_FRAME_DELAY = 16;
+
+    @Thunk Launcher mLauncher;
+    @Thunk Callbacks mCb;
+    @Thunk AnimatorSet mStateAnimation;
+
+    public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) {
+        mLauncher = l;
+        mCb = cb;
+    }
+
+    /**
+     * Starts an animation to the apps view.
+     *
+     * @param startSearchAfterTransition Immediately starts app search after the transition to
+     *                                   All Apps is completed.
+     */
+    public void startAnimationToAllApps(final boolean animated,
+            final boolean startSearchAfterTransition) {
+        final AllAppsContainerView toView = mLauncher.getAppsView();
+        final View buttonView = mLauncher.getAllAppsButton();
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+            @Override
+            public float getMaterialRevealViewFinalAlpha(View revealView) {
+                return 1f;
+            }
+            @Override
+            public float getMaterialRevealViewStartFinalRadius() {
+                int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
+                return allAppsButtonSize / 2;
+            }
+            @Override
+            public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+                    final View revealView, final View allAppsButtonView) {
+                return new AnimatorListenerAdapter() {
+                    public void onAnimationStart(Animator animation) {
+                        allAppsButtonView.setVisibility(View.INVISIBLE);
+                    }
+                    public void onAnimationEnd(Animator animation) {
+                        allAppsButtonView.setVisibility(View.VISIBLE);
+                    }
+                };
+            }
+            @Override
+            void onTransitionComplete() {
+                if (startSearchAfterTransition) {
+                    toView.startAppsSearch();
+                }
+            }
+        };
+        // Only animate the search bar if animating from spring loaded mode back to all apps
+        startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, buttonView, toView,
+                toView.getContentView(), toView.getRevealView(), toView.getSearchBarView(),
+                animated, true /* hideSearchBar */, cb);
+    }
+
+    /**
+     * Starts an animation to the widgets view.
+     */
+    public void startAnimationToWidgets(final boolean animated) {
+        final WidgetsContainerView toView = mLauncher.getWidgetsView();
+        final View buttonView = mLauncher.getWidgetsButton();
+
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+            @Override
+            public float getMaterialRevealViewFinalAlpha(View revealView) {
+                return 0.3f;
+            }
+        };
+        startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, buttonView, toView,
+                toView.getContentView(), toView.getRevealView(), null, animated,
+                true /* hideSearchBar */, cb);
+    }
+
+    /**
+     * Starts and animation to the workspace from the current overlay view.
+     */
+    public void startAnimationToWorkspace(final Launcher.State fromState,
+              final Workspace.State toWorkspaceState, final int toWorkspacePage,
+              final boolean animated, final Runnable onCompleteRunnable) {
+        if (toWorkspaceState != Workspace.State.NORMAL &&
+                toWorkspaceState != Workspace.State.SPRING_LOADED &&
+                toWorkspaceState != Workspace.State.OVERVIEW) {
+            Log.e(TAG, "Unexpected call to startAnimationToWorkspace");
+        }
+
+        if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
+            startAnimationToWorkspaceFromAllApps(toWorkspaceState, toWorkspacePage,
+                    animated, onCompleteRunnable);
+        } else {
+            startAnimationToWorkspaceFromWidgets(toWorkspaceState, toWorkspacePage,
+                    animated, onCompleteRunnable);
+        }
+    }
+
+    /**
+     * Creates and starts a new animation to a particular overlay view.
+     */
+    @SuppressLint("NewApi")
+    private void startAnimationToOverlay(final Workspace.State toWorkspaceState,
+            final View buttonView, final View toView, final View contentView, final View revealView,
+            final View overlaySearchBarView, final boolean animated, final boolean hideSearchBar,
+            final PrivateTransitionCallbacks pCb) {
+        final Resources res = mLauncher.getResources();
+        final boolean material = Utilities.isLmpOrAbove();
+        final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
+        final int itemsAlphaStagger =
+                res.getInteger(R.integer.config_overlayItemsAlphaStagger);
+
+        final View fromView = mLauncher.getWorkspace();
+
+        final HashMap<View, Integer> layerViews = new HashMap<>();
+
+        // If for some reason our views aren't initialized, don't animate
+        boolean initialized = buttonView != null;
+
+        // Cancel the current animation
+        cancelAnimation();
+
+        // Create the workspace animation.
+        // NOTE: this call apparently also sets the state for the workspace if !animated
+        Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState, -1,
+                animated, overlaySearchBarView != null /* hasOverlaySearchBar */, layerViews);
+
+        if (animated && initialized) {
+            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+            // Setup the reveal view animation
+            int width = revealView.getMeasuredWidth();
+            int height = revealView.getMeasuredHeight();
+            float revealRadius = (float) Math.hypot(width / 2, height / 2);
+            revealView.setVisibility(View.VISIBLE);
+            revealView.setAlpha(0f);
+            revealView.setTranslationY(0f);
+            revealView.setTranslationX(0f);
+
+            // Calculate the final animation values
+            final float revealViewToAlpha;
+            final float revealViewToXDrift;
+            final float revealViewToYDrift;
+            if (material) {
+                int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
+                        buttonView, null);
+                revealViewToAlpha = pCb.getMaterialRevealViewFinalAlpha(revealView);
+                revealViewToYDrift = buttonViewToPanelDelta[1];
+                revealViewToXDrift = buttonViewToPanelDelta[0];
+            } else {
+                revealViewToAlpha = 0f;
+                revealViewToYDrift = 2 * height / 3;
+                revealViewToXDrift = 0;
+            }
+
+            // Create the animators
+            PropertyValuesHolder panelAlpha =
+                    PropertyValuesHolder.ofFloat("alpha", revealViewToAlpha, 1f);
+            PropertyValuesHolder panelDriftY =
+                    PropertyValuesHolder.ofFloat("translationY", revealViewToYDrift, 0);
+            PropertyValuesHolder panelDriftX =
+                    PropertyValuesHolder.ofFloat("translationX", revealViewToXDrift, 0);
+            ObjectAnimator panelAlphaAndDrift = ObjectAnimator.ofPropertyValuesHolder(revealView,
+                    panelAlpha, panelDriftY, panelDriftX);
+            panelAlphaAndDrift.setDuration(revealDuration);
+            panelAlphaAndDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+
+            // Play the animation
+            layerViews.put(revealView, BUILD_AND_SET_LAYER);
+            mStateAnimation.play(panelAlphaAndDrift);
+
+            if (overlaySearchBarView != null) {
+                overlaySearchBarView.setAlpha(0f);
+                ObjectAnimator searchBarAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 0f, 1f);
+                searchBarAlpha.setDuration(100);
+                searchBarAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+                layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
+                mStateAnimation.play(searchBarAlpha);
+            }
+
+            // Setup the animation for the content view
+            contentView.setVisibility(View.VISIBLE);
+            contentView.setAlpha(0f);
+            contentView.setTranslationY(revealViewToYDrift);
+            layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
+            // Create the individual animators
+            ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
+                    revealViewToYDrift, 0);
+            pageDrift.setDuration(revealDuration);
+            pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0));
+            pageDrift.setStartDelay(itemsAlphaStagger);
+            mStateAnimation.play(pageDrift);
+
+            ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f);
+            itemsAlpha.setDuration(revealDuration);
+            itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f));
+            itemsAlpha.setStartDelay(itemsAlphaStagger);
+            mStateAnimation.play(itemsAlpha);
+
+            if (material) {
+                float startRadius = pCb.getMaterialRevealViewStartFinalRadius();
+                AnimatorListenerAdapter listener = pCb.getMaterialRevealViewAnimatorListener(
+                        revealView, buttonView);
+                Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
+                        height / 2, startRadius, revealRadius);
+                reveal.setDuration(revealDuration);
+                reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+                if (listener != null) {
+                    reveal.addListener(listener);
+                }
+                mStateAnimation.play(reveal);
+            }
+
+            mStateAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    dispatchOnLauncherTransitionEnd(fromView, animated, false);
+                    dispatchOnLauncherTransitionEnd(toView, animated, false);
+
+                    // Hide the reveal view
+                    revealView.setVisibility(View.INVISIBLE);
+
+                    // Disable all necessary layers
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_NONE, null);
+                        }
+                    }
+
+                    if (hideSearchBar) {
+                        mCb.onStateTransitionHideSearchBar();
+                    }
+
+                    // This can hold unnecessary references to views.
+                    mStateAnimation = null;
+                    pCb.onTransitionComplete();
+                }
+
+            });
+
+            // Play the workspace animation
+            if (workspaceAnim != null) {
+                mStateAnimation.play(workspaceAnim);
+            }
+
+            // Dispatch the prepare transition signal
+            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+            dispatchOnLauncherTransitionPrepare(toView, animated, false);
+
+
+            final AnimatorSet stateAnimation = mStateAnimation;
+            final Runnable startAnimRunnable = new Runnable() {
+                public void run() {
+                    // Check that mStateAnimation hasn't changed while
+                    // we waited for a layout/draw pass
+                    if (mStateAnimation != stateAnimation)
+                        return;
+                    dispatchOnLauncherTransitionStart(fromView, animated, false);
+                    dispatchOnLauncherTransitionStart(toView, animated, false);
+
+                    // Enable all necessary layers
+                    boolean isLmpOrAbove = Utilities.isLmpOrAbove();
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                        }
+                        if (isLmpOrAbove && Utilities.isViewAttachedToWindow(v)) {
+                            v.buildLayer();
+                        }
+                    }
+
+                    // Focus the new view
+                    toView.requestFocus();
+
+                    mStateAnimation.start();
+                }
+            };
+            toView.bringToFront();
+            toView.setVisibility(View.VISIBLE);
+            toView.post(startAnimRunnable);
+        } else {
+            toView.setTranslationX(0.0f);
+            toView.setTranslationY(0.0f);
+            toView.setScaleX(1.0f);
+            toView.setScaleY(1.0f);
+            toView.setVisibility(View.VISIBLE);
+            toView.bringToFront();
+
+            // Show the content view
+            contentView.setVisibility(View.VISIBLE);
+
+            if (hideSearchBar) {
+                mCb.onStateTransitionHideSearchBar();
+            }
+
+            dispatchOnLauncherTransitionPrepare(fromView, animated, false);
+            dispatchOnLauncherTransitionStart(fromView, animated, false);
+            dispatchOnLauncherTransitionEnd(fromView, animated, false);
+            dispatchOnLauncherTransitionPrepare(toView, animated, false);
+            dispatchOnLauncherTransitionStart(toView, animated, false);
+            dispatchOnLauncherTransitionEnd(toView, animated, false);
+            pCb.onTransitionComplete();
+        }
+    }
+
+    /**
+     * Starts and animation to the workspace from the apps view.
+     */
+    private void startAnimationToWorkspaceFromAllApps(final Workspace.State toWorkspaceState,
+            final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) {
+        AllAppsContainerView appsView = mLauncher.getAppsView();
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+            int[] mAllAppsToPanelDelta;
+
+            @Override
+            float getMaterialRevealViewFinalAlpha(View revealView) {
+                // No alpha anim from all apps
+                return 1f;
+            }
+            @Override
+            float getMaterialRevealViewStartFinalRadius() {
+                int allAppsButtonSize = mLauncher.getDeviceProfile().allAppsButtonVisualSize;
+                return allAppsButtonSize / 2;
+            }
+            @Override
+            public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+                    final View revealView, final View allAppsButtonView) {
+                return new AnimatorListenerAdapter() {
+                    public void onAnimationStart(Animator animation) {
+                        // We set the alpha instead of visibility to ensure that the focus does not
+                        // get taken from the all apps view
+                        allAppsButtonView.setVisibility(View.VISIBLE);
+                        allAppsButtonView.setAlpha(0f);
+                    }
+                    public void onAnimationEnd(Animator animation) {
+                        // Hide the reveal view
+                        revealView.setVisibility(View.INVISIBLE);
+
+                        // Show the all apps button, and focus it
+                        allAppsButtonView.setAlpha(1f);
+                    }
+                };
+            }
+        };
+        // Only animate the search bar if animating to spring loaded mode from all apps
+        startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage,
+                mLauncher.getAllAppsButton(), appsView, appsView.getContentView(),
+                appsView.getRevealView(), appsView.getSearchBarView(), animated,
+                onCompleteRunnable, cb);
+    }
+
+    /**
+     * Starts and animation to the workspace from the widgets view.
+     */
+    private void startAnimationToWorkspaceFromWidgets(final Workspace.State toWorkspaceState,
+              final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) {
+        final WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
+        PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
+            @Override
+            float getMaterialRevealViewFinalAlpha(View revealView) {
+                return 0.3f;
+            }
+            @Override
+            public AnimatorListenerAdapter getMaterialRevealViewAnimatorListener(
+                    final View revealView, final View widgetsButtonView) {
+                return new AnimatorListenerAdapter() {
+                    public void onAnimationEnd(Animator animation) {
+                        // Hide the reveal view
+                        revealView.setVisibility(View.INVISIBLE);
+                    }
+                };
+            }
+        };
+        startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage,
+                mLauncher.getWidgetsButton(), widgetsView, widgetsView.getContentView(),
+                widgetsView.getRevealView(), null, animated, onCompleteRunnable, cb);
+    }
+
+    /**
+     * Creates and starts a new animation to the workspace.
+     */
+    private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
+              final int toWorkspacePage, final View buttonView, final View fromView,
+              final View contentView, final View revealView, final View overlaySearchBarView,
+              final boolean animated, final Runnable onCompleteRunnable,
+              final PrivateTransitionCallbacks pCb) {
+        final Resources res = mLauncher.getResources();
+        final boolean material = Utilities.isLmpOrAbove();
+        final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime);
+        final int itemsAlphaStagger =
+                res.getInteger(R.integer.config_overlayItemsAlphaStagger);
+
+        final View toView = mLauncher.getWorkspace();
+
+        final HashMap<View, Integer> layerViews = new HashMap<>();
+
+        // If for some reason our views aren't initialized, don't animate
+        boolean initialized = buttonView != null;
+
+        // Cancel the current animation
+        cancelAnimation();
+
+        // Create the workspace animation.
+        // NOTE: this call apparently also sets the state for the workspace if !animated
+        Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState,
+                toWorkspacePage, animated, overlaySearchBarView != null /* hasOverlaySearchBar */,
+                layerViews);
+
+        if (animated && initialized) {
+            mStateAnimation = LauncherAnimUtils.createAnimatorSet();
+
+            // Play the workspace animation
+            if (workspaceAnim != null) {
+                mStateAnimation.play(workspaceAnim);
+            }
+
+            // hideAppsCustomizeHelper is called in some cases when it is already hidden
+            // don't perform all these no-op animations. In particularly, this was causing
+            // the all-apps button to pop in and out.
+            if (fromView.getVisibility() == View.VISIBLE) {
+                int width = revealView.getMeasuredWidth();
+                int height = revealView.getMeasuredHeight();
+                float revealRadius = (float) Math.hypot(width / 2, height / 2);
+                revealView.setVisibility(View.VISIBLE);
+                revealView.setAlpha(1f);
+                revealView.setTranslationY(0);
+                layerViews.put(revealView, BUILD_AND_SET_LAYER);
+
+                // Calculate the final animation values
+                final float revealViewToXDrift;
+                final float revealViewToYDrift;
+                if (material) {
+                    int[] buttonViewToPanelDelta = Utilities.getCenterDeltaInScreenSpace(revealView,
+                            buttonView, null);
+                    revealViewToYDrift = buttonViewToPanelDelta[1];
+                    revealViewToXDrift = buttonViewToPanelDelta[0];
+                } else {
+                    revealViewToYDrift = 2 * height / 3;
+                    revealViewToXDrift = 0;
+                }
+
+                // The vertical motion of the apps panel should be delayed by one frame
+                // from the conceal animation in order to give the right feel. We correspondingly
+                // shorten the duration so that the slide and conceal end at the same time.
+                TimeInterpolator decelerateInterpolator = material ?
+                        new LogDecelerateInterpolator(100, 0) :
+                        new DecelerateInterpolator(1f);
+                ObjectAnimator panelDriftY = ObjectAnimator.ofFloat(revealView, "translationY",
+                        0, revealViewToYDrift);
+                panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+                panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                panelDriftY.setInterpolator(decelerateInterpolator);
+                mStateAnimation.play(panelDriftY);
+
+                ObjectAnimator panelDriftX = ObjectAnimator.ofFloat(revealView, "translationX",
+                        0, revealViewToXDrift);
+                panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+                panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                panelDriftX.setInterpolator(decelerateInterpolator);
+                mStateAnimation.play(panelDriftX);
+
+                // Setup animation for the reveal panel alpha
+                final float revealViewToAlpha = !material ? 0f :
+                        pCb.getMaterialRevealViewFinalAlpha(revealView);
+                if (revealViewToAlpha != 1f) {
+                    ObjectAnimator panelAlpha = ObjectAnimator.ofFloat(revealView, "alpha",
+                            1f, revealViewToAlpha);
+                    panelAlpha.setDuration(material ? revealDuration : 150);
+                    panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                    panelAlpha.setInterpolator(decelerateInterpolator);
+                    mStateAnimation.play(panelAlpha);
+                }
+
+                // Setup the animation for the content view
+                layerViews.put(contentView, BUILD_AND_SET_LAYER);
+
+                // Create the individual animators
+                ObjectAnimator pageDrift = ObjectAnimator.ofFloat(contentView, "translationY",
+                        0, revealViewToYDrift);
+                contentView.setTranslationY(0);
+                pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY);
+                pageDrift.setInterpolator(decelerateInterpolator);
+                pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                mStateAnimation.play(pageDrift);
+
+                contentView.setAlpha(1f);
+                ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 1f, 0f);
+                itemsAlpha.setDuration(100);
+                itemsAlpha.setInterpolator(decelerateInterpolator);
+                mStateAnimation.play(itemsAlpha);
+
+                if (overlaySearchBarView != null) {
+                    overlaySearchBarView.setAlpha(1f);
+                    ObjectAnimator searchAlpha = ObjectAnimator.ofFloat(overlaySearchBarView, "alpha", 1f, 0f);
+                    searchAlpha.setDuration(material ? 100 : 150);
+                    searchAlpha.setInterpolator(decelerateInterpolator);
+                    searchAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY);
+                    layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER);
+                    mStateAnimation.play(searchAlpha);
+                }
+
+                if (material) {
+                    // Animate the all apps button
+                    float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
+                    AnimatorListenerAdapter listener =
+                            pCb.getMaterialRevealViewAnimatorListener(revealView, buttonView);
+                    Animator reveal = UiThreadCircularReveal.createCircularReveal(revealView, width / 2,
+                            height / 2, revealRadius, finalRadius);
+                    reveal.setInterpolator(new LogDecelerateInterpolator(100, 0));
+                    reveal.setDuration(revealDuration);
+                    reveal.setStartDelay(itemsAlphaStagger);
+                    if (listener != null) {
+                        reveal.addListener(listener);
+                    }
+                    mStateAnimation.play(reveal);
+                }
+
+                dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+                dispatchOnLauncherTransitionPrepare(toView, animated, true);
+            }
+
+            mStateAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    fromView.setVisibility(View.GONE);
+                    dispatchOnLauncherTransitionEnd(fromView, animated, true);
+                    dispatchOnLauncherTransitionEnd(toView, animated, true);
+
+                    // Run any queued runnables
+                    if (onCompleteRunnable != null) {
+                        onCompleteRunnable.run();
+                    }
+
+                    // Disable all necessary layers
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_NONE, null);
+                        }
+                    }
+
+                    // Reset page transforms
+                    if (contentView != null) {
+                        contentView.setTranslationX(0);
+                        contentView.setTranslationY(0);
+                        contentView.setAlpha(1);
+                    }
+                    if (overlaySearchBarView != null) {
+                        overlaySearchBarView.setAlpha(1f);
+                    }
+
+                    // This can hold unnecessary references to views.
+                    mStateAnimation = null;
+                    pCb.onTransitionComplete();
+                }
+            });
+
+            final AnimatorSet stateAnimation = mStateAnimation;
+            final Runnable startAnimRunnable = new Runnable() {
+                public void run() {
+                    // Check that mStateAnimation hasn't changed while
+                    // we waited for a layout/draw pass
+                    if (mStateAnimation != stateAnimation)
+                        return;
+                    dispatchOnLauncherTransitionStart(fromView, animated, false);
+                    dispatchOnLauncherTransitionStart(toView, animated, false);
+
+                    // Enable all necessary layers
+                    boolean isLmpOrAbove = Utilities.isLmpOrAbove();
+                    for (View v : layerViews.keySet()) {
+                        if (layerViews.get(v) == BUILD_AND_SET_LAYER) {
+                            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                        }
+                        if (isLmpOrAbove && Utilities.isViewAttachedToWindow(v)) {
+                            v.buildLayer();
+                        }
+                    }
+                    mStateAnimation.start();
+                }
+            };
+            fromView.post(startAnimRunnable);
+        } else {
+            fromView.setVisibility(View.GONE);
+            dispatchOnLauncherTransitionPrepare(fromView, animated, true);
+            dispatchOnLauncherTransitionStart(fromView, animated, true);
+            dispatchOnLauncherTransitionEnd(fromView, animated, true);
+            dispatchOnLauncherTransitionPrepare(toView, animated, true);
+            dispatchOnLauncherTransitionStart(toView, animated, true);
+            dispatchOnLauncherTransitionEnd(toView, animated, true);
+            pCb.onTransitionComplete();
+
+            // Run any queued runnables
+            if (onCompleteRunnable != null) {
+                onCompleteRunnable.run();
+            }
+        }
+    }
+
+
+    /**
+     * Dispatches the prepare-transition event to suitable views.
+     */
+    void dispatchOnLauncherTransitionPrepare(View v, boolean animated, boolean toWorkspace) {
+        if (v instanceof LauncherTransitionable) {
+            ((LauncherTransitionable) v).onLauncherTransitionPrepare(mLauncher, animated,
+                    toWorkspace);
+        }
+    }
+
+    /**
+     * Dispatches the start-transition event to suitable views.
+     */
+    void dispatchOnLauncherTransitionStart(View v, boolean animated, boolean toWorkspace) {
+        if (v instanceof LauncherTransitionable) {
+            ((LauncherTransitionable) v).onLauncherTransitionStart(mLauncher, animated,
+                    toWorkspace);
+        }
+
+        // Update the workspace transition step as well
+        dispatchOnLauncherTransitionStep(v, 0f);
+    }
+
+    /**
+     * Dispatches the step-transition event to suitable views.
+     */
+    void dispatchOnLauncherTransitionStep(View v, float t) {
+        if (v instanceof LauncherTransitionable) {
+            ((LauncherTransitionable) v).onLauncherTransitionStep(mLauncher, t);
+        }
+    }
+
+    /**
+     * Dispatches the end-transition event to suitable views.
+     */
+    void dispatchOnLauncherTransitionEnd(View v, boolean animated, boolean toWorkspace) {
+        if (v instanceof LauncherTransitionable) {
+            ((LauncherTransitionable) v).onLauncherTransitionEnd(mLauncher, animated,
+                    toWorkspace);
+        }
+
+        // Update the workspace transition step as well
+        dispatchOnLauncherTransitionStep(v, 1f);
+    }
+
+    /**
+     * Cancels the current animation.
+     */
+    private void cancelAnimation() {
+        if (mStateAnimation != null) {
+            mStateAnimation.setDuration(0);
+            mStateAnimation.cancel();
+            mStateAnimation = null;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/LauncherTransitionable.java b/src/com/android/launcher3/LauncherTransitionable.java
new file mode 100644
index 0000000..49af692
--- /dev/null
+++ b/src/com/android/launcher3/LauncherTransitionable.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+/**
+ * An interface to get callbacks during a launcher transition.
+ */
+public interface LauncherTransitionable {
+    void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace);
+    void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace);
+    void onLauncherTransitionStep(Launcher l, float t);
+    void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace);
+}
diff --git a/src/com/android/launcher3/MemoryTracker.java b/src/com/android/launcher3/MemoryTracker.java
index 2d37c80..067a50f 100644
--- a/src/com/android/launcher3/MemoryTracker.java
+++ b/src/com/android/launcher3/MemoryTracker.java
@@ -101,7 +101,7 @@
 
     public void startTrackingProcess(int pid, String name, long start) {
         synchronized (mLock) {
-            final Long lpid = new Long(pid);
+            final Long lpid = Long.valueOf(pid);
 
             if (mPids.contains(lpid)) return;
 
diff --git a/src/com/android/launcher3/PackageChangedReceiver.java b/src/com/android/launcher3/PackageChangedReceiver.java
deleted file mode 100644
index e59f6d8..0000000
--- a/src/com/android/launcher3/PackageChangedReceiver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.android.launcher3;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class PackageChangedReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(final Context context, Intent intent) {
-        final String packageName = intent.getData().getSchemeSpecificPart();
-
-        if (packageName == null || packageName.length() == 0) {
-            // they sent us a bad intent
-            return;
-        }
-        // in rare cases the receiver races with the application to set up LauncherAppState
-        LauncherAppState.setApplicationContext(context.getApplicationContext());
-        LauncherAppState app = LauncherAppState.getInstance();
-        WidgetPreviewLoader.removePackageFromDb(app.getWidgetPreviewCacheDb(), packageName);
-    }
-}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 7d65f46..218c1a3 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -19,16 +19,16 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.PointF;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -46,21 +46,13 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.AnimationUtils;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
+
+import com.android.launcher3.util.LauncherEdgeEffect;
+import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
 
-interface Page {
-    public int getPageChildCount();
-    public View getChildOnPageAt(int i);
-    public void removeAllViewsOnPage();
-    public void removeViewOnPageAt(int i);
-    public int indexOfChildOnPage(View v);
-}
-
 /**
  * An abstraction of the original Workspace which supports browsing through a
  * sequential list of "pages"
@@ -74,28 +66,21 @@
     private static final int MIN_LENGTH_FOR_FLING = 25;
 
     protected static final int PAGE_SNAP_ANIMATION_DURATION = 750;
-    protected static final int OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION = 350;
     protected static final int SLOW_PAGE_SNAP_ANIMATION_DURATION = 950;
     protected static final float NANOTIME_DIV = 1000000000.0f;
 
-    private static final float OVERSCROLL_ACCELERATE_FACTOR = 2;
-    private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
-
     private static final float RETURN_TO_ORIGINAL_PAGE_THRESHOLD = 0.33f;
     // The page is moved more than halfway, automatically move to the next page on touch up.
     private static final float SIGNIFICANT_MOVE_THRESHOLD = 0.4f;
 
+    private static final float MAX_SCROLL_PROGRESS = 1.0f;
+
     // The following constants need to be scaled based on density. The scaled versions will be
     // assigned to the corresponding member variables below.
     private static final int FLING_THRESHOLD_VELOCITY = 500;
     private static final int MIN_SNAP_VELOCITY = 1500;
     private static final int MIN_FLING_VELOCITY = 250;
 
-    // We are disabling touch interaction of the widget region for factory ROM.
-    private static final boolean DISABLE_TOUCH_INTERACTION = false;
-    private static final boolean DISABLE_TOUCH_SIDE_PAGES = true;
-    private static final boolean DISABLE_FLING_TO_DELETE = true;
-
     public static final int INVALID_RESTORE_PAGE = -1001;
 
     private boolean mFreeScroll = false;
@@ -124,7 +109,7 @@
     protected LauncherScroller mScroller;
     private Interpolator mDefaultInterpolator;
     private VelocityTracker mVelocityTracker;
-    private int mPageSpacing = 0;
+    @Thunk int mPageSpacing = 0;
 
     private float mParentDownMotionX;
     private float mParentDownMotionY;
@@ -156,7 +141,6 @@
     protected OnLongClickListener mLongClickListener;
 
     protected int mTouchSlop;
-    private int mPagingTouchSlop;
     private int mMaximumVelocity;
     protected int mPageLayoutWidthGap;
     protected int mPageLayoutHeightGap;
@@ -164,15 +148,8 @@
     protected int mCellCountY = 0;
     protected boolean mCenterPagesVertically;
     protected boolean mAllowOverScroll = true;
-    protected int mUnboundedScrollX;
     protected int[] mTempVisiblePagesRange = new int[2];
     protected boolean mForceDrawAllChildrenNextFrame;
-    private boolean mSpacePagesAutomatically = false;
-
-    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
-    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
-    // the screens from continuing to translate beyond the normal bounds.
-    protected int mOverScrollX;
 
     protected static final int INVALID_POINTER = -1;
 
@@ -180,37 +157,16 @@
 
     private PageSwitchListener mPageSwitchListener;
 
-    protected ArrayList<Boolean> mDirtyPageContent;
-
-    // If true, syncPages and syncPageItems will be called to refresh pages
-    protected boolean mContentIsRefreshable = true;
-
     // If true, modify alpha of neighboring pages as user scrolls left/right
     protected boolean mFadeInAdjacentScreens = false;
 
-    // It true, use a different slop parameter (pagingTouchSlop = 2 * touchSlop) for deciding
-    // to switch to a new page
-    protected boolean mUsePagingTouchSlop = true;
-
-    // If true, the subclass should directly update scrollX itself in its computeScroll method
-    // (SmoothPagedView does this)
-    protected boolean mDeferScrollUpdate = false;
-    protected boolean mDeferLoadAssociatedPagesUntilScrollCompletes = false;
-
     protected boolean mIsPageMoving = false;
 
-    // All syncs and layout passes are deferred until data is ready.
-    protected boolean mIsDataReady = false;
-
-    protected boolean mAllowLongPress = true;
-
     private boolean mWasInOverscroll = false;
 
     // Page Indicator
-    private int mPageIndicatorViewId;
-    private PageIndicator mPageIndicator;
-    private boolean mAllowPagedViewAnimations = true;
-
+    @Thunk int mPageIndicatorViewId;
+    @Thunk PageIndicator mPageIndicator;
     // The viewport whether the pages are to be contained (the actual view may be larger than the
     // viewport)
     private Rect mViewport = new Rect();
@@ -218,16 +174,15 @@
     // Reordering
     // We use the min scale to determine how much to expand the actually PagedView measured
     // dimensions such that when we are zoomed out, the view is not clipped
-    private int REORDERING_DROP_REPOSITION_DURATION = 200;
-    protected int REORDERING_REORDER_REPOSITION_DURATION = 300;
-    protected int REORDERING_ZOOM_IN_OUT_DURATION = 250;
-    private int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80;
+    private static int REORDERING_DROP_REPOSITION_DURATION = 200;
+    @Thunk static int REORDERING_REORDER_REPOSITION_DURATION = 300;
+    private static int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80;
+
     private float mMinScale = 1f;
     private boolean mUseMinScale = false;
     protected View mDragView;
-    protected AnimatorSet mZoomInOutAnim;
     private Runnable mSidePageHoverRunnable;
-    private int mSidePageHoverIndex = -1;
+    @Thunk int mSidePageHoverIndex = -1;
     // This variable's scope is only for the duration of startReordering() and endReordering()
     private boolean mReorderingStarted = false;
     // This variable's scope is for the duration of startReordering() and after the zoomIn()
@@ -239,30 +194,17 @@
     private Runnable mPostReorderingPreZoomInRunnable;
 
     // Convenience/caching
-    private Matrix mTmpInvMatrix = new Matrix();
-    private float[] mTmpPoint = new float[2];
-    private int[] mTmpIntPoint = new int[2];
-    private Rect mTmpRect = new Rect();
-    private Rect mAltTmpRect = new Rect();
-
-    // Fling to delete
-    private int FLING_TO_DELETE_FADE_OUT_DURATION = 350;
-    private float FLING_TO_DELETE_FRICTION = 0.035f;
-    // The degrees specifies how much deviation from the up vector to still consider a fling "up"
-    private float FLING_TO_DELETE_MAX_FLING_DEGREES = 65f;
-    protected int mFlingToDeleteThresholdVelocity = -1400;
-    // Drag to delete
-    private boolean mDeferringForDelete = false;
-    private int DELETE_SLIDE_IN_SIDE_PAGE_DURATION = 250;
-    private int DRAG_TO_DELETE_FADE_OUT_DURATION = 350;
-
-    // Drop to delete
-    private View mDeleteDropTarget;
-
-    // Bouncer
-    private boolean mTopAlignPageWhenShrinkingForBouncer = false;
+    private static final Matrix sTmpInvMatrix = new Matrix();
+    private static final float[] sTmpPoint = new float[2];
+    private static final int[] sTmpIntPoint = new int[2];
+    private static final Rect sTmpRect = new Rect();
 
     protected final Rect mInsets = new Rect();
+    protected final boolean mIsRtl;
+
+    // Edge effect
+    private final LauncherEdgeEffect mEdgeGlowLeft = new LauncherEdgeEffect();
+    private final LauncherEdgeEffect mEdgeGlowRight = new LauncherEdgeEffect();
 
     public interface PageSwitchListener {
         void onPageSwitch(View newPage, int newPageIndex);
@@ -290,6 +232,7 @@
         a.recycle();
 
         setHapticFeedbackEnabled(false);
+        mIsRtl = Utilities.isRtl(getResources());
         init();
     }
 
@@ -297,8 +240,6 @@
      * Initializes various states for this workspace.
      */
     protected void init() {
-        mDirtyPageContent = new ArrayList<Boolean>();
-        mDirtyPageContent.ensureCapacity(32);
         mScroller = new LauncherScroller(getContext());
         setDefaultInterpolator(new ScrollInterpolator());
         mCurrentPage = 0;
@@ -306,18 +247,19 @@
 
         final ViewConfiguration configuration = ViewConfiguration.get(getContext());
         mTouchSlop = configuration.getScaledPagingTouchSlop();
-        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mDensity = getResources().getDisplayMetrics().density;
 
-        // Scale the fling-to-delete threshold by the density
-        mFlingToDeleteThresholdVelocity =
-                (int) (mFlingToDeleteThresholdVelocity * mDensity);
-
         mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
         mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * mDensity);
         mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * mDensity);
         setOnHierarchyChangeListener(this);
+        setWillNotDraw(false);
+    }
+
+    protected void setEdgeGlowColor(int color) {
+        mEdgeGlowLeft.setColor(color);
+        mEdgeGlowRight.setColor(color);
     }
 
     protected void setDefaultInterpolator(Interpolator interpolator) {
@@ -333,7 +275,7 @@
         ViewGroup grandParent = (ViewGroup) parent.getParent();
         if (mPageIndicator == null && mPageIndicatorViewId > -1) {
             mPageIndicator = (PageIndicator) grandParent.findViewById(mPageIndicatorViewId);
-            mPageIndicator.removeAllMarkers(mAllowPagedViewAnimations);
+            mPageIndicator.removeAllMarkers(true);
 
             ArrayList<PageIndicator.PageMarkerResources> markers =
                     new ArrayList<PageIndicator.PageMarkerResources>();
@@ -341,7 +283,7 @@
                 markers.add(getPageIndicatorMarker(i));
             }
 
-            mPageIndicator.addMarkers(markers, mAllowPagedViewAnimations);
+            mPageIndicator.addMarkers(markers, true);
 
             OnClickListener listener = getPageIndicatorClickListener();
             if (listener != null) {
@@ -359,33 +301,31 @@
         return null;
     }
 
+    @Override
     protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
         // Unhook the page indicator
         mPageIndicator = null;
     }
 
-    void setDeleteDropTarget(View v) {
-        mDeleteDropTarget = v;
-    }
-
     // Convenience methods to map points from self to parent and vice versa
-    float[] mapPointFromViewToParent(View v, float x, float y) {
-        mTmpPoint[0] = x;
-        mTmpPoint[1] = y;
-        v.getMatrix().mapPoints(mTmpPoint);
-        mTmpPoint[0] += v.getLeft();
-        mTmpPoint[1] += v.getTop();
-        return mTmpPoint;
+    private float[] mapPointFromViewToParent(View v, float x, float y) {
+        sTmpPoint[0] = x;
+        sTmpPoint[1] = y;
+        v.getMatrix().mapPoints(sTmpPoint);
+        sTmpPoint[0] += v.getLeft();
+        sTmpPoint[1] += v.getTop();
+        return sTmpPoint;
     }
-    float[] mapPointFromParentToView(View v, float x, float y) {
-        mTmpPoint[0] = x - v.getLeft();
-        mTmpPoint[1] = y - v.getTop();
-        v.getMatrix().invert(mTmpInvMatrix);
-        mTmpInvMatrix.mapPoints(mTmpPoint);
-        return mTmpPoint;
+    private float[] mapPointFromParentToView(View v, float x, float y) {
+        sTmpPoint[0] = x - v.getLeft();
+        sTmpPoint[1] = y - v.getTop();
+        v.getMatrix().invert(sTmpInvMatrix);
+        sTmpInvMatrix.mapPoints(sTmpPoint);
+        return sTmpPoint;
     }
 
-    void updateDragViewTranslationDuringDrag() {
+    private void updateDragViewTranslationDuringDrag() {
         if (mDragView != null) {
             float x = (mLastMotionX - mDownMotionX) + (getScrollX() - mDownScrollX) +
                     (mDragViewBaselineLeft - mDragView.getLeft());
@@ -453,33 +393,15 @@
     }
 
     /**
-     * Note: this is a reimplementation of View.isLayoutRtl() since that is currently hidden api.
-     */
-    public boolean isLayoutRtl() {
-        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
-    }
-
-    /**
-     * Called by subclasses to mark that data is ready, and that we can begin loading and laying
-     * out pages.
-     */
-    protected void setDataIsReady() {
-        mIsDataReady = true;
-    }
-
-    protected boolean isDataReady() {
-        return mIsDataReady;
-    }
-
-    /**
      * Returns the index of the currently displayed page.
-     *
-     * @return The index of the currently displayed page.
      */
-    int getCurrentPage() {
+    public int getCurrentPage() {
         return mCurrentPage;
     }
 
+    /**
+     * Returns the index of page to be shown immediately afterwards.
+     */
     int getNextPage() {
         return (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
     }
@@ -488,7 +410,7 @@
         return getChildCount();
     }
 
-    View getPageAt(int index) {
+    public View getPageAt(int index) {
         return getChildAt(index);
     }
 
@@ -512,17 +434,6 @@
         forceFinishScroller();
     }
 
-    /**
-     * Called during AllApps/Home transitions to avoid unnecessary work. When that other animation
-     * {@link #updateCurrentPageScroll()} should be called, to correctly set the final state and
-     * re-enable scrolling.
-     */
-    void stopScrolling() {
-        mCurrentPage = getNextPage();
-        notifyPageSwitchListener();
-        forceFinishScroller();
-    }
-
     private void abortScrollerAnimation(boolean resetNextPage) {
         mScroller.abortAnimation();
         // We need to clean up the next page here to avoid computeScrollHelper from
@@ -555,7 +466,7 @@
     /**
      * Sets the current page.
      */
-    void setCurrentPage(int currentPage) {
+    public void setCurrentPage(int currentPage) {
         if (!mScroller.isFinished()) {
             abortScrollerAnimation(true);
         }
@@ -647,37 +558,41 @@
 
     @Override
     public void scrollBy(int x, int y) {
-        scrollTo(mUnboundedScrollX + x, getScrollY() + y);
+        scrollTo(getScrollX() + x, getScrollY() + y);
     }
 
     @Override
     public void scrollTo(int x, int y) {
         // In free scroll mode, we clamp the scrollX
         if (mFreeScroll) {
+            // If the scroller is trying to move to a location beyond the maximum allowed
+            // in the free scroll mode, we make sure to end the scroll operation.
+            if (!mScroller.isFinished() &&
+                    (x > mFreeScrollMaxScrollX || x < mFreeScrollMinScrollX)) {
+                forceFinishScroller();
+            }
+
             x = Math.min(x, mFreeScrollMaxScrollX);
             x = Math.max(x, mFreeScrollMinScrollX);
         }
 
-        final boolean isRtl = isLayoutRtl();
-        mUnboundedScrollX = x;
-
-        boolean isXBeforeFirstPage = isRtl ? (x > mMaxScrollX) : (x < 0);
-        boolean isXAfterLastPage = isRtl ? (x < 0) : (x > mMaxScrollX);
+        boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
+        boolean isXAfterLastPage = mIsRtl ? (x < 0) : (x > mMaxScrollX);
         if (isXBeforeFirstPage) {
-            super.scrollTo(0, y);
+            super.scrollTo(mIsRtl ? mMaxScrollX : 0, y);
             if (mAllowOverScroll) {
                 mWasInOverscroll = true;
-                if (isRtl) {
+                if (mIsRtl) {
                     overScroll(x - mMaxScrollX);
                 } else {
                     overScroll(x);
                 }
             }
         } else if (isXAfterLastPage) {
-            super.scrollTo(mMaxScrollX, y);
+            super.scrollTo(mIsRtl ? 0 : mMaxScrollX, y);
             if (mAllowOverScroll) {
                 mWasInOverscroll = true;
-                if (isRtl) {
+                if (mIsRtl) {
                     overScroll(x);
                 } else {
                     overScroll(x - mMaxScrollX);
@@ -688,7 +603,6 @@
                 overScroll(0);
                 mWasInOverscroll = false;
             }
-            mOverScrollX = x;
             super.scrollTo(x, y);
         }
 
@@ -708,21 +622,17 @@
         AccessibilityManager am =
                 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
         if (am.isEnabled()) {
-            AccessibilityEvent ev =
-                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
-            ev.setItemCount(getChildCount());
-            ev.setFromIndex(mCurrentPage);
-            ev.setToIndex(getNextPage());
+            if (mCurrentPage != getNextPage()) {
+                AccessibilityEvent ev =
+                        AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+                ev.setScrollable(true);
+                ev.setScrollX(getScrollX());
+                ev.setScrollY(getScrollY());
+                ev.setMaxScrollX(mMaxScrollX);
+                ev.setMaxScrollY(0);
 
-            final int action;
-            if (getNextPage() >= mCurrentPage) {
-                action = AccessibilityNodeInfo.ACTION_SCROLL_FORWARD;
-            } else {
-                action = AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD;
+                sendAccessibilityEventUnchecked(ev);
             }
-
-            ev.setAction(action);
-            sendAccessibilityEventUnchecked(ev);
         }
     }
 
@@ -731,8 +641,7 @@
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
             if (getScrollX() != mScroller.getCurrX()
-                || getScrollY() != mScroller.getCurrY()
-                || mOverScrollX != mScroller.getCurrX()) {
+                || getScrollY() != mScroller.getCurrY()) {
                 float scaleX = mFreeScroll ? getScaleX() : 1f;
                 int scrollX = (int) (mScroller.getCurrX() * (1 / scaleX));
                 scrollTo(scrollX, mScroller.getCurrY());
@@ -746,12 +655,6 @@
             mNextPage = INVALID_PAGE;
             notifyPageSwitchListener();
 
-            // Load the associated pages if necessary
-            if (mDeferLoadAssociatedPagesUntilScrollCompletes) {
-                loadAssociatedPages(mCurrentPage);
-                mDeferLoadAssociatedPagesUntilScrollCompletes = false;
-            }
-
             // We don't want to trigger a page end moving unless the page has settled
             // and the user has stopped scrolling
             if (mTouchState == TOUCH_STATE_REST) {
@@ -775,10 +678,6 @@
         computeScrollHelper();
     }
 
-    protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
-        return mTopAlignPageWhenShrinkingForBouncer;
-    }
-
     public static class LayoutParams extends ViewGroup.LayoutParams {
         public boolean isFullScreenPage = false;
 
@@ -789,15 +688,35 @@
             super(width, height);
         }
 
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
         public LayoutParams(ViewGroup.LayoutParams source) {
             super(source);
         }
     }
 
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
     protected LayoutParams generateDefaultLayoutParams() {
         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     }
 
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new LayoutParams(p);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams;
+    }
+
     public void addFullScreenPage(View page) {
         LayoutParams lp = generateDefaultLayoutParams();
         lp.isFullScreenPage = true;
@@ -810,7 +729,7 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (!mIsDataReady || getChildCount() == 0) {
+        if (getChildCount() == 0) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
             return;
         }
@@ -914,27 +833,12 @@
                 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
             }
         }
-        if (mSpacePagesAutomatically) {
-            int spacing = (getViewportWidth() - mInsets.left - mInsets.right
-                    - referenceChildWidth) / 2;
-            if (spacing >= 0) {
-                setPageSpacing(spacing);
-            }
-            mSpacePagesAutomatically = false;
-        }
         setMeasuredDimension(scaledWidthSize, scaledHeightSize);
     }
 
-    /**
-     * This method should be called once before first layout / measure pass.
-     */
-    protected void setSinglePageInViewport() {
-        mSpacePagesAutomatically = true;
-    }
-
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (!mIsDataReady || getChildCount() == 0) {
+        if (getChildCount() == 0) {
             return;
         }
 
@@ -945,13 +849,11 @@
         int offsetY = getViewportOffsetY();
 
         // Update the viewport offsets
-        mViewport.offset(offsetX,  offsetY);
+        mViewport.offset(offsetX, offsetY);
 
-        final boolean isRtl = isLayoutRtl();
-
-        final int startIndex = isRtl ? childCount - 1 : 0;
-        final int endIndex = isRtl ? -1 : childCount;
-        final int delta = isRtl ? -1 : 1;
+        final int startIndex = mIsRtl ? childCount - 1 : 0;
+        final int endIndex = mIsRtl ? -1 : childCount;
+        final int delta = mIsRtl ? -1 : 1;
 
         int verticalPadding = getPaddingTop() + getPaddingBottom();
 
@@ -959,8 +861,8 @@
         LayoutParams nextLp;
 
         int childLeft = offsetX + (lp.isFullScreenPage ? 0 : getPaddingLeft());
-        if (mPageScrolls == null || getChildCount() != mChildCountOnLastLayout) {
-            mPageScrolls = new int[getChildCount()];
+        if (mPageScrolls == null || childCount != mChildCountOnLastLayout) {
+            mPageScrolls = new int[childCount];
         }
 
         for (int i = startIndex; i != endIndex; i += delta) {
@@ -1003,24 +905,40 @@
                     pageGap = getPaddingRight();
                 }
 
-                childLeft += childWidth + pageGap;
+                childLeft += childWidth + pageGap + getChildGap();
             }
         }
 
-        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+        final LayoutTransition transition = getLayoutTransition();
+        // If the transition is running defer updating max scroll, as some empty pages could
+        // still be present, and a max scroll change could cause sudden jumps in scroll.
+        if (transition != null && transition.isRunning()) {
+            transition.addTransitionListener(new LayoutTransition.TransitionListener() {
+
+                @Override
+                public void startTransition(LayoutTransition transition, ViewGroup container,
+                        View view, int transitionType) { }
+
+                @Override
+                public void endTransition(LayoutTransition transition, ViewGroup container,
+                        View view, int transitionType) {
+                    // Wait until all transitions are complete.
+                    if (!transition.isRunning()) {
+                        transition.removeTransitionListener(this);
+                        updateMaxScrollX();
+                    }
+                }
+            });
+        } else {
+            updateMaxScrollX();
+        }
+
+        if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < childCount) {
             updateCurrentPageScroll();
             mFirstLayout = false;
         }
 
-        if (childCount > 0) {
-            final int index = isLayoutRtl() ? 0 : childCount - 1;
-            mMaxScrollX = getScrollForPage(index);
-        } else {
-            mMaxScrollX = 0;
-        }
-
-        if (mScroller.isFinished() && mChildCountOnLastLayout != getChildCount() &&
-                !mDeferringForDelete) {
+        if (mScroller.isFinished() && mChildCountOnLastLayout != childCount) {
             if (mRestorePage != INVALID_RESTORE_PAGE) {
                 setCurrentPage(mRestorePage);
                 mRestorePage = INVALID_RESTORE_PAGE;
@@ -1028,41 +946,36 @@
                 setCurrentPage(getNextPage());
             }
         }
-        mChildCountOnLastLayout = getChildCount();
+        mChildCountOnLastLayout = childCount;
 
         if (isReordering(true)) {
             updateDragViewTranslationDuringDrag();
         }
     }
 
+    protected int getChildGap() {
+        return 0;
+    }
+
+    @Thunk void updateMaxScrollX() {
+        int childCount = getChildCount();
+        if (childCount > 0) {
+            final int index = mIsRtl ? 0 : childCount - 1;
+            mMaxScrollX = getScrollForPage(index);
+        } else {
+            mMaxScrollX = 0;
+        }
+    }
+
     public void setPageSpacing(int pageSpacing) {
         mPageSpacing = pageSpacing;
         requestLayout();
     }
 
-    protected void screenScrolled(int screenCenter) {
-        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
-
-        if (mFadeInAdjacentScreens && !isInOverscroll) {
-            for (int i = 0; i < getChildCount(); i++) {
-                View child = getChildAt(i);
-                if (child != null) {
-                    float scrollProgress = getScrollProgress(screenCenter, child, i);
-                    float alpha = 1 - Math.abs(scrollProgress);
-                    child.setAlpha(alpha);
-                }
-            }
-            invalidate();
-        }
-    }
-
-    protected void enablePagedViewAnimations() {
-        mAllowPagedViewAnimations = true;
-
-    }
-    protected void disablePagedViewAnimations() {
-        mAllowPagedViewAnimations = false;
-    }
+    /**
+     * Called when the center screen changes during scrolling.
+     */
+    protected void screenScrolled(int screenCenter) { }
 
     @Override
     public void onChildViewAdded(View parent, View child) {
@@ -1072,7 +985,7 @@
             int pageIndex = indexOfChild(child);
             mPageIndicator.addMarker(pageIndex,
                     getPageIndicatorMarker(pageIndex),
-                    mAllowPagedViewAnimations);
+                    true);
         }
 
         // This ensures that when children are added, they get the correct transforms / alphas
@@ -1093,7 +1006,7 @@
         // Update the page indicator, we don't update the page indicator as we
         // add/remove pages
         if (mPageIndicator != null && !isReordering(false)) {
-            mPageIndicator.removeMarker(index, mAllowPagedViewAnimations);
+            mPageIndicator.removeMarker(index, true);
         }
     }
 
@@ -1115,7 +1028,7 @@
     public void removeViewAt(int index) {
         // XXX: We should find a better way to hook into this before the view
         // gets removed form its parent...
-        removeViewAt(index);
+        removeMarkerForView(index);
         super.removeViewAt(index);
     }
     @Override
@@ -1123,7 +1036,7 @@
         // Update the page indicator, we don't update the page indicator as we
         // add/remove pages
         if (mPageIndicator != null) {
-            mPageIndicator.removeAllMarkers(mAllowPagedViewAnimations);
+            mPageIndicator.removeAllMarkers(true);
         }
 
         super.removeAllViewsInLayout();
@@ -1144,7 +1057,7 @@
 
     protected void getVisiblePages(int[] range) {
         final int pageCount = getChildCount();
-        mTmpIntPoint[0] = mTmpIntPoint[1] = 0;
+        sTmpIntPoint[0] = sTmpIntPoint[1] = 0;
 
         range[0] = -1;
         range[1] = -1;
@@ -1157,9 +1070,9 @@
             for (int i = 0; i < count; i++) {
                 View currPage = getPageAt(i);
 
-                mTmpIntPoint[0] = 0;
-                Utilities.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false);
-                if (mTmpIntPoint[0] > viewportWidth) {
+                sTmpIntPoint[0] = 0;
+                Utilities.getDescendantCoordRelativeToParent(currPage, this, sTmpIntPoint, false);
+                if (sTmpIntPoint[0] > viewportWidth) {
                     if (range[0] == -1) {
                         continue;
                     } else {
@@ -1167,9 +1080,9 @@
                     }
                 }
 
-                mTmpIntPoint[0] = currPage.getMeasuredWidth();
-                Utilities.getDescendantCoordRelativeToParent(currPage, this, mTmpIntPoint, false);
-                if (mTmpIntPoint[0] < 0) {
+                sTmpIntPoint[0] = currPage.getMeasuredWidth();
+                Utilities.getDescendantCoordRelativeToParent(currPage, this, sTmpIntPoint, false);
+                if (sTmpIntPoint[0] < 0) {
                     if (range[0] == -1) {
                         continue;
                     } else {
@@ -1199,9 +1112,7 @@
         final int pageCount = getChildCount();
         if (pageCount > 0) {
             int halfScreenSize = getViewportWidth() / 2;
-            // mOverScrollX is equal to getScrollX() when we're within the normal scroll range.
-            // Otherwise it is equal to the scaled overscroll position.
-            int screenCenter = mOverScrollX + halfScreenSize;
+            int screenCenter = getScrollX() + halfScreenSize;
 
             if (screenCenter != mLastScreenCenter || mForceScreenScrolled) {
                 // set mForceScreenScrolled before calling screenScrolled so that screenScrolled can
@@ -1242,6 +1153,46 @@
     }
 
     @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        if (getPageCount() > 0) {
+            if (!mEdgeGlowLeft.isFinished()) {
+                final int restoreCount = canvas.save();
+                Rect display = mViewport;
+                canvas.translate(display.left, display.top);
+                canvas.rotate(270);
+
+                getEdgeVerticalPostion(sTmpIntPoint);
+                canvas.translate(display.top - sTmpIntPoint[1], 0);
+                mEdgeGlowLeft.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
+                if (mEdgeGlowLeft.draw(canvas)) {
+                    postInvalidateOnAnimation();
+                }
+                canvas.restoreToCount(restoreCount);
+            }
+            if (!mEdgeGlowRight.isFinished()) {
+                final int restoreCount = canvas.save();
+                Rect display = mViewport;
+                canvas.translate(display.left + mPageScrolls[mIsRtl ? 0 : (getPageCount() - 1)], display.top);
+                canvas.rotate(90);
+
+                getEdgeVerticalPostion(sTmpIntPoint);
+                canvas.translate(sTmpIntPoint[0] - display.top, -display.width());
+                mEdgeGlowRight.setSize(sTmpIntPoint[1] - sTmpIntPoint[0], display.width());
+                if (mEdgeGlowRight.draw(canvas)) {
+                    postInvalidateOnAnimation();
+                }
+                canvas.restoreToCount(restoreCount);
+            }
+        }
+    }
+
+    /**
+     * Returns the top and bottom position for the edge effect.
+     */
+    protected abstract void getEdgeVerticalPostion(int[] pos);
+
+    @Override
     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
         int page = indexToPage(indexOfChild(child));
         if (page != mCurrentPage || !mScroller.isFinished()) {
@@ -1346,7 +1297,7 @@
      * Return true if a tap at (x, y) should trigger a flip to the previous page.
      */
     protected boolean hitsPreviousPage(float x, float y) {
-        if (isLayoutRtl()) {
+        if (mIsRtl) {
             return (x > (getViewportOffsetX() + getViewportWidth() -
                     getPaddingRight() - mPageSpacing));
         }
@@ -1357,7 +1308,7 @@
      * Return true if a tap at (x, y) should trigger a flip to the next page.
      */
     protected boolean hitsNextPage(float x, float y) {
-        if (isLayoutRtl()) {
+        if (mIsRtl) {
             return (x < getViewportOffsetX() + getPaddingLeft() + mPageSpacing);
         }
         return  (x > (getViewportOffsetX() + getViewportWidth() -
@@ -1366,17 +1317,13 @@
 
     /** Returns whether x and y originated within the buffered viewport */
     private boolean isTouchPointInViewportWithBuffer(int x, int y) {
-        mTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
+        sTmpRect.set(mViewport.left - mViewport.width() / 2, mViewport.top,
                 mViewport.right + mViewport.width() / 2, mViewport.bottom);
-        return mTmpRect.contains(x, y);
+        return sTmpRect.contains(x, y);
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
         /*
          * This method JUST determines whether we want to intercept the motion.
          * If we return true, onTouchEvent will be called and we do the actual
@@ -1453,19 +1400,6 @@
                     }
                 }
 
-                // check if this can be the beginning of a tap on the side of the pages
-                // to scroll the current page
-                if (!DISABLE_TOUCH_SIDE_PAGES) {
-                    if (mTouchState != TOUCH_STATE_PREV_PAGE && mTouchState != TOUCH_STATE_NEXT_PAGE) {
-                        if (getChildCount() > 0) {
-                            if (hitsPreviousPage(x, y)) {
-                                mTouchState = TOUCH_STATE_PREV_PAGE;
-                            } else if (hitsNextPage(x, y)) {
-                                mTouchState = TOUCH_STATE_NEXT_PAGE;
-                            }
-                        }
-                    }
-                }
                 break;
             }
 
@@ -1506,54 +1440,33 @@
         if (!isTouchPointInViewportWithBuffer((int) x, (int) y)) return;
 
         final int xDiff = (int) Math.abs(x - mLastMotionX);
-        final int yDiff = (int) Math.abs(y - mLastMotionY);
 
         final int touchSlop = Math.round(touchSlopScale * mTouchSlop);
-        boolean xPaged = xDiff > mPagingTouchSlop;
         boolean xMoved = xDiff > touchSlop;
-        boolean yMoved = yDiff > touchSlop;
 
-        if (xMoved || xPaged || yMoved) {
-            if (mUsePagingTouchSlop ? xPaged : xMoved) {
-                // Scroll if the user moved far enough along the X axis
-                mTouchState = TOUCH_STATE_SCROLLING;
-                mTotalMotionX += Math.abs(mLastMotionX - x);
-                mLastMotionX = x;
-                mLastMotionXRemainder = 0;
-                mTouchX = getViewportOffsetX() + getScrollX();
-                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-                onScrollInteractionBegin();
-                pageBeginMoving();
-            }
+        if (xMoved) {
+            // Scroll if the user moved far enough along the X axis
+            mTouchState = TOUCH_STATE_SCROLLING;
+            mTotalMotionX += Math.abs(mLastMotionX - x);
+            mLastMotionX = x;
+            mLastMotionXRemainder = 0;
+            mTouchX = getViewportOffsetX() + getScrollX();
+            mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
+            onScrollInteractionBegin();
+            pageBeginMoving();
         }
     }
 
-    protected float getMaxScrollProgress() {
-        return 1.0f;
-    }
-
     protected void cancelCurrentPageLongPress() {
-        if (mAllowLongPress) {
-            //mAllowLongPress = false;
-            // Try canceling the long press. It could also have been scheduled
-            // by a distant descendant, so use the mAllowLongPress flag to block
-            // everything
-            final View currentPage = getPageAt(mCurrentPage);
-            if (currentPage != null) {
-                currentPage.cancelLongPress();
-            }
+        // Try canceling the long press. It could also have been scheduled
+        // by a distant descendant, so use the mAllowLongPress flag to block
+        // everything
+        final View currentPage = getPageAt(mCurrentPage);
+        if (currentPage != null) {
+            currentPage.cancelLongPress();
         }
     }
 
-    protected float getBoundedScrollProgress(int screenCenter, View v, int page) {
-        final int halfScreenSize = getViewportWidth() / 2;
-
-        screenCenter = Math.min(getScrollX() + halfScreenSize, screenCenter);
-        screenCenter = Math.max(halfScreenSize,  screenCenter);
-
-        return getScrollProgress(screenCenter, v, page);
-    }
-
     protected float getScrollProgress(int screenCenter, View v, int page) {
         final int halfScreenSize = getViewportWidth() / 2;
 
@@ -1563,7 +1476,7 @@
         final int totalDistance;
 
         int adjacentPage = page + 1;
-        if ((delta < 0 && !isLayoutRtl()) || (delta > 0 && isLayoutRtl())) {
+        if ((delta < 0 && !mIsRtl) || (delta > 0 && mIsRtl)) {
             adjacentPage = page - 1;
         }
 
@@ -1574,8 +1487,8 @@
         }
 
         float scrollProgress = delta / (totalDistance * 1.0f);
-        scrollProgress = Math.min(scrollProgress, getMaxScrollProgress());
-        scrollProgress = Math.max(scrollProgress, - getMaxScrollProgress());
+        scrollProgress = Math.min(scrollProgress, MAX_SCROLL_PROGRESS);
+        scrollProgress = Math.max(scrollProgress, - MAX_SCROLL_PROGRESS);
         return scrollProgress;
     }
 
@@ -1598,7 +1511,7 @@
             int scrollOffset = 0;
             LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (!lp.isFullScreenPage) {
-                scrollOffset = isLayoutRtl() ? getPaddingRight() : getPaddingLeft();
+                scrollOffset = mIsRtl ? getPaddingRight() : getPaddingLeft();
             }
 
             int baselineX = mPageScrolls[index] + scrollOffset + getViewportOffsetX();
@@ -1606,49 +1519,15 @@
         }
     }
 
-    // This curve determines how the effect of scrolling over the limits of the page dimishes
-    // as the user pulls further and further from the bounds
-    private float overScrollInfluenceCurve(float f) {
-        f -= 1.0f;
-        return f * f * f + 1.0f;
-    }
-
-    protected float acceleratedOverFactor(float amount) {
-        int screenSize = getViewportWidth();
-
-        // We want to reach the max over scroll effect when the user has
-        // over scrolled half the size of the screen
-        float f = OVERSCROLL_ACCELERATE_FACTOR * (amount / screenSize);
-
-        if (f == 0) return 0;
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-        return f;
-    }
-
     protected void dampedOverScroll(float amount) {
         int screenSize = getViewportWidth();
-
         float f = (amount / screenSize);
-
-        if (f == 0) return;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-
-        // Clamp this factor, f, to -1 < f < 1
-        if (Math.abs(f) >= 1) {
-            f /= Math.abs(f);
-        }
-
-        int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
-        if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(mOverScrollX, getScrollY());
+        if (f < 0) {
+            mEdgeGlowLeft.onPull(-f);
+        } else if (f > 0) {
+            mEdgeGlowRight.onPull(f);
         } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mOverScrollX, getScrollY());
+            return;
         }
         invalidate();
     }
@@ -1657,25 +1536,17 @@
         dampedOverScroll(amount);
     }
 
-    protected float maxOverScroll() {
-        // Using the formula in overScroll, assuming that f = 1.0 (which it should generally not
-        // exceed). Used to find out how much extra wallpaper we need for the over scroll effect
-        float f = 1.0f;
-        f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
-        return OVERSCROLL_DAMP_FACTOR * f;
-    }
-
-    protected void enableFreeScroll() {
+    public void enableFreeScroll() {
         setEnableFreeScroll(true);
     }
 
-    protected void disableFreeScroll() {
+    public void disableFreeScroll() {
         setEnableFreeScroll(false);
     }
 
     void updateFreescrollBounds() {
         getFreeScrollPageRange(mTempVisiblePagesRange);
-        if (isLayoutRtl()) {
+        if (mIsRtl) {
             mFreeScrollMinScrollX = getScrollForPage(mTempVisiblePagesRange[1]);
             mFreeScrollMaxScrollX = getScrollForPage(mTempVisiblePagesRange[0]);
         } else {
@@ -1700,11 +1571,11 @@
         setEnableOverscroll(!freeScroll);
     }
 
-    private void setEnableOverscroll(boolean enable) {
+    protected void setEnableOverscroll(boolean enable) {
         mAllowOverScroll = enable;
     }
 
-    int getNearestHoverOverPageIndex() {
+    private int getNearestHoverOverPageIndex() {
         if (mDragView != null) {
             int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2)
                     + mDragView.getTranslationX());
@@ -1727,10 +1598,6 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (DISABLE_TOUCH_INTERACTION) {
-            return false;
-        }
-
         super.onTouchEvent(ev);
 
         // Skip touch handling if there are no pages to swipe
@@ -1785,12 +1652,7 @@
                 if (Math.abs(deltaX) >= 1.0f) {
                     mTouchX += deltaX;
                     mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
-                    if (!mDeferScrollUpdate) {
-                        scrollBy((int) deltaX, 0);
-                        if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
-                    } else {
-                        invalidate();
-                    }
+                    scrollBy((int) deltaX, 0);
                     mLastMotionX = x;
                     mLastMotionXRemainder = deltaX - (int) deltaX;
                 } else {
@@ -1811,19 +1673,13 @@
                 // Find the closest page to the touch point
                 final int dragViewIndex = indexOfChild(mDragView);
 
-                // Change the drag view if we are hovering over the drop target
-                boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget(
-                        (int) mParentDownMotionX, (int) mParentDownMotionY);
-                setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);
-
                 if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX);
                 if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY);
                 if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
                 if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);
 
                 final int pageUnderPointIndex = getNearestHoverOverPageIndex();
-                if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView) &&
-                        !isHoveringOverDelete) {
+                if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)) {
                     mTempVisiblePagesRange[0] = 0;
                     mTempVisiblePagesRange[1] = getPageCount() - 1;
                     getFreeScrollPageRange(mTempVisiblePagesRange);
@@ -1870,9 +1726,7 @@
                                 }
 
                                 removeView(mDragView);
-                                onRemoveView(mDragView, false);
                                 addView(mDragView, pageUnderPointIndex);
-                                onAddView(mDragView, pageUnderPointIndex);
                                 mSidePageHoverIndex = -1;
                                 if (mPageIndicator != null) {
                                     mPageIndicator.setActiveMarker(getNextPage());
@@ -1922,9 +1776,8 @@
                     // We give flings precedence over large moves, which is why we short-circuit our
                     // test for a large move if a fling has been registered. That is, a large
                     // move to the left and fling to the right will register as a fling to the right.
-                    final boolean isRtl = isLayoutRtl();
-                    boolean isDeltaXLeft = isRtl ? deltaX > 0 : deltaX < 0;
-                    boolean isVelocityXLeft = isRtl ? velocityX > 0 : velocityX < 0;
+                    boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
+                    boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
                     if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
                             (isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
                         finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
@@ -1983,19 +1836,6 @@
                 mParentDownMotionX = pt[0];
                 mParentDownMotionY = pt[1];
                 updateDragViewTranslationDuringDrag();
-                boolean handledFling = false;
-                if (!DISABLE_FLING_TO_DELETE) {
-                    // Check the velocity and see if we are flinging-to-delete
-                    PointF flingToDeleteVector = isFlingingToDelete();
-                    if (flingToDeleteVector != null) {
-                        onFlingToDelete(flingToDeleteVector);
-                        handledFling = true;
-                    }
-                }
-                if (!handledFling && isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
-                        (int) mParentDownMotionY)) {
-                    onDropToDelete();
-                }
             } else {
                 if (!mCancelTap) {
                     onUnhandledTap(ev);
@@ -2024,17 +1864,14 @@
         return true;
     }
 
-    public void onFlingToDelete(View v) {}
-    public void onRemoveView(View v, boolean deletePermanently) {}
-    public void onRemoveViewAnimationCompleted() {}
-    public void onAddView(View v, int index) {}
-
     private void resetTouchState() {
         releaseVelocityTracker();
         endReordering();
         mCancelTap = false;
         mTouchState = TOUCH_STATE_REST;
         mActivePointerId = INVALID_POINTER;
+        mEdgeGlowLeft.onRelease();
+        mEdgeGlowRight.onRelease();
     }
 
     /**
@@ -2066,7 +1903,7 @@
                         hscroll = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
                     }
                     if (hscroll != 0 || vscroll != 0) {
-                        boolean isForwardScroll = isLayoutRtl() ? (hscroll < 0 || vscroll < 0)
+                        boolean isForwardScroll = mIsRtl ? (hscroll < 0 || vscroll < 0)
                                                          : (hscroll > 0 || vscroll > 0);
                         if (isForwardScroll) {
                             scrollRight();
@@ -2124,22 +1961,6 @@
         }
     }
 
-    protected int getChildWidth(int index) {
-        return getPageAt(index).getMeasuredWidth();
-    }
-
-    int getPageNearestToPoint(float x) {
-        int index = 0;
-        for (int i = 0; i < getChildCount(); ++i) {
-            if (x < getChildAt(i).getRight() - getScrollX()) {
-                return index;
-            } else {
-                index++;
-            }
-        }
-        return Math.min(index, getChildCount() - 1);
-    }
-
     int getPageNearestToCenterOfScreen() {
         int minDistanceFromScreenCenter = Integer.MAX_VALUE;
         int minDistanceFromScreenCenterIndex = -1;
@@ -2159,20 +1980,8 @@
         return minDistanceFromScreenCenterIndex;
     }
 
-    protected boolean isInOverScroll() {
-        return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
-    }
-
-    protected int getPageSnapDuration() {
-        if (isInOverScroll()) {
-            return OVER_SCROLL_PAGE_SNAP_ANIMATION_DURATION;
-        }
-        return PAGE_SNAP_ANIMATION_DURATION;
-
-    }
-
     protected void snapToDestination() {
-        snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
+        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
     }
 
     private static class ScrollInterpolator implements Interpolator {
@@ -2189,7 +1998,7 @@
     // the screen has to travel, however, we don't want this duration to be effected in a
     // purely linear fashion. Instead, we use this method to moderate the effect that the distance
     // of travel has on the overall snap duration.
-    float distanceInfluenceForSnapDuration(float f) {
+    private float distanceInfluenceForSnapDuration(float f) {
         f -= 0.5f; // center the values about 0.
         f *= 0.3f * Math.PI / 2.0f;
         return (float) Math.sin(f);
@@ -2200,13 +2009,13 @@
         int halfScreenSize = getViewportWidth() / 2;
 
         final int newX = getScrollForPage(whichPage);
-        int delta = newX - mUnboundedScrollX;
+        int delta = newX - getScrollX();
         int duration = 0;
 
-        if (Math.abs(velocity) < mMinFlingVelocity || isInOverScroll()) {
+        if (Math.abs(velocity) < mMinFlingVelocity) {
             // If the velocity is low enough, then treat this more as an automatic page advance
             // as opposed to an apparent physical response to flinging
-            snapToPage(whichPage, getPageSnapDuration());
+            snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
             return;
         }
 
@@ -2229,12 +2038,12 @@
         snapToPage(whichPage, delta, duration);
     }
 
-    protected void snapToPage(int whichPage) {
-        snapToPage(whichPage, getPageSnapDuration());
+    public void snapToPage(int whichPage) {
+        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
     }
 
     protected void snapToPageImmediately(int whichPage) {
-        snapToPage(whichPage, getPageSnapDuration(), true, null);
+        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null);
     }
 
     protected void snapToPage(int whichPage, int duration) {
@@ -2250,8 +2059,7 @@
         whichPage = validateNewPage(whichPage);
 
         int newX = getScrollForPage(whichPage);
-        final int sX = mUnboundedScrollX;
-        final int delta = newX - sX;
+        final int delta = newX - getScrollX();
         snapToPage(whichPage, delta, duration, immediate, interpolator);
     }
 
@@ -2270,8 +2078,6 @@
             focusedChild.clearFocus();
         }
 
-        sendScrollAccessibilityEvent();
-
         pageBeginMoving();
         awakenScrollBars(duration);
         if (immediate) {
@@ -2290,7 +2096,7 @@
             mScroller.setInterpolator(mDefaultInterpolator);
         }
 
-        mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration);
+        mScroller.startScroll(getScrollX(), 0, delta, 0, duration);
 
         updatePageIndicator();
 
@@ -2299,9 +2105,6 @@
             computeScroll();
         }
 
-        // Defer loading associated pages until the scroll settles
-        mDeferLoadAssociatedPagesUntilScrollCompletes = true;
-
         mForceScreenScrolled = true;
         invalidate();
     }
@@ -2328,27 +2131,12 @@
         return result;
     }
 
-    /**
-     * @return True is long presses are still allowed for the current touch
-     */
-    public boolean allowLongPress() {
-        return mAllowLongPress;
-    }
-
     @Override
     public boolean performLongClick() {
         mCancelTap = true;
         return super.performLongClick();
     }
 
-    /**
-     * Set true to allow long-press events to be triggered, usually checked by
-     * {@link Launcher} to accept or block dpad-initiated long-presses.
-     */
-    public void setAllowLongPress(boolean allowLongPress) {
-        mAllowLongPress = allowLongPress;
-    }
-
     public static class SavedState extends BaseSavedState {
         int currentPage = -1;
 
@@ -2356,7 +2144,7 @@
             super(superState);
         }
 
-        private SavedState(Parcel in) {
+        @Thunk SavedState(Parcel in) {
             super(in);
             currentPage = in.readInt();
         }
@@ -2379,113 +2167,8 @@
         };
     }
 
-    protected void loadAssociatedPages(int page) {
-        loadAssociatedPages(page, false);
-    }
-    protected void loadAssociatedPages(int page, boolean immediateAndOnly) {
-        if (mContentIsRefreshable) {
-            final int count = getChildCount();
-            if (page < count) {
-                int lowerPageBound = getAssociatedLowerPageBound(page);
-                int upperPageBound = getAssociatedUpperPageBound(page);
-                if (DEBUG) Log.d(TAG, "loadAssociatedPages: " + lowerPageBound + "/"
-                        + upperPageBound);
-                // First, clear any pages that should no longer be loaded
-                for (int i = 0; i < count; ++i) {
-                    Page layout = (Page) getPageAt(i);
-                    if ((i < lowerPageBound) || (i > upperPageBound)) {
-                        if (layout.getPageChildCount() > 0) {
-                            layout.removeAllViewsOnPage();
-                        }
-                        mDirtyPageContent.set(i, true);
-                    }
-                }
-                // Next, load any new pages
-                for (int i = 0; i < count; ++i) {
-                    if ((i != page) && immediateAndOnly) {
-                        continue;
-                    }
-                    if (lowerPageBound <= i && i <= upperPageBound) {
-                        if (mDirtyPageContent.get(i)) {
-                            syncPageItems(i, (i == page) && immediateAndOnly);
-                            mDirtyPageContent.set(i, false);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    protected int getAssociatedLowerPageBound(int page) {
-        return Math.max(0, page - 1);
-    }
-    protected int getAssociatedUpperPageBound(int page) {
-        final int count = getChildCount();
-        return Math.min(page + 1, count - 1);
-    }
-
-    /**
-     * This method is called ONLY to synchronize the number of pages that the paged view has.
-     * To actually fill the pages with information, implement syncPageItems() below.  It is
-     * guaranteed that syncPageItems() will be called for a particular page before it is shown,
-     * and therefore, individual page items do not need to be updated in this method.
-     */
-    public abstract void syncPages();
-
-    /**
-     * This method is called to synchronize the items that are on a particular page.  If views on
-     * the page can be reused, then they should be updated within this method.
-     */
-    public abstract void syncPageItems(int page, boolean immediate);
-
-    protected void invalidatePageData() {
-        invalidatePageData(-1, false);
-    }
-    protected void invalidatePageData(int currentPage) {
-        invalidatePageData(currentPage, false);
-    }
-    protected void invalidatePageData(int currentPage, boolean immediateAndOnly) {
-        if (!mIsDataReady) {
-            return;
-        }
-
-        if (mContentIsRefreshable) {
-            // Force all scrolling-related behavior to end
-            forceFinishScroller();
-
-            // Update all the pages
-            syncPages();
-
-            // We must force a measure after we've loaded the pages to update the content width and
-            // to determine the full scroll width
-            measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
-
-            // Set a new page as the current page if necessary
-            if (currentPage > -1) {
-                setCurrentPage(Math.min(getPageCount() - 1, currentPage));
-            }
-
-            // Mark each of the pages as dirty
-            final int count = getChildCount();
-            mDirtyPageContent.clear();
-            for (int i = 0; i < count; ++i) {
-                mDirtyPageContent.add(true);
-            }
-
-            // Load any pages that are necessary for the current window of views
-            loadAssociatedPages(mCurrentPage, immediateAndOnly);
-            requestLayout();
-        }
-        if (isPageMoving()) {
-            // If the page is moving, then snap it to the final position to ensure we don't get
-            // stuck between pages
-            snapToDestination();
-        }
-    }
-
     // Animate the drag view back to the original position
-    void animateDragViewToOriginalPosition() {
+    private void animateDragViewToOriginalPosition() {
         if (mDragView != null) {
             AnimatorSet anim = new AnimatorSet();
             anim.setDuration(REORDERING_DROP_REPOSITION_DURATION);
@@ -2504,7 +2187,7 @@
         }
     }
 
-    protected void onStartReordering() {
+    public void onStartReordering() {
         // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.)
         mTouchState = TOUCH_STATE_REORDERING;
         mIsReordering = true;
@@ -2514,7 +2197,7 @@
         invalidate();
     }
 
-    private void onPostReorderingAnimationCompleted() {
+    @Thunk void onPostReorderingAnimationCompleted() {
         // Trigger the callback when reordering has settled
         --mPostReorderingPreZoomInRemainingAnimationCount;
         if (mPostReorderingPreZoomInRunnable != null &&
@@ -2524,7 +2207,7 @@
         }
     }
 
-    protected void onEndReordering() {
+    public void onEndReordering() {
         mIsReordering = false;
     }
 
@@ -2574,281 +2257,26 @@
                 onEndReordering();
             }
         };
-        if (!mDeferringForDelete) {
-            mPostReorderingPreZoomInRunnable = new Runnable() {
-                public void run() {
-                    onCompleteRunnable.run();
-                    enableFreeScroll();
-                };
+
+        mPostReorderingPreZoomInRunnable = new Runnable() {
+            public void run() {
+                onCompleteRunnable.run();
+                enableFreeScroll();
             };
+        };
 
-            mPostReorderingPreZoomInRemainingAnimationCount =
-                    NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
-            // Snap to the current page
-            snapToPage(indexOfChild(mDragView), 0);
-            // Animate the drag view back to the front position
-            animateDragViewToOriginalPosition();
-        } else {
-            // Handled in post-delete-animation-callbacks
-        }
+        mPostReorderingPreZoomInRemainingAnimationCount =
+                NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT;
+        // Snap to the current page
+        snapToPage(indexOfChild(mDragView), 0);
+        // Animate the drag view back to the front position
+        animateDragViewToOriginalPosition();
     }
 
-    /*
-     * Flinging to delete - IN PROGRESS
-     */
-    private PointF isFlingingToDelete() {
-        ViewConfiguration config = ViewConfiguration.get(getContext());
-        mVelocityTracker.computeCurrentVelocity(1000, config.getScaledMaximumFlingVelocity());
-
-        if (mVelocityTracker.getYVelocity() < mFlingToDeleteThresholdVelocity) {
-            // Do a quick dot product test to ensure that we are flinging upwards
-            PointF vel = new PointF(mVelocityTracker.getXVelocity(),
-                    mVelocityTracker.getYVelocity());
-            PointF upVec = new PointF(0f, -1f);
-            float theta = (float) Math.acos(((vel.x * upVec.x) + (vel.y * upVec.y)) /
-                    (vel.length() * upVec.length()));
-            if (theta <= Math.toRadians(FLING_TO_DELETE_MAX_FLING_DEGREES)) {
-                return vel;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Creates an animation from the current drag view along its current velocity vector.
-     * For this animation, the alpha runs for a fixed duration and we update the position
-     * progressively.
-     */
-    private static class FlingAlongVectorAnimatorUpdateListener implements AnimatorUpdateListener {
-        private View mDragView;
-        private PointF mVelocity;
-        private Rect mFrom;
-        private long mPrevTime;
-        private float mFriction;
-
-        private final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
-
-        public FlingAlongVectorAnimatorUpdateListener(View dragView, PointF vel, Rect from,
-                long startTime, float friction) {
-            mDragView = dragView;
-            mVelocity = vel;
-            mFrom = from;
-            mPrevTime = startTime;
-            mFriction = 1f - (mDragView.getResources().getDisplayMetrics().density * friction);
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            float t = ((Float) animation.getAnimatedValue()).floatValue();
-            long curTime = AnimationUtils.currentAnimationTimeMillis();
-
-            mFrom.left += (mVelocity.x * (curTime - mPrevTime) / 1000f);
-            mFrom.top += (mVelocity.y * (curTime - mPrevTime) / 1000f);
-
-            mDragView.setTranslationX(mFrom.left);
-            mDragView.setTranslationY(mFrom.top);
-            mDragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
-
-            mVelocity.x *= mFriction;
-            mVelocity.y *= mFriction;
-            mPrevTime = curTime;
-        }
-    };
-
     private static final int ANIM_TAG_KEY = 100;
 
-    private Runnable createPostDeleteAnimationRunnable(final View dragView) {
-        return new Runnable() {
-            @Override
-            public void run() {
-                int dragViewIndex = indexOfChild(dragView);
-
-                // For each of the pages around the drag view, animate them from the previous
-                // position to the new position in the layout (as a result of the drag view moving
-                // in the layout)
-                // NOTE: We can make an assumption here because we have side-bound pages that we
-                //       will always have pages to animate in from the left
-                getFreeScrollPageRange(mTempVisiblePagesRange);
-                boolean isLastWidgetPage = (mTempVisiblePagesRange[0] == mTempVisiblePagesRange[1]);
-                boolean slideFromLeft = (isLastWidgetPage ||
-                        dragViewIndex > mTempVisiblePagesRange[0]);
-
-                // Setup the scroll to the correct page before we swap the views
-                if (slideFromLeft) {
-                    snapToPageImmediately(dragViewIndex - 1);
-                }
-
-                int firstIndex = (isLastWidgetPage ? 0 : mTempVisiblePagesRange[0]);
-                int lastIndex = Math.min(mTempVisiblePagesRange[1], getPageCount() - 1);
-                int lowerIndex = (slideFromLeft ? firstIndex : dragViewIndex + 1 );
-                int upperIndex = (slideFromLeft ? dragViewIndex - 1 : lastIndex);
-                ArrayList<Animator> animations = new ArrayList<Animator>();
-                for (int i = lowerIndex; i <= upperIndex; ++i) {
-                    View v = getChildAt(i);
-                    // dragViewIndex < pageUnderPointIndex, so after we remove the
-                    // drag view all subsequent views to pageUnderPointIndex will
-                    // shift down.
-                    int oldX = 0;
-                    int newX = 0;
-                    if (slideFromLeft) {
-                        if (i == 0) {
-                            // Simulate the page being offscreen with the page spacing
-                            oldX = getViewportOffsetX() + getChildOffset(i) - getChildWidth(i)
-                                    - mPageSpacing;
-                        } else {
-                            oldX = getViewportOffsetX() + getChildOffset(i - 1);
-                        }
-                        newX = getViewportOffsetX() + getChildOffset(i);
-                    } else {
-                        oldX = getChildOffset(i) - getChildOffset(i - 1);
-                        newX = 0;
-                    }
-
-                    // Animate the view translation from its old position to its new
-                    // position
-                    AnimatorSet anim = (AnimatorSet) v.getTag();
-                    if (anim != null) {
-                        anim.cancel();
-                    }
-
-                    // Note: Hacky, but we want to skip any optimizations to not draw completely
-                    // hidden views
-                    v.setAlpha(Math.max(v.getAlpha(), 0.01f));
-                    v.setTranslationX(oldX - newX);
-                    anim = new AnimatorSet();
-                    anim.playTogether(
-                            ObjectAnimator.ofFloat(v, "translationX", 0f),
-                            ObjectAnimator.ofFloat(v, "alpha", 1f));
-                    animations.add(anim);
-                    v.setTag(ANIM_TAG_KEY, anim);
-                }
-
-                AnimatorSet slideAnimations = new AnimatorSet();
-                slideAnimations.playTogether(animations);
-                slideAnimations.setDuration(DELETE_SLIDE_IN_SIDE_PAGE_DURATION);
-                slideAnimations.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        mDeferringForDelete = false;
-                        onEndReordering();
-                        onRemoveViewAnimationCompleted();
-                    }
-                });
-                slideAnimations.start();
-
-                removeView(dragView);
-                onRemoveView(dragView, true);
-            }
-        };
-    }
-
-    public void onFlingToDelete(PointF vel) {
-        final long startTime = AnimationUtils.currentAnimationTimeMillis();
-
-        // NOTE: Because it takes time for the first frame of animation to actually be
-        // called and we expect the animation to be a continuation of the fling, we have
-        // to account for the time that has elapsed since the fling finished.  And since
-        // we don't have a startDelay, we will always get call to update when we call
-        // start() (which we want to ignore).
-        final TimeInterpolator tInterpolator = new TimeInterpolator() {
-            private int mCount = -1;
-            private long mStartTime;
-            private float mOffset;
-            /* Anonymous inner class ctor */ {
-                mStartTime = startTime;
-            }
-
-            @Override
-            public float getInterpolation(float t) {
-                if (mCount < 0) {
-                    mCount++;
-                } else if (mCount == 0) {
-                    mOffset = Math.min(0.5f, (float) (AnimationUtils.currentAnimationTimeMillis() -
-                            mStartTime) / FLING_TO_DELETE_FADE_OUT_DURATION);
-                    mCount++;
-                }
-                return Math.min(1f, mOffset + t);
-            }
-        };
-
-        final Rect from = new Rect();
-        final View dragView = mDragView;
-        from.left = (int) dragView.getTranslationX();
-        from.top = (int) dragView.getTranslationY();
-        AnimatorUpdateListener updateCb = new FlingAlongVectorAnimatorUpdateListener(dragView, vel,
-                from, startTime, FLING_TO_DELETE_FRICTION);
-
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        // Create and start the animation
-        ValueAnimator mDropAnim = new ValueAnimator();
-        mDropAnim.setInterpolator(tInterpolator);
-        mDropAnim.setDuration(FLING_TO_DELETE_FADE_OUT_DURATION);
-        mDropAnim.setFloatValues(0f, 1f);
-        mDropAnim.addUpdateListener(updateCb);
-        mDropAnim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        mDropAnim.start();
-        mDeferringForDelete = true;
-    }
-
-    /* Drag to delete */
-    private boolean isHoveringOverDeleteDropTarget(int x, int y) {
-        if (mDeleteDropTarget != null) {
-            mAltTmpRect.set(0, 0, 0, 0);
-            View parent = (View) mDeleteDropTarget.getParent();
-            if (parent != null) {
-                parent.getGlobalVisibleRect(mAltTmpRect);
-            }
-            mDeleteDropTarget.getGlobalVisibleRect(mTmpRect);
-            mTmpRect.offset(-mAltTmpRect.left, -mAltTmpRect.top);
-            return mTmpRect.contains(x, y);
-        }
-        return false;
-    }
-
-    protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {}
-
-    private void onDropToDelete() {
-        final View dragView = mDragView;
-
-        final float toScale = 0f;
-        final float toAlpha = 0f;
-
-        // Create and start the complex animation
-        ArrayList<Animator> animations = new ArrayList<Animator>();
-        AnimatorSet motionAnim = new AnimatorSet();
-        motionAnim.setInterpolator(new DecelerateInterpolator(2));
-        motionAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "scaleX", toScale),
-                ObjectAnimator.ofFloat(dragView, "scaleY", toScale));
-        animations.add(motionAnim);
-
-        AnimatorSet alphaAnim = new AnimatorSet();
-        alphaAnim.setInterpolator(new LinearInterpolator());
-        alphaAnim.playTogether(
-                ObjectAnimator.ofFloat(dragView, "alpha", toAlpha));
-        animations.add(alphaAnim);
-
-        final Runnable onAnimationEndRunnable = createPostDeleteAnimationRunnable(dragView);
-
-        AnimatorSet anim = new AnimatorSet();
-        anim.playTogether(animations);
-        anim.setDuration(DRAG_TO_DELETE_FADE_OUT_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            public void onAnimationEnd(Animator animation) {
-                onAnimationEndRunnable.run();
-            }
-        });
-        anim.start();
-
-        mDeferringForDelete = true;
-    }
-
     /* Accessibility */
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
@@ -2859,6 +2287,15 @@
         if (getCurrentPage() > 0) {
             info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
         }
+        info.setClassName(getClass().getName());
+
+        // Accessibility-wise, PagedView doesn't support long click, so disabling it.
+        // Besides disabling the accessibility long-click, this also prevents this view from getting
+        // accessibility focus.
+        info.setLongClickable(false);
+        if (Utilities.isLmpOrAbove()) {
+            info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+        }
     }
 
     @Override
@@ -2872,7 +2309,7 @@
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
-        event.setScrollable(true);
+        event.setScrollable(getPageCount() > 1);
     }
 
     @Override
diff --git a/src/com/android/launcher3/PagedViewCellLayout.java b/src/com/android/launcher3/PagedViewCellLayout.java
deleted file mode 100644
index 2d9e10b..0000000
--- a/src/com/android/launcher3/PagedViewCellLayout.java
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-
-/**
- * An abstraction of the original CellLayout which supports laying out items
- * which span multiple cells into a grid-like layout.  Also supports dimming
- * to give a preview of its contents.
- */
-public class PagedViewCellLayout extends ViewGroup implements Page {
-    static final String TAG = "PagedViewCellLayout";
-
-    private int mCellCountX;
-    private int mCellCountY;
-    private int mOriginalCellWidth;
-    private int mOriginalCellHeight;
-    private int mCellWidth;
-    private int mCellHeight;
-    private int mOriginalWidthGap;
-    private int mOriginalHeightGap;
-    private int mWidthGap;
-    private int mHeightGap;
-    protected PagedViewCellLayoutChildren mChildren;
-
-    public PagedViewCellLayout(Context context) {
-        this(context, null);
-    }
-
-    public PagedViewCellLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        setAlwaysDrawnWithCacheEnabled(false);
-
-        // setup default cell parameters
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        mOriginalCellWidth = mCellWidth = grid.cellWidthPx;
-        mOriginalCellHeight = mCellHeight = grid.cellHeightPx;
-        mCellCountX = (int) grid.numColumns;
-        mCellCountY = (int) grid.numRows;
-        mOriginalWidthGap = mOriginalHeightGap = mWidthGap = mHeightGap = -1;
-
-        mChildren = new PagedViewCellLayoutChildren(context);
-        mChildren.setCellDimensions(mCellWidth, mCellHeight);
-        mChildren.setGap(mWidthGap, mHeightGap);
-
-        addView(mChildren);
-    }
-
-    public int getCellWidth() {
-        return mCellWidth;
-    }
-
-    public int getCellHeight() {
-        return mCellHeight;
-    }
-
-    @Override
-    public void cancelLongPress() {
-        super.cancelLongPress();
-
-        // Cancel long press for all children
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            child.cancelLongPress();
-        }
-    }
-
-    public boolean addViewToCellLayout(View child, int index, int childId,
-            PagedViewCellLayout.LayoutParams params) {
-        final PagedViewCellLayout.LayoutParams lp = params;
-
-        // Generate an id for each view, this assumes we have at most 256x256 cells
-        // per workspace screen
-        if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
-                lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
-            // If the horizontal or vertical span is set to -1, it is taken to
-            // mean that it spans the extent of the CellLayout
-            if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
-            if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
-
-            child.setId(childId);
-            mChildren.addView(child, index, lp);
-
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void removeAllViewsOnPage() {
-        mChildren.removeAllViews();
-        setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    @Override
-    public void removeViewOnPageAt(int index) {
-        mChildren.removeViewAt(index);
-    }
-
-    /**
-     * Clears all the key listeners for the individual icons.
-     */
-    public void resetChildrenOnKeyListeners() {
-        int childCount = mChildren.getChildCount();
-        for (int j = 0; j < childCount; ++j) {
-            mChildren.getChildAt(j).setOnKeyListener(null);
-        }
-    }
-
-    @Override
-    public int getPageChildCount() {
-        return mChildren.getChildCount();
-    }
-
-    public PagedViewCellLayoutChildren getChildrenLayout() {
-        return mChildren;
-    }
-
-    @Override
-    public View getChildOnPageAt(int i) {
-        return mChildren.getChildAt(i);
-    }
-
-    @Override
-    public int indexOfChildOnPage(View v) {
-        return mChildren.indexOfChild(v);
-    }
-
-    public int getCellCountX() {
-        return mCellCountX;
-    }
-
-    public int getCellCountY() {
-        return mCellCountY;
-    }
-
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
-        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
-
-        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
-            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
-        }
-
-        int numWidthGaps = mCellCountX - 1;
-        int numHeightGaps = mCellCountY - 1;
-
-        if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
-            int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
-            int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
-            int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
-            int vFreeSpace = vSpace - (mCellCountY * mOriginalCellHeight);
-            mWidthGap = numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0;
-            mHeightGap = numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0;
-
-            mChildren.setGap(mWidthGap, mHeightGap);
-        } else {
-            mWidthGap = mOriginalWidthGap;
-            mHeightGap = mOriginalHeightGap;
-        }
-
-        // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
-        int newWidth = widthSpecSize;
-        int newHeight = heightSpecSize;
-        if (widthSpecMode == MeasureSpec.AT_MOST) {
-            newWidth = getPaddingLeft() + getPaddingRight() + (mCellCountX * mCellWidth) +
-                ((mCellCountX - 1) * mWidthGap);
-            newHeight = getPaddingTop() + getPaddingBottom() + (mCellCountY * mCellHeight) +
-                ((mCellCountY - 1) * mHeightGap);
-            setMeasuredDimension(newWidth, newHeight);
-        }
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            int childWidthMeasureSpec =
-                MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
-                        getPaddingRight(), MeasureSpec.EXACTLY);
-            int childheightMeasureSpec =
-                MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
-                        getPaddingBottom(), MeasureSpec.EXACTLY);
-            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-        }
-
-        setMeasuredDimension(newWidth, newHeight);
-    }
-
-    int getContentWidth() {
-        return getWidthBeforeFirstLayout() + getPaddingLeft() + getPaddingRight();
-    }
-
-    int getContentHeight() {
-        if (mCellCountY > 0) {
-            return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
-        }
-        return 0;
-    }
-
-    int getWidthBeforeFirstLayout() {
-        if (mCellCountX > 0) {
-            return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
-        }
-        return 0;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            child.layout(getPaddingLeft(), getPaddingTop(),
-                r - l - getPaddingRight(), b - t - getPaddingBottom());
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        boolean result = super.onTouchEvent(event);
-        int count = getPageChildCount();
-        if (count > 0) {
-            // We only intercept the touch if we are tapping in empty space after the final row
-            View child = getChildOnPageAt(count - 1);
-            int bottom = child.getBottom();
-            int numRows = (int) Math.ceil((float) getPageChildCount() / getCellCountX());
-            if (numRows < getCellCountY()) {
-                // Add a little bit of buffer if there is room for another row
-                bottom += mCellHeight / 2;
-            }
-            result = result || (event.getY() < bottom);
-        }
-        return result;
-    }
-
-    public void enableCenteredContent(boolean enabled) {
-        mChildren.enableCenteredContent(enabled);
-    }
-
-    @Override
-    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
-        mChildren.setChildrenDrawingCacheEnabled(enabled);
-    }
-
-    public void setCellCount(int xCount, int yCount) {
-        mCellCountX = xCount;
-        mCellCountY = yCount;
-        requestLayout();
-    }
-
-    public void setGap(int widthGap, int heightGap) {
-        mOriginalWidthGap = mWidthGap = widthGap;
-        mOriginalHeightGap = mHeightGap = heightGap;
-        mChildren.setGap(widthGap, heightGap);
-    }
-
-    public int[] getCellCountForDimensions(int width, int height) {
-        // Always assume we're working with the smallest span to make sure we
-        // reserve enough space in both orientations
-        int smallerSize = Math.min(mCellWidth, mCellHeight);
-
-        // Always round up to next largest cell
-        int spanX = (width + smallerSize) / smallerSize;
-        int spanY = (height + smallerSize) / smallerSize;
-
-        return new int[] { spanX, spanY };
-    }
-
-    /**
-     * Start dragging the specified child
-     *
-     * @param child The child that is being dragged
-     */
-    void onDragChild(View child) {
-        PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
-        lp.isDragging = true;
-    }
-
-    /**
-     * Estimates the number of cells that the specified width would take up.
-     */
-    public int estimateCellHSpan(int width) {
-        // We don't show the next/previous pages any more, so we use the full width, minus the
-        // padding
-        int availWidth = width - (getPaddingLeft() + getPaddingRight());
-
-        // We know that we have to fit N cells with N-1 width gaps, so we just juggle to solve for N
-        int n = Math.max(1, (availWidth + mWidthGap) / (mCellWidth + mWidthGap));
-
-        // We don't do anything fancy to determine if we squeeze another row in.
-        return n;
-    }
-
-    /**
-     * Estimates the number of cells that the specified height would take up.
-     */
-    public int estimateCellVSpan(int height) {
-        // The space for a page is the height - top padding (current page) - bottom padding (current
-        // page)
-        int availHeight = height - (getPaddingTop() + getPaddingBottom());
-
-        // We know that we have to fit N cells with N-1 height gaps, so we juggle to solve for N
-        int n = Math.max(1, (availHeight + mHeightGap) / (mCellHeight + mHeightGap));
-
-        // We don't do anything fancy to determine if we squeeze another row in.
-        return n;
-    }
-
-    /** Returns an estimated center position of the cell at the specified index */
-    public int[] estimateCellPosition(int x, int y) {
-        return new int[] {
-                getPaddingLeft() + (x * mCellWidth) + (x * mWidthGap) + (mCellWidth / 2),
-                getPaddingTop() + (y * mCellHeight) + (y * mHeightGap) + (mCellHeight / 2)
-        };
-    }
-
-    public void calculateCellCount(int width, int height, int maxCellCountX, int maxCellCountY) {
-        mCellCountX = Math.min(maxCellCountX, estimateCellHSpan(width));
-        mCellCountY = Math.min(maxCellCountY, estimateCellVSpan(height));
-        requestLayout();
-    }
-
-    /**
-     * Estimates the width that the number of hSpan cells will take up.
-     */
-    public int estimateCellWidth(int hSpan) {
-        // TODO: we need to take widthGap into effect
-        return hSpan * mCellWidth;
-    }
-
-    /**
-     * Estimates the height that the number of vSpan cells will take up.
-     */
-    public int estimateCellHeight(int vSpan) {
-        // TODO: we need to take heightGap into effect
-        return vSpan * mCellHeight;
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof PagedViewCellLayout.LayoutParams;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new PagedViewCellLayout.LayoutParams(p);
-    }
-
-    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
-        /**
-         * Horizontal location of the item in the grid.
-         */
-        @ViewDebug.ExportedProperty
-        public int cellX;
-
-        /**
-         * Vertical location of the item in the grid.
-         */
-        @ViewDebug.ExportedProperty
-        public int cellY;
-
-        /**
-         * Number of cells spanned horizontally by the item.
-         */
-        @ViewDebug.ExportedProperty
-        public int cellHSpan;
-
-        /**
-         * Number of cells spanned vertically by the item.
-         */
-        @ViewDebug.ExportedProperty
-        public int cellVSpan;
-
-        /**
-         * Is this item currently being dragged
-         */
-        public boolean isDragging;
-
-        // a data object that you can bind to this layout params
-        private Object mTag;
-
-        // X coordinate of the view in the layout.
-        @ViewDebug.ExportedProperty
-        int x;
-        // Y coordinate of the view in the layout.
-        @ViewDebug.ExportedProperty
-        int y;
-
-        public LayoutParams() {
-            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-            cellHSpan = 1;
-            cellVSpan = 1;
-        }
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-            cellHSpan = 1;
-            cellVSpan = 1;
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams source) {
-            super(source);
-            cellHSpan = 1;
-            cellVSpan = 1;
-        }
-
-        public LayoutParams(LayoutParams source) {
-            super(source);
-            this.cellX = source.cellX;
-            this.cellY = source.cellY;
-            this.cellHSpan = source.cellHSpan;
-            this.cellVSpan = source.cellVSpan;
-        }
-
-        public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
-            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-            this.cellX = cellX;
-            this.cellY = cellY;
-            this.cellHSpan = cellHSpan;
-            this.cellVSpan = cellVSpan;
-        }
-
-        public void setup(Context context,
-                          int cellWidth, int cellHeight, int widthGap, int heightGap,
-                          int hStartPadding, int vStartPadding) {
-
-            final int myCellHSpan = cellHSpan;
-            final int myCellVSpan = cellVSpan;
-            final int myCellX = cellX;
-            final int myCellY = cellY;
-
-            width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
-                    leftMargin - rightMargin;
-            height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
-                    topMargin - bottomMargin;
-
-            if (LauncherAppState.getInstance().isScreenLarge()) {
-                x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
-                y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
-            } else {
-                x = myCellX * (cellWidth + widthGap) + leftMargin;
-                y = myCellY * (cellHeight + heightGap) + topMargin;
-            }
-        }
-
-        public Object getTag() {
-            return mTag;
-        }
-
-        public void setTag(Object tag) {
-            mTag = tag;
-        }
-
-        public String toString() {
-            return "(" + this.cellX + ", " + this.cellY + ", " +
-                this.cellHSpan + ", " + this.cellVSpan + ")";
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/launcher3/PagedViewCellLayoutChildren.java b/src/com/android/launcher3/PagedViewCellLayoutChildren.java
deleted file mode 100644
index 84d2b1d..0000000
--- a/src/com/android/launcher3/PagedViewCellLayoutChildren.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.graphics.Rect;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * An abstraction of the original CellLayout which supports laying out items
- * which span multiple cells into a grid-like layout.  Also supports dimming
- * to give a preview of its contents.
- */
-public class PagedViewCellLayoutChildren extends ViewGroup {
-    static final String TAG = "PagedViewCellLayout";
-
-    private boolean mCenterContent;
-
-    private int mCellWidth;
-    private int mCellHeight;
-    private int mWidthGap;
-    private int mHeightGap;
-
-    public PagedViewCellLayoutChildren(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void cancelLongPress() {
-        super.cancelLongPress();
-
-        // Cancel long press for all children
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            child.cancelLongPress();
-        }
-    }
-
-    public void setGap(int widthGap, int heightGap) {
-        mWidthGap = widthGap;
-        mHeightGap = heightGap;
-        requestLayout();
-    }
-
-    public void setCellDimensions(int width, int height) {
-        mCellWidth = width;
-        mCellHeight = height;
-        requestLayout();
-    }
-
-    @Override
-    public void requestChildFocus(View child, View focused) {
-        super.requestChildFocus(child, focused);
-        if (child != null) {
-            Rect r = new Rect();
-            child.getDrawingRect(r);
-            requestRectangleOnScreen(r);
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
-        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
-
-        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
-        int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
-
-        if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
-            throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
-        }
-
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            PagedViewCellLayout.LayoutParams lp =
-                (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
-            lp.setup(getContext(),
-                    mCellWidth, mCellHeight, mWidthGap, mHeightGap,
-                    getPaddingLeft(),
-                    getPaddingTop());
-
-            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
-                    MeasureSpec.EXACTLY);
-            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
-                    MeasureSpec.EXACTLY);
-
-            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
-        }
-
-        setMeasuredDimension(widthSpecSize, heightSpecSize);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int count = getChildCount();
-
-        int offsetX = 0;
-        if (mCenterContent && count > 0) {
-            // determine the max width of all the rows and center accordingly
-            int maxRowX = 0;
-            int minRowX = Integer.MAX_VALUE;
-            for (int i = 0; i < count; i++) {
-                View child = getChildAt(i);
-                if (child.getVisibility() != GONE) {
-                    PagedViewCellLayout.LayoutParams lp =
-                        (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
-                    minRowX = Math.min(minRowX, lp.x);
-                    maxRowX = Math.max(maxRowX, lp.x + lp.width);
-                }
-            }
-            int maxRowWidth = maxRowX - minRowX;
-            offsetX = (getMeasuredWidth() - maxRowWidth) / 2;
-        }
-
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            if (child.getVisibility() != GONE) {
-                PagedViewCellLayout.LayoutParams lp =
-                    (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
-
-                int childLeft = offsetX + lp.x;
-                int childTop = lp.y;
-                child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
-            }
-        }
-    }
-
-    public void enableCenteredContent(boolean enabled) {
-        mCenterContent = enabled;
-    }
-
-    @Override
-    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            final View view = getChildAt(i);
-            view.setDrawingCacheEnabled(enabled);
-            // Update the drawing caches
-            if (!view.isHardwareAccelerated()) {
-                view.buildDrawingCache(true);
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/PagedViewGridLayout.java b/src/com/android/launcher3/PagedViewGridLayout.java
deleted file mode 100644
index f69fa56..0000000
--- a/src/com/android/launcher3/PagedViewGridLayout.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.GridLayout;
-
-/**
- * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
- */
-public class PagedViewGridLayout extends GridLayout implements Page {
-    static final String TAG = "PagedViewGridLayout";
-
-    private int mCellCountX;
-    private int mCellCountY;
-    private Runnable mOnLayoutListener;
-
-    public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
-        super(context, null, 0);
-        mCellCountX = cellCountX;
-        mCellCountY = cellCountY;
-    }
-
-    int getCellCountX() {
-        return mCellCountX;
-    }
-
-    int getCellCountY() {
-        return mCellCountY;
-    }
-
-    /**
-     * Clears all the key listeners for the individual widgets.
-     */
-    public void resetChildrenOnKeyListeners() {
-        int childCount = getChildCount();
-        for (int j = 0; j < childCount; ++j) {
-            getChildAt(j).setOnKeyListener(null);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mOnLayoutListener = null;
-    }
-
-    public void setOnLayoutListener(Runnable r) {
-        mOnLayoutListener = r;
-    }
-
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mOnLayoutListener != null) {
-            mOnLayoutListener.run();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        boolean result = super.onTouchEvent(event);
-        int count = getPageChildCount();
-        if (count > 0) {
-            // We only intercept the touch if we are tapping in empty space after the final row
-            View child = getChildOnPageAt(count - 1);
-            int bottom = child.getBottom();
-            result = result || (event.getY() < bottom);
-        }
-        return result;
-    }
-
-    @Override
-    public void removeAllViewsOnPage() {
-        removeAllViews();
-        mOnLayoutListener = null;
-        setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    @Override
-    public void removeViewOnPageAt(int index) {
-        removeViewAt(index);
-    }
-
-    @Override
-    public int getPageChildCount() {
-        return getChildCount();
-    }
-
-    @Override
-    public View getChildOnPageAt(int i) {
-        return getChildAt(i);
-    }
-
-    @Override
-    public int indexOfChildOnPage(View v) {
-        return indexOfChild(v);
-    }
-
-    public static class LayoutParams extends FrameLayout.LayoutParams {
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/PagedViewWidget.java
deleted file mode 100644
index e6e11a3..0000000
--- a/src/com/android/launcher3/PagedViewWidget.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.launcher3.compat.AppWidgetManagerCompat;
-
-/**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
- */
-public class PagedViewWidget extends LinearLayout {
-    static final String TAG = "PagedViewWidgetLayout";
-
-    private static boolean sDeletePreviewsWhenDetachedFromWindow = true;
-    private static boolean sRecyclePreviewsWhenDetachedFromWindow = true;
-
-    private String mDimensionsFormatString;
-    CheckForShortPress mPendingCheckForShortPress = null;
-    ShortPressListener mShortPressListener = null;
-    boolean mShortPressTriggered = false;
-    static PagedViewWidget sShortpressTarget = null;
-    boolean mIsAppWidget;
-    private final Rect mOriginalImagePadding = new Rect();
-    private Object mInfo;
-    private WidgetPreviewLoader mWidgetPreviewLoader;
-
-    public PagedViewWidget(Context context) {
-        this(context, null);
-    }
-
-    public PagedViewWidget(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        final Resources r = context.getResources();
-        mDimensionsFormatString = r.getString(R.string.widget_dims_format);
-
-        setWillNotDraw(false);
-        setClipToPadding(false);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-        mOriginalImagePadding.left = image.getPaddingLeft();
-        mOriginalImagePadding.top = image.getPaddingTop();
-        mOriginalImagePadding.right = image.getPaddingRight();
-        mOriginalImagePadding.bottom = image.getPaddingBottom();
-
-        // Ensure we are using the right text size
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        TextView name = (TextView) findViewById(R.id.widget_name);
-        if (name != null) {
-            name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
-        }
-        TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
-        }
-    }
-
-    public static void setDeletePreviewsWhenDetachedFromWindow(boolean value) {
-        sDeletePreviewsWhenDetachedFromWindow = value;
-    }
-
-    public static void setRecyclePreviewsWhenDetachedFromWindow(boolean value) {
-        sRecyclePreviewsWhenDetachedFromWindow = value;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        if (sDeletePreviewsWhenDetachedFromWindow) {
-            final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-            if (image != null) {
-                FastBitmapDrawable preview = (FastBitmapDrawable) image.getDrawable();
-                if (sRecyclePreviewsWhenDetachedFromWindow &&
-                        mInfo != null && preview != null && preview.getBitmap() != null) {
-                    mWidgetPreviewLoader.recycleBitmap(mInfo, preview.getBitmap());
-                }
-                image.setImageDrawable(null);
-            }
-        }
-    }
-
-    public void applyFromAppWidgetProviderInfo(AppWidgetProviderInfo info,
-            int maxWidth, int[] cellSpan, WidgetPreviewLoader loader) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
-        mIsAppWidget = true;
-        mInfo = info;
-        final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-        if (maxWidth > -1) {
-            image.setMaxWidth(maxWidth);
-        }
-        final TextView name = (TextView) findViewById(R.id.widget_name);
-        name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
-        final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            int hSpan = Math.min(cellSpan[0], (int) grid.numColumns);
-            int vSpan = Math.min(cellSpan[1], (int) grid.numRows);
-            dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
-        }
-        mWidgetPreviewLoader = loader;
-    }
-
-    public void applyFromResolveInfo(
-            PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
-        mIsAppWidget = false;
-        mInfo = info;
-        CharSequence label = info.loadLabel(pm);
-        final TextView name = (TextView) findViewById(R.id.widget_name);
-        name.setText(label);
-        final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        if (dims != null) {
-            dims.setText(String.format(mDimensionsFormatString, 1, 1));
-        }
-        mWidgetPreviewLoader = loader;
-    }
-
-    public int[] getPreviewSize() {
-        final ImageView i = (ImageView) findViewById(R.id.widget_preview);
-        int[] maxSize = new int[2];
-        maxSize[0] = i.getWidth() - mOriginalImagePadding.left - mOriginalImagePadding.right;
-        maxSize[1] = i.getHeight() - mOriginalImagePadding.top;
-        return maxSize;
-    }
-
-    void applyPreview(FastBitmapDrawable preview, int index) {
-        final PagedViewWidgetImageView image =
-            (PagedViewWidgetImageView) findViewById(R.id.widget_preview);
-        if (preview != null) {
-            image.mAllowRequestLayout = false;
-            image.setImageDrawable(preview);
-            if (mIsAppWidget) {
-                // center horizontally
-                int[] imageSize = getPreviewSize();
-                int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
-                image.setPadding(mOriginalImagePadding.left + centerAmount,
-                        mOriginalImagePadding.top,
-                        mOriginalImagePadding.right,
-                        mOriginalImagePadding.bottom);
-            }
-            image.setAlpha(1f);
-            image.mAllowRequestLayout = true;
-        }
-    }
-
-    void setShortPressListener(ShortPressListener listener) {
-        mShortPressListener = listener;
-    }
-
-    interface ShortPressListener {
-        void onShortPress(View v);
-        void cleanUpShortPress(View v);
-    }
-
-    class CheckForShortPress implements Runnable {
-        public void run() {
-            if (sShortpressTarget != null) return;
-            if (mShortPressListener != null) {
-                mShortPressListener.onShortPress(PagedViewWidget.this);
-                sShortpressTarget = PagedViewWidget.this;
-            }
-            mShortPressTriggered = true;
-        }
-    }
-
-    private void checkForShortPress() {
-        if (sShortpressTarget != null) return;
-        if (mPendingCheckForShortPress == null) {
-            mPendingCheckForShortPress = new CheckForShortPress();
-        }
-        postDelayed(mPendingCheckForShortPress, 120);
-    }
-
-    /**
-     * Remove the longpress detection timer.
-     */
-    private void removeShortPressCallback() {
-        if (mPendingCheckForShortPress != null) {
-          removeCallbacks(mPendingCheckForShortPress);
-        }
-    }
-
-    private void cleanUpShortPress() {
-        removeShortPressCallback();
-        if (mShortPressTriggered) {
-            if (mShortPressListener != null) {
-                mShortPressListener.cleanUpShortPress(PagedViewWidget.this);
-            }
-            mShortPressTriggered = false;
-        }
-    }
-
-    static void resetShortPressTarget() {
-        sShortpressTarget = null;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        super.onTouchEvent(event);
-
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_UP:
-                cleanUpShortPress();
-                break;
-            case MotionEvent.ACTION_DOWN:
-                checkForShortPress();
-                break;
-            case MotionEvent.ACTION_CANCEL:
-                cleanUpShortPress();
-                break;
-            case MotionEvent.ACTION_MOVE:
-                break;
-        }
-
-        // We eat up the touch events here, since the PagedView (which uses the same swiping
-        // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
-        // the user is scrolling between pages.  This means that if the pages themselves don't
-        // handle touch events, it gets forwarded up to PagedView itself, and it's own
-        // onTouchEvent() handling will prevent further intercept touch events from being called
-        // (it's the same view in that case).  This is not ideal, but to prevent more changes,
-        // we just always mark the touch event as handled.
-        return true;
-    }
-}
diff --git a/src/com/android/launcher3/PagedViewWidgetImageView.java b/src/com/android/launcher3/PagedViewWidgetImageView.java
deleted file mode 100644
index 7d82795..0000000
--- a/src/com/android/launcher3/PagedViewWidgetImageView.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-public class PagedViewWidgetImageView extends ImageView {
-    public boolean mAllowRequestLayout = true;
-
-    public PagedViewWidgetImageView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void requestLayout() {
-        if (mAllowRequestLayout) {
-            super.requestLayout();
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        canvas.save();
-        canvas.clipRect(getScrollX() + getPaddingLeft(),
-                getScrollY() + getPaddingTop(),
-                getScrollX() + getRight() - getLeft() - getPaddingRight(),
-                getScrollY() + getBottom() - getTop() - getPaddingBottom());
-
-        super.onDraw(canvas);
-        canvas.restore();
-
-    }
-}
diff --git a/src/com/android/launcher3/PagedViewWithDraggableItems.java b/src/com/android/launcher3/PagedViewWithDraggableItems.java
deleted file mode 100644
index 0e59369..0000000
--- a/src/com/android/launcher3/PagedViewWithDraggableItems.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
- * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
- * Subclasses must do the following:
- *   * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
- *   * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
- *       (good place to do it is in syncPageItems)
- *   * override beginDragging(View) (but be careful to call super.beginDragging(View)
- *
- */
-public abstract class PagedViewWithDraggableItems extends PagedView
-    implements View.OnLongClickListener, View.OnTouchListener {
-    private View mLastTouchedItem;
-    private boolean mIsDragging;
-    private boolean mIsDragEnabled;
-    private float mDragSlopeThreshold;
-    private Launcher mLauncher;
-
-    public PagedViewWithDraggableItems(Context context) {
-        this(context, null);
-    }
-
-    public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mLauncher = (Launcher) context;
-    }
-
-    protected boolean beginDragging(View v) {
-        boolean wasDragging = mIsDragging;
-        mIsDragging = true;
-        return !wasDragging;
-    }
-
-    protected void cancelDragging() {
-        mIsDragging = false;
-        mLastTouchedItem = null;
-        mIsDragEnabled = false;
-    }
-
-    private void handleTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN:
-                cancelDragging();
-                mIsDragEnabled = true;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) {
-                    determineDraggingStart(ev);
-                }
-                break;
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        handleTouchEvent(ev);
-        return super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        handleTouchEvent(ev);
-        return super.onTouchEvent(ev);
-    }
-
-    public void trimMemory() {
-        mLastTouchedItem = null;
-    }
-
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        mLastTouchedItem = v;
-        mIsDragEnabled = true;
-        return false;
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        // Return early if this is not initiated from a touch
-        if (!v.isInTouchMode()) return false;
-        // Return early if we are still animating the pages
-        if (mNextPage != INVALID_PAGE) return false;
-        // When we have exited all apps or are in transition, disregard long clicks
-        if (!mLauncher.isAllAppsVisible() ||
-                mLauncher.getWorkspace().isSwitchingState()) return false;
-        // Return if global dragging is not enabled
-        if (!mLauncher.isDraggingEnabled()) return false;
-
-        return beginDragging(v);
-    }
-
-    /*
-     * Determines if we should change the touch state to start scrolling after the
-     * user moves their touch point too far.
-     */
-    protected void determineScrollingStart(MotionEvent ev) {
-        if (!mIsDragging) super.determineScrollingStart(ev);
-    }
-
-    /*
-     * Determines if we should change the touch state to start dragging after the
-     * user moves their touch point far enough.
-     */
-    protected void determineDraggingStart(MotionEvent ev) {
-        /*
-         * Locally do absolute value. mLastMotionX is set to the y value
-         * of the down event.
-         */
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        final int xDiff = (int) Math.abs(x - mLastMotionX);
-        final int yDiff = (int) Math.abs(y - mLastMotionY);
-
-        final int touchSlop = mTouchSlop;
-        boolean yMoved = yDiff > touchSlop;
-        boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
-
-        if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
-            // Drag if the user moved far enough along the Y axis
-            beginDragging(mLastTouchedItem);
-
-            // Cancel any pending long press
-            if (mAllowLongPress) {
-                mAllowLongPress = false;
-                // Try canceling the long press. It could also have been scheduled
-                // by a distant descendant, so use the mAllowLongPress flag to block
-                // everything
-                final View currentPage = getPageAt(mCurrentPage);
-                if (currentPage != null) {
-                    currentPage.cancelLongPress();
-                }
-            }
-        }
-    }
-
-    public void setDragSlopeThreshold(float dragSlopeThreshold) {
-        mDragSlopeThreshold = dragSlopeThreshold;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        cancelDragging();
-        super.onDetachedFromWindow();
-    }
-}
diff --git a/src/com/android/launcher3/Partner.java b/src/com/android/launcher3/Partner.java
index e191319..380078b 100644
--- a/src/com/android/launcher3/Partner.java
+++ b/src/com/android/launcher3/Partner.java
@@ -47,8 +47,6 @@
     public static final String RES_REQUIRE_FIRST_RUN_FLOW = "requires_first_run_flow";
 
     /** These resources are used to override the device profile  */
-    public static final String RES_GRID_AA_SHORT_EDGE_COUNT = "grid_aa_short_edge_count";
-    public static final String RES_GRID_AA_LONG_EDGE_COUNT = "grid_aa_long_edge_count";
     public static final String RES_GRID_NUM_ROWS = "grid_num_rows";
     public static final String RES_GRID_NUM_COLUMNS = "grid_num_columns";
     public static final String RES_GRID_ICON_SIZE_DP = "grid_icon_size_dp";
@@ -116,56 +114,42 @@
         return resId != 0 && getResources().getBoolean(resId);
     }
 
-    public DeviceProfile getDeviceProfileOverride(DisplayMetrics dm) {
-        boolean containsProfileOverrides = false;
-
-        DeviceProfile dp = new DeviceProfile();
-
-        // We initialize customizable fields to be invalid
-        dp.numRows = -1;
-        dp.numColumns = -1;
-        dp.allAppsShortEdgeCount = -1;
-        dp.allAppsLongEdgeCount = -1;
+    public void applyInvariantDeviceProfileOverrides(InvariantDeviceProfile inv, DisplayMetrics dm) {
+        int numRows = -1;
+        int numColumns = -1;
+        float iconSize = -1;
 
         try {
             int resId = getResources().getIdentifier(RES_GRID_NUM_ROWS,
                     "integer", getPackageName());
             if (resId > 0) {
-                containsProfileOverrides = true;
-                dp.numRows = getResources().getInteger(resId);
+                numRows = getResources().getInteger(resId);
             }
 
             resId = getResources().getIdentifier(RES_GRID_NUM_COLUMNS,
                     "integer", getPackageName());
             if (resId > 0) {
-                containsProfileOverrides = true;
-                dp.numColumns = getResources().getInteger(resId);
-            }
-
-            resId = getResources().getIdentifier(RES_GRID_AA_SHORT_EDGE_COUNT,
-                    "integer", getPackageName());
-            if (resId > 0) {
-                containsProfileOverrides = true;
-                dp.allAppsShortEdgeCount = getResources().getInteger(resId);
-            }
-
-            resId = getResources().getIdentifier(RES_GRID_AA_LONG_EDGE_COUNT,
-                    "integer", getPackageName());
-            if (resId > 0) {
-                containsProfileOverrides = true;
-                dp.allAppsLongEdgeCount = getResources().getInteger(resId);
+                numColumns = getResources().getInteger(resId);
             }
 
             resId = getResources().getIdentifier(RES_GRID_ICON_SIZE_DP,
                     "dimen", getPackageName());
             if (resId > 0) {
-                containsProfileOverrides = true;
                 int px = getResources().getDimensionPixelSize(resId);
-                dp.iconSize = DynamicGrid.dpiFromPx(px, dm);
+                iconSize = Utilities.dpiFromPx(px, dm);
             }
         } catch (Resources.NotFoundException ex) {
             Log.e(TAG, "Invalid Partner grid resource!", ex);
+            return;
         }
-        return containsProfileOverrides ? dp : null;
+
+        if (numRows > 0 && numColumns > 0) {
+            inv.numRows = numRows;
+            inv.numColumns = numColumns;
+        }
+
+        if (iconSize > 0) {
+            inv.iconSize = iconSize;
+        }
     }
 }
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index 967cc92..1aaf85b 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -16,92 +16,17 @@
 
 package com.android.launcher3;
 
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.os.Bundle;
-import android.os.Parcelable;
 
 /**
- * We pass this object with a drag from the customization tray
+ * Meta data that is used for deferred binding.
+ * e.g., this object is used to pass information on dragable targets when they are dropped onto
+ * the workspace from another container.
  */
-class PendingAddItemInfo extends ItemInfo {
+public class PendingAddItemInfo extends ItemInfo {
+
     /**
      * The component that will be created.
      */
-    ComponentName componentName;
-}
-
-class PendingAddShortcutInfo extends PendingAddItemInfo {
-
-    ActivityInfo shortcutActivityInfo;
-
-    public PendingAddShortcutInfo(ActivityInfo activityInfo) {
-        shortcutActivityInfo = activityInfo;
-    }
-
-    @Override
-    public String toString() {
-        return "Shortcut: " + shortcutActivityInfo.packageName;
-    }
-}
-
-class PendingAddWidgetInfo extends PendingAddItemInfo {
-    int minWidth;
-    int minHeight;
-    int minResizeWidth;
-    int minResizeHeight;
-    int previewImage;
-    int icon;
-    AppWidgetProviderInfo info;
-    AppWidgetHostView boundWidget;
-    Bundle bindOptions = null;
-
-    // Any configuration data that we want to pass to a configuration activity when
-    // starting up a widget
-    String mimeType;
-    Parcelable configurationData;
-
-    public PendingAddWidgetInfo(AppWidgetProviderInfo i, String dataMimeType, Parcelable data) {
-        itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
-        this.info = i;
-        componentName = i.provider;
-        minWidth = i.minWidth;
-        minHeight = i.minHeight;
-        minResizeWidth = i.minResizeWidth;
-        minResizeHeight = i.minResizeHeight;
-        previewImage = i.previewImage;
-        icon = i.icon;
-        if (dataMimeType != null && data != null) {
-            mimeType = dataMimeType;
-            configurationData = data;
-        }
-    }
-
-    // Copy constructor
-    public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
-        minWidth = copy.minWidth;
-        minHeight = copy.minHeight;
-        minResizeWidth = copy.minResizeWidth;
-        minResizeHeight = copy.minResizeHeight;
-        previewImage = copy.previewImage;
-        icon = copy.icon;
-        info = copy.info;
-        boundWidget = copy.boundWidget;
-        mimeType = copy.mimeType;
-        configurationData = copy.configurationData;
-        componentName = copy.componentName;
-        itemType = copy.itemType;
-        spanX = copy.spanX;
-        spanY = copy.spanY;
-        minSpanX = copy.minSpanX;
-        minSpanY = copy.minSpanY;
-        bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
-    }
-
-    @Override
-    public String toString() {
-        return "Widget: " + componentName.toShortString();
-    }
+    public ComponentName componentName;
 }
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index 179c60a..08f8e56 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -42,6 +42,7 @@
     private final int mStartState;
     private final Intent mIconLookupIntent;
     private final boolean mDisabledForSafeMode;
+    private Launcher mLauncher;
 
     private Bitmap mIcon;
 
@@ -56,6 +57,8 @@
     public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
             boolean disabledForSafeMode) {
         super(context);
+
+        mLauncher = (Launcher) context;
         mInfo = info;
         mStartState = info.restoreStatus;
         mIconLookupIntent = new Intent().setComponent(info.providerName);
@@ -64,7 +67,7 @@
         mPaint = new TextPaint();
         mPaint.setColor(0xFFFFFFFF);
         mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
+                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
         setBackgroundResource(R.drawable.quantum_panel_dark);
         setWillNotDraw(false);
     }
@@ -118,7 +121,7 @@
             //   2) Preload icon in the center
             //   3) Setup icon in the center and app icon in the top right corner.
             if (mDisabledForSafeMode) {
-                FastBitmapDrawable disabledIcon = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable disabledIcon = mLauncher.createIconDrawable(mIcon);
                 disabledIcon.setGhostModeEnabled(true);
                 mCenterDrawable = disabledIcon;
                 mTopCornerDrawable = null;
@@ -131,7 +134,7 @@
                     sPreloaderTheme.applyStyle(R.style.PreloadIcon, true);
                 }
 
-                FastBitmapDrawable drawable = Utilities.createIconDrawable(mIcon);
+                FastBitmapDrawable drawable = mLauncher.createIconDrawable(mIcon);
                 mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme);
                 mCenterDrawable.setCallback(this);
                 mTopCornerDrawable = null;
@@ -173,12 +176,12 @@
             return;
         }
 
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         if (mTopCornerDrawable == null) {
             if (mDrawableSizeChanged) {
                 int outset = (mCenterDrawable instanceof PreloadIconDrawable) ?
                         ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0;
-                int maxSize = LauncherAppState.getInstance().getDynamicGrid()
-                        .getDeviceProfile().iconSizePx + 2 * outset;
+                int maxSize = grid.iconSizePx + 2 * outset;
                 int size = Math.min(maxSize, Math.min(
                         getWidth() - getPaddingLeft() - getPaddingRight(),
                         getHeight() - getPaddingTop() - getPaddingBottom()));
@@ -193,7 +196,6 @@
         } else  {
             // Draw the top corner icon and "Setup" text is possible
             if (mDrawableSizeChanged) {
-                DeviceProfile grid = getDeviceProfile();
                 int iconSize = grid.iconSizePx;
                 int paddingTop = getPaddingTop();
                 int paddingBottom = getPaddingBottom();
@@ -251,8 +253,4 @@
             }
         }
     }
-
-    private DeviceProfile getDeviceProfile() {
-        return LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
-    }
 }
diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java
index 2972c4f..bcb59c4 100644
--- a/src/com/android/launcher3/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/PreloadIconDrawable.java
@@ -54,12 +54,11 @@
         mPaint.setStrokeCap(Paint.Cap.ROUND);
 
         setBounds(icon.getBounds());
-        applyTheme(theme);
+        applyPreloaderTheme(theme);
         onLevelChange(0);
     }
 
-    @Override
-    public void applyTheme(Theme t) {
+    public void applyPreloaderTheme(Theme t) {
         TypedArray ta = t.obtainStyledAttributes(R.styleable.PreloadIconDrawable);
         mBgDrawable = ta.getDrawable(R.styleable.PreloadIconDrawable_background);
         mBgDrawable.setFilterBitmap(true);
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index 99c2e08..4cdf1ca 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -33,23 +33,22 @@
  */
 public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
 
-    private static final int sTransitionInDuration = 200;
-    private static final int sTransitionOutDuration = 175;
+    private static final int TRANSITION_DURATION = 200;
 
-    private ObjectAnimator mDropTargetBarAnim;
-    private ValueAnimator mQSBSearchBarAnim;
+    private ObjectAnimator mShowDropTargetBarAnim;
+    private ValueAnimator mHideSearchBarAnim;
     private static final AccelerateInterpolator sAccelerateInterpolator =
             new AccelerateInterpolator();
 
     private boolean mIsSearchBarHidden;
     private View mQSBSearchBar;
     private View mDropTargetBar;
-    private ButtonDropTarget mInfoDropTarget;
-    private ButtonDropTarget mDeleteDropTarget;
-    private int mBarHeight;
     private boolean mDeferOnDragEnd = false;
 
-    private boolean mEnableDropDownDropTargets;
+    // Drop targets
+    private ButtonDropTarget mInfoDropTarget;
+    private ButtonDropTarget mDeleteDropTarget;
+    private ButtonDropTarget mUninstallDropTarget;
 
     public SearchDropTargetBar(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -61,29 +60,30 @@
 
     public void setup(Launcher launcher, DragController dragController) {
         dragController.addDragListener(this);
+        dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
+
         dragController.addDragListener(mInfoDropTarget);
         dragController.addDragListener(mDeleteDropTarget);
+        dragController.addDragListener(mUninstallDropTarget);
+
         dragController.addDropTarget(mInfoDropTarget);
         dragController.addDropTarget(mDeleteDropTarget);
-        dragController.setFlingToDeleteDropTarget(mDeleteDropTarget);
+        dragController.addDropTarget(mUninstallDropTarget);
+
         mInfoDropTarget.setLauncher(launcher);
         mDeleteDropTarget.setLauncher(launcher);
+        mUninstallDropTarget.setLauncher(launcher);
     }
 
     public void setQsbSearchBar(View qsb) {
         mQSBSearchBar = qsb;
         if (mQSBSearchBar != null) {
-            if (mEnableDropDownDropTargets) {
-                mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0,
-                        -mBarHeight);
-            } else {
-                mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
-            }
-            setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
+            mHideSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
+            setupAnimation(mHideSearchBarAnim, mQSBSearchBar);
         } else {
             // Create a no-op animation of the search bar is null
-            mQSBSearchBarAnim = ValueAnimator.ofFloat(0, 0);
-            mQSBSearchBarAnim.setDuration(sTransitionInDuration);
+            mHideSearchBarAnim = ValueAnimator.ofFloat(0, 0);
+            mHideSearchBarAnim.setDuration(TRANSITION_DURATION);
         }
     }
 
@@ -97,7 +97,7 @@
 
     private void setupAnimation(ValueAnimator anim, final View v) {
         anim.setInterpolator(sAccelerateInterpolator);
-        anim.setDuration(sTransitionInDuration);
+        anim.setDuration(TRANSITION_DURATION);
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -116,80 +116,80 @@
         mDropTargetBar = findViewById(R.id.drag_target_bar);
         mInfoDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.info_target_text);
         mDeleteDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.delete_target_text);
+        mUninstallDropTarget = (ButtonDropTarget) mDropTargetBar.findViewById(R.id.uninstall_target_text);
 
         mInfoDropTarget.setSearchDropTargetBar(this);
         mDeleteDropTarget.setSearchDropTargetBar(this);
-
-        mEnableDropDownDropTargets =
-            getResources().getBoolean(R.bool.config_useDropTargetDownTransition);
+        mUninstallDropTarget.setSearchDropTargetBar(this);
 
         // Create the various fade animations
-        if (mEnableDropDownDropTargets) {
-            LauncherAppState app = LauncherAppState.getInstance();
-            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-            mBarHeight = grid.searchBarSpaceHeightPx;
-            mDropTargetBar.setTranslationY(-mBarHeight);
-            mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "translationY",
-                    -mBarHeight, 0f);
-
-        } else {
-            mDropTargetBar.setAlpha(0f);
-            mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
-        }
-        setupAnimation(mDropTargetBarAnim, mDropTargetBar);
+        mDropTargetBar.setAlpha(0f);
+        mShowDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
+        setupAnimation(mShowDropTargetBarAnim, mDropTargetBar);
     }
 
+    /**
+     * Finishes all the animations on the search and drop target bars.
+     */
     public void finishAnimations() {
         prepareStartAnimation(mDropTargetBar);
-        mDropTargetBarAnim.reverse();
+        mShowDropTargetBarAnim.reverse();
         prepareStartAnimation(mQSBSearchBar);
-        mQSBSearchBarAnim.reverse();
+        mHideSearchBarAnim.reverse();
     }
 
-    /*
-     * Shows and hides the search bar.
+    /**
+     * Shows the search bar.
      */
     public void showSearchBar(boolean animated) {
-        boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated;
-        if (!mIsSearchBarHidden && !needToCancelOngoingAnimation) return;
+        if (!mIsSearchBarHidden) return;
         if (animated) {
             prepareStartAnimation(mQSBSearchBar);
-            mQSBSearchBarAnim.reverse();
+            mHideSearchBarAnim.reverse();
         } else {
-            mQSBSearchBarAnim.cancel();
-            if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
-                mQSBSearchBar.setTranslationY(0);
-            } else if (mQSBSearchBar != null) {
+            mHideSearchBarAnim.cancel();
+            if (mQSBSearchBar != null) {
                 mQSBSearchBar.setAlpha(1f);
             }
         }
         mIsSearchBarHidden = false;
     }
+
+    /**
+     * Hides the search bar.  We only use this for clings.
+     */
     public void hideSearchBar(boolean animated) {
-        boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated;
-        if (mIsSearchBarHidden && !needToCancelOngoingAnimation) return;
+        if (mIsSearchBarHidden) return;
         if (animated) {
             prepareStartAnimation(mQSBSearchBar);
-            mQSBSearchBarAnim.start();
+            mHideSearchBarAnim.start();
         } else {
-            mQSBSearchBarAnim.cancel();
-            if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
-                mQSBSearchBar.setTranslationY(-mBarHeight);
-            } else if (mQSBSearchBar != null) {
+            mHideSearchBarAnim.cancel();
+            if (mQSBSearchBar != null) {
                 mQSBSearchBar.setAlpha(0f);
             }
         }
         mIsSearchBarHidden = true;
     }
 
-    /*
-     * Gets various transition durations.
+    /**
+     * Shows the drop target bar.
      */
-    public int getTransitionInDuration() {
-        return sTransitionInDuration;
+    public void showDeleteTarget() {
+        // Animate out the QSB search bar, and animate in the drop target bar
+        prepareStartAnimation(mDropTargetBar);
+        mShowDropTargetBarAnim.start();
+        hideSearchBar(true);
     }
-    public int getTransitionOutDuration() {
-        return sTransitionOutDuration;
+
+    /**
+     * Hides the drop target bar.
+     */
+    public void hideDeleteTarget() {
+        // Restore the QSB search bar, and animate out the drop target bar
+        prepareStartAnimation(mDropTargetBar);
+        mShowDropTargetBarAnim.reverse();
+        showSearchBar(true);
     }
 
     /*
@@ -197,13 +197,7 @@
      */
     @Override
     public void onDragStart(DragSource source, Object info, int dragAction) {
-        // Animate out the QSB search bar, and animate in the drop target bar
-        prepareStartAnimation(mDropTargetBar);
-        mDropTargetBarAnim.start();
-        if (!mIsSearchBarHidden) {
-            prepareStartAnimation(mQSBSearchBar);
-            mQSBSearchBarAnim.start();
-        }
+        showDeleteTarget();
     }
 
     public void deferOnDragEnd() {
@@ -213,13 +207,7 @@
     @Override
     public void onDragEnd() {
         if (!mDeferOnDragEnd) {
-            // Restore the QSB search bar, and animate out the drop target bar
-            prepareStartAnimation(mDropTargetBar);
-            mDropTargetBarAnim.reverse();
-            if (!mIsSearchBarHidden) {
-                prepareStartAnimation(mQSBSearchBar);
-                mQSBSearchBarAnim.reverse();
-            }
+            hideDeleteTarget();
         } else {
             mDeferOnDragEnd = false;
         }
@@ -240,4 +228,13 @@
             return null;
         }
     }
+
+    public void enableAccessibleDrag(boolean enable) {
+        if (mQSBSearchBar != null) {
+            mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
+        }
+        mInfoDropTarget.enableAccessibleDrag(enable);
+        mDeleteDropTarget.enableAccessibleDrag(enable);
+        mUninstallDropTarget.enableAccessibleDrag(enable);
+    }
 }
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
new file mode 100644
index 0000000..dab71c8
--- /dev/null
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.preference.SwitchPreference;
+
+/**
+ * Settings activity for Launcher. Currently implements the following setting: Allow rotation
+ */
+public class SettingsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Display the fragment as the main content.
+        getFragmentManager().beginTransaction()
+                .replace(android.R.id.content, new LauncherSettingsFragment())
+                .commit();
+    }
+
+    /**
+     * This fragment shows the launcher preferences.
+     */
+    public static class LauncherSettingsFragment extends PreferenceFragment
+            implements OnPreferenceChangeListener {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            addPreferencesFromResource(R.xml.launcher_preferences);
+
+            SwitchPreference pref = (SwitchPreference) findPreference(
+                    Utilities.ALLOW_ROTATION_PREFERENCE_KEY);
+            pref.setPersistent(false);
+
+            Bundle extras = new Bundle();
+            extras.putBoolean(LauncherSettings.Settings.EXTRA_DEFAULT_VALUE, false);
+            Bundle value = getActivity().getContentResolver().call(
+                    LauncherSettings.Settings.CONTENT_URI,
+                    LauncherSettings.Settings.METHOD_GET_BOOLEAN,
+                    Utilities.ALLOW_ROTATION_PREFERENCE_KEY, extras);
+            pref.setChecked(value.getBoolean(LauncherSettings.Settings.EXTRA_VALUE));
+
+            pref.setOnPreferenceChangeListener(this);
+        }
+
+        @Override
+        public boolean onPreferenceChange(Preference preference, Object newValue) {
+            Bundle extras = new Bundle();
+            extras.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, (Boolean) newValue);
+            getActivity().getContentResolver().call(
+                    LauncherSettings.Settings.CONTENT_URI,
+                    LauncherSettings.Settings.METHOD_SET_BOOLEAN,
+                    preference.getKey(), extras);
+            return true;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index bb5601e..157b48a 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 
 public class ShortcutAndWidgetContainer extends ViewGroup {
     static final String TAG = "CellLayoutChildren";
@@ -44,10 +45,13 @@
     private int mCountX;
     private int mCountY;
 
+    private Launcher mLauncher;
+
     private boolean mInvertIfRtl = false;
 
     public ShortcutAndWidgetContainer(Context context) {
         super(context);
+        mLauncher = (Launcher) context;
         mWallpaperManager = WallpaperManager.getInstance(context);
     }
 
@@ -124,22 +128,19 @@
     }
 
     int getCellContentWidth() {
-        final LauncherAppState app = LauncherAppState.getInstance();
-        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        final DeviceProfile grid = mLauncher.getDeviceProfile();
         return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
                 grid.hotseatCellWidthPx: grid.cellWidthPx);
     }
 
     int getCellContentHeight() {
-        final LauncherAppState app = LauncherAppState.getInstance();
-        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        final DeviceProfile grid = mLauncher.getDeviceProfile();
         return Math.min(getMeasuredHeight(), mIsHotseatLayout ?
                 grid.hotseatCellHeightPx : grid.cellHeightPx);
     }
 
     public void measureChild(View child) {
-        final LauncherAppState app = LauncherAppState.getInstance();
-        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        final DeviceProfile grid = mLauncher.getDeviceProfile();
         final int cellWidth = mCellWidth;
         final int cellHeight = mCellHeight;
         CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
@@ -168,12 +169,8 @@
         child.measure(childWidthMeasureSpec, childheightMeasureSpec);
     }
 
-    private boolean invertLayoutHorizontally() {
-        return mInvertIfRtl && isLayoutRtl();
-    }
-
-    public boolean isLayoutRtl() {
-        return (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+    public boolean invertLayoutHorizontally() {
+        return mInvertIfRtl && Utilities.isRtl(getResources());
     }
 
     @Override
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 01f7931..56c0b9d 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -23,7 +23,10 @@
 import android.graphics.Bitmap;
 import android.util.Log;
 
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -46,18 +49,24 @@
      * be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
      * parsing.
      */
-    public static final int FLAG_AUTOINTALL_ICON = 2;
+    public static final int FLAG_AUTOINTALL_ICON = 2; //0B10;
 
     /**
      * The icon is being installed. If {@link FLAG_RESTORED_ICON} or {@link FLAG_AUTOINTALL_ICON}
      * is set, then the icon is either being installed or is in a broken state.
      */
-    public static final int FLAG_INSTALL_SESSION_ACTIVE = 4;
+    public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
 
     /**
      * Indicates that the widget restore has started.
      */
-    public static final int FLAG_RESTORE_STARTED = 8;
+    public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
+
+    /**
+     * Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
+     * Upto 15 different types supported.
+     */
+    public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
 
     /**
      * The intent used to start the application.
@@ -67,8 +76,9 @@
     /**
      * Indicates whether the icon comes from an application's resource (if false)
      * or from a custom Bitmap (if true.)
+     * TODO: remove this flag
      */
-    boolean customIcon;
+    public boolean customIcon;
 
     /**
      * Indicates whether we're using the default fallback icon instead of something from the
@@ -77,10 +87,15 @@
     boolean usingFallbackIcon;
 
     /**
+     * Indicates whether we're using a low res icon
+     */
+    boolean usingLowResIcon;
+
+    /**
      * If isShortcut=true and customIcon=false, this contains a reference to the
      * shortcut icon as an application's resource.
      */
-    Intent.ShortcutIconResource iconResource;
+    public Intent.ShortcutIconResource iconResource;
 
     /**
      * The application icon.
@@ -113,7 +128,7 @@
     /**
      * Refer {@link AppInfo#firstInstallTime}.
      */
-    long firstInstallTime;
+    public long firstInstallTime;
 
     /**
      * TODO move this to {@link status}
@@ -139,7 +154,7 @@
             Bitmap icon, UserHandleCompat user) {
         this();
         this.intent = intent;
-        this.title = title;
+        this.title = Utilities.trim(title);
         this.contentDescription = contentDescription;
         mIcon = icon;
         this.user = user;
@@ -147,7 +162,7 @@
 
     public ShortcutInfo(Context context, ShortcutInfo info) {
         super(info);
-        title = info.title.toString();
+        title = Utilities.trim(info.title);
         intent = new Intent(info.intent);
         if (info.iconResource != null) {
             iconResource = new Intent.ShortcutIconResource();
@@ -165,7 +180,7 @@
     /** TODO: Remove this.  It's only called by ApplicationInfo.makeShortcut. */
     public ShortcutInfo(AppInfo info) {
         super(info);
-        title = info.title.toString();
+        title = Utilities.trim(info.title);
         intent = new Intent(info.intent);
         customIcon = false;
         flags = info.flags;
@@ -184,8 +199,10 @@
     }
 
     public void updateIcon(IconCache iconCache) {
-        mIcon = iconCache.getIcon(promisedIntent != null ? promisedIntent : intent, user);
-        usingFallbackIcon = iconCache.isDefaultIcon(mIcon, user);
+        if (itemType == Favorites.ITEM_TYPE_APPLICATION) {
+            iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user,
+                    shouldUseLowResIcon());
+        }
     }
 
     @Override
@@ -198,6 +215,7 @@
         String uri = promisedIntent != null ? promisedIntent.toUri(0)
                 : (intent != null ? intent.toUri(0) : null);
         values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
+        values.put(LauncherSettings.Favorites.RESTORED, status);
 
         if (customIcon) {
             values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
@@ -207,9 +225,9 @@
             if (!usingFallbackIcon) {
                 writeBitmap(values, mIcon);
             }
-            values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
-                    LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
             if (iconResource != null) {
+                values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
+                        LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
                 values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
                         iconResource.packageName);
                 values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
@@ -256,5 +274,23 @@
         mInstallProgress = progress;
         status |= FLAG_INSTALL_SESSION_ACTIVE;
     }
+
+    public boolean shouldUseLowResIcon() {
+        return usingLowResIcon && container >= 0 && rank >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
+    }
+
+    public static ShortcutInfo fromActivityInfo(LauncherActivityInfoCompat info, Context context) {
+        final ShortcutInfo shortcut = new ShortcutInfo();
+        shortcut.user = info.getUser();
+        shortcut.title = Utilities.trim(info.getLabel());
+        shortcut.contentDescription = UserManagerCompat.getInstance(context)
+                .getBadgedLabelForUser(info.getLabel(), info.getUser());
+        shortcut.customIcon = false;
+        shortcut.intent = AppInfo.makeLaunchIntent(context, info, info.getUser());
+        shortcut.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+        shortcut.flags = AppInfo.initFlags(info);
+        shortcut.firstInstallTime = info.getFirstInstallTime();
+        return shortcut;
+    }
 }
 
diff --git a/src/com/android/launcher3/SmoothPagedView.java b/src/com/android/launcher3/SmoothPagedView.java
deleted file mode 100644
index 4e331aa..0000000
--- a/src/com/android/launcher3/SmoothPagedView.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.animation.Interpolator;
-
-public abstract class SmoothPagedView extends PagedView {
-    private static final float SMOOTHING_SPEED = 0.75f;
-    private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
-
-    private float mBaseLineFlingVelocity;
-    private float mFlingVelocityInfluence;
-
-    static final int DEFAULT_MODE = 0;
-    static final int X_LARGE_MODE = 1;
-
-    int mScrollMode;
-
-    private Interpolator mScrollInterpolator;
-
-    public static class OvershootInterpolator implements Interpolator {
-        private static final float DEFAULT_TENSION = 1.3f;
-        private float mTension;
-
-        public OvershootInterpolator() {
-            mTension = DEFAULT_TENSION;
-        }
-
-        public void setDistance(int distance) {
-            mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
-        }
-
-        public void disableSettle() {
-            mTension = 0.f;
-        }
-
-        public float getInterpolation(float t) {
-            t -= 1.0f;
-            return t * t * ((mTension + 1) * t + mTension) + 1.0f;
-        }
-    }
-
-    /**
-     * Used to inflate the Workspace from XML.
-     *
-     * @param context The application's context.
-     * @param attrs The attributes set containing the Workspace's customization values.
-     */
-    public SmoothPagedView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    /**
-     * Used to inflate the Workspace from XML.
-     *
-     * @param context The application's context.
-     * @param attrs The attributes set containing the Workspace's customization values.
-     * @param defStyle Unused.
-     */
-    public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mUsePagingTouchSlop = false;
-
-        // This means that we'll take care of updating the scroll parameter ourselves (we do it
-        // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
-        mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
-    }
-
-    protected int getScrollMode() {
-        return X_LARGE_MODE;
-    }
-
-    /**
-     * Initializes various states for this workspace.
-     */
-    @Override
-    protected void init() {
-        super.init();
-
-        mScrollMode = getScrollMode();
-        if (mScrollMode == DEFAULT_MODE) {
-            mBaseLineFlingVelocity = 2500.0f;
-            mFlingVelocityInfluence = 0.4f;
-            mScrollInterpolator = new OvershootInterpolator();
-            setDefaultInterpolator(mScrollInterpolator);
-        }
-    }
-
-    @Override
-    protected void snapToDestination() {
-        if (mScrollMode == X_LARGE_MODE) {
-            super.snapToDestination();
-        } else {
-            snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
-        }
-    }
-
-    @Override
-    protected void snapToPageWithVelocity(int whichPage, int velocity) {
-        if (mScrollMode == X_LARGE_MODE) {
-            super.snapToPageWithVelocity(whichPage, velocity);
-        } else {
-            snapToPageWithVelocity(whichPage, 0, true);
-        }
-    }
-
-    private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
-            // if (!mScroller.isFinished()) return;
-
-        whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
-
-        final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
-        final int newX = getScrollForPage(whichPage);
-        final int delta = newX - mUnboundedScrollX;
-        int duration = (screenDelta + 1) * 100;
-
-        if (!mScroller.isFinished()) {
-            mScroller.abortAnimation();
-        }
-
-        if (settle) {
-            ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
-        } else {
-            ((OvershootInterpolator) mScrollInterpolator).disableSettle();
-        }
-
-        velocity = Math.abs(velocity);
-        if (velocity > 0) {
-            duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
-        } else {
-            duration += 100;
-        }
-
-        snapToPage(whichPage, delta, duration);
-    }
-
-    @Override
-    protected void snapToPage(int whichPage) {
-       if (mScrollMode == X_LARGE_MODE) {
-           super.snapToPage(whichPage);
-       } else {
-           snapToPageWithVelocity(whichPage, 0, false);
-       }
-    }
-
-    @Override
-    public void computeScroll() {
-        if (mScrollMode == X_LARGE_MODE) {
-            super.computeScroll();
-        } else {
-            boolean scrollComputed = computeScrollHelper();
-
-            if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
-                final float now = System.nanoTime() / NANOTIME_DIV;
-                final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
-
-                final float dx = mTouchX - mUnboundedScrollX;
-                scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY());
-                mSmoothingTime = now;
-
-                // Keep generating points as long as we're more than 1px away from the target
-                if (dx > 1.f || dx < -1.f) {
-                    invalidate();
-                }
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java
index a879865..cb0e252 100644
--- a/src/com/android/launcher3/Stats.java
+++ b/src/com/android/launcher3/Stats.java
@@ -20,16 +20,64 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.os.Bundle;
 import android.util.Log;
-
-import java.io.*;
-import java.util.ArrayList;
+import android.view.View;
+import android.view.ViewParent;
 
 public class Stats {
-    private static final boolean DEBUG_BROADCASTS = false;
-    private static final String TAG = "Launcher3/Stats";
 
-    private static final boolean LOCAL_LAUNCH_LOG = true;
+    /**
+     * Implemented by containers to provide a launch source for a given child.
+     */
+    public interface LaunchSourceProvider {
+        void fillInLaunchSourceData(Bundle sourceData);
+    }
+
+    /**
+     * Helpers to add the source to a launch intent.
+     */
+    public static class LaunchSourceUtils {
+        /**
+         * Create a default bundle for LaunchSourceProviders to fill in their data.
+         */
+        public static Bundle createSourceData() {
+            Bundle sourceData = new Bundle();
+            sourceData.putString(SOURCE_EXTRA_CONTAINER, CONTAINER_HOMESCREEN);
+            // Have default container/sub container pages
+            sourceData.putInt(SOURCE_EXTRA_CONTAINER_PAGE, 0);
+            sourceData.putInt(SOURCE_EXTRA_SUB_CONTAINER_PAGE, 0);
+            return sourceData;
+        }
+
+        /**
+         * Finds the next launch source provider in the parents of the view hierarchy and populates
+         * the source data from that provider.
+         */
+        public static void populateSourceDataFromAncestorProvider(View v, Bundle sourceData) {
+            if (v == null) {
+                return;
+            }
+
+            Stats.LaunchSourceProvider provider = null;
+            ViewParent parent = v.getParent();
+            while (parent != null && parent instanceof View) {
+                if (parent instanceof Stats.LaunchSourceProvider) {
+                    provider = (Stats.LaunchSourceProvider) parent;
+                    break;
+                }
+                parent = parent.getParent();
+            }
+
+            if (provider != null) {
+                provider.fillInLaunchSourceData(sourceData);
+            } else if (LauncherAppState.isDogfoodBuild()) {
+                throw new RuntimeException("Expected LaunchSourceProvider");
+            }
+        }
+    }
+
+    private static final boolean DEBUG_BROADCASTS = false;
 
     public static final String ACTION_LAUNCH = "com.android.launcher3.action.LAUNCH";
     public static final String EXTRA_INTENT = "intent";
@@ -37,55 +85,37 @@
     public static final String EXTRA_SCREEN = "screen";
     public static final String EXTRA_CELLX = "cellX";
     public static final String EXTRA_CELLY = "cellY";
+    public static final String EXTRA_SOURCE = "source";
 
-    private static final int LOG_VERSION = 1;
-    private static final int LOG_TAG_VERSION = 0x1;
-    private static final int LOG_TAG_LAUNCH = 0x1000;
+    public static final String SOURCE_EXTRA_CONTAINER = "container";
+    public static final String SOURCE_EXTRA_CONTAINER_PAGE = "container_page";
+    public static final String SOURCE_EXTRA_SUB_CONTAINER = "sub_container";
+    public static final String SOURCE_EXTRA_SUB_CONTAINER_PAGE = "sub_container_page";
 
-    private static final int STATS_VERSION = 1;
-    private static final int INITIAL_STATS_SIZE = 100;
+    public static final String CONTAINER_SEARCH_BOX = "search_box";
+    public static final String CONTAINER_ALL_APPS = "all_apps";
+    public static final String CONTAINER_HOMESCREEN = "homescreen"; // aka. Workspace
+    public static final String CONTAINER_HOTSEAT = "hotseat";
 
-    // TODO: delayed/batched writes
-    private static final boolean FLUSH_IMMEDIATELY = true;
+    public static final String SUB_CONTAINER_FOLDER = "folder";
+    public static final String SUB_CONTAINER_ALL_APPS_A_Z = "a-z";
+    public static final String SUB_CONTAINER_ALL_APPS_PREDICTION = "prediction";
+    public static final String SUB_CONTAINER_ALL_APPS_SEARCH = "search";
 
     private final Launcher mLauncher;
-
     private final String mLaunchBroadcastPermission;
 
-    DataOutputStream mLog;
-
-    ArrayList<String> mIntents;
-    ArrayList<Integer> mHistogram;
-
     public Stats(Launcher launcher) {
         mLauncher = launcher;
-
         mLaunchBroadcastPermission =
                 launcher.getResources().getString(R.string.receive_launch_broadcasts_permission);
 
-        loadStats();
-
-        if (LOCAL_LAUNCH_LOG) {
-            try {
-                mLog = new DataOutputStream(mLauncher.openFileOutput(
-                        LauncherFiles.LAUNCHES_LOG, Context.MODE_APPEND));
-                mLog.writeInt(LOG_TAG_VERSION);
-                mLog.writeInt(LOG_VERSION);
-            } catch (FileNotFoundException e) {
-                Log.e(TAG, "unable to create stats log: " + e);
-                mLog = null;
-            } catch (IOException e) {
-                Log.e(TAG, "unable to write to stats log: " + e);
-                mLog = null;
-            }
-        }
-
         if (DEBUG_BROADCASTS) {
             launcher.registerReceiver(
                     new BroadcastReceiver() {
                         @Override
                         public void onReceive(Context context, Intent intent) {
-                            android.util.Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
+                            Log.v("Stats", "got broadcast: " + intent + " for launched intent: "
                                     + intent.getStringExtra(EXTRA_INTENT));
                         }
                     },
@@ -96,26 +126,11 @@
         }
     }
 
-    public void incrementLaunch(String intentStr) {
-        int pos = mIntents.indexOf(intentStr);
-        if (pos < 0) {
-            mIntents.add(intentStr);
-            mHistogram.add(1);
-        } else {
-            mHistogram.set(pos, mHistogram.get(pos) + 1);
-        }
-    }
-
-    public void recordLaunch(Intent intent) {
-        recordLaunch(intent, null);
-    }
-
-    public void recordLaunch(Intent intent, ShortcutInfo shortcut) {
+    public void recordLaunch(View v, Intent intent, ShortcutInfo shortcut) {
         intent = new Intent(intent);
         intent.setSourceBounds(null);
 
         final String flat = intent.toUri(0);
-
         Intent broadcastIntent = new Intent(ACTION_LAUNCH).putExtra(EXTRA_INTENT, flat);
         if (shortcut != null) {
             broadcastIntent.putExtra(EXTRA_CONTAINER, shortcut.container)
@@ -123,95 +138,10 @@
                     .putExtra(EXTRA_CELLX, shortcut.cellX)
                     .putExtra(EXTRA_CELLY, shortcut.cellY);
         }
+
+        Bundle sourceExtras = LaunchSourceUtils.createSourceData();
+        LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras);
+        broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras);
         mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission);
-
-        incrementLaunch(flat);
-
-        if (FLUSH_IMMEDIATELY) {
-            saveStats();
-        }
-
-        if (LOCAL_LAUNCH_LOG && mLog != null) {
-            try {
-                mLog.writeInt(LOG_TAG_LAUNCH);
-                mLog.writeLong(System.currentTimeMillis());
-                if (shortcut == null) {
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                    mLog.writeShort(0);
-                } else {
-                    mLog.writeShort((short) shortcut.container);
-                    mLog.writeShort((short) shortcut.screenId);
-                    mLog.writeShort((short) shortcut.cellX);
-                    mLog.writeShort((short) shortcut.cellY);
-                }
-                mLog.writeUTF(flat);
-                if (FLUSH_IMMEDIATELY) {
-                    mLog.flush(); // TODO: delayed writes
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    private void saveStats() {
-        DataOutputStream stats = null;
-        try {
-            stats = new DataOutputStream(mLauncher.openFileOutput(
-                    LauncherFiles.STATS_LOG + ".tmp", Context.MODE_PRIVATE));
-            stats.writeInt(STATS_VERSION);
-            final int N = mHistogram.size();
-            stats.writeInt(N);
-            for (int i=0; i<N; i++) {
-                stats.writeUTF(mIntents.get(i));
-                stats.writeInt(mHistogram.get(i));
-            }
-            stats.close();
-            stats = null;
-            mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG + ".tmp")
-                     .renameTo(mLauncher.getFileStreamPath(LauncherFiles.STATS_LOG));
-        } catch (FileNotFoundException e) {
-            Log.e(TAG, "unable to create stats data: " + e);
-        } catch (IOException e) {
-            Log.e(TAG, "unable to write to stats data: " + e);
-        } finally {
-            if (stats != null) {
-                try {
-                    stats.close();
-                } catch (IOException e) { }
-            }
-        }
-    }
-
-    private void loadStats() {
-        mIntents = new ArrayList<String>(INITIAL_STATS_SIZE);
-        mHistogram = new ArrayList<Integer>(INITIAL_STATS_SIZE);
-        DataInputStream stats = null;
-        try {
-            stats = new DataInputStream(mLauncher.openFileInput(LauncherFiles.STATS_LOG));
-            final int version = stats.readInt();
-            if (version == STATS_VERSION) {
-                final int N = stats.readInt();
-                for (int i=0; i<N; i++) {
-                    final String pkg = stats.readUTF();
-                    final int count = stats.readInt();
-                    mIntents.add(pkg);
-                    mHistogram.add(count);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            // not a problem
-        } catch (IOException e) {
-            // more of a problem
-
-        } finally {
-            if (stats != null) {
-                try {
-                    stats.close();
-                } catch (IOException e) { }
-            }
-        }
     }
 }
diff --git a/src/com/android/launcher3/StylusEventHelper.java b/src/com/android/launcher3/StylusEventHelper.java
new file mode 100644
index 0000000..da46e6a
--- /dev/null
+++ b/src/com/android/launcher3/StylusEventHelper.java
@@ -0,0 +1,84 @@
+package com.android.launcher3;
+
+import com.android.launcher3.Utilities;
+
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+/**
+ * Helper for identifying when a stylus touches a view while the primary stylus button is pressed.
+ * This can occur in {@value MotionEvent#ACTION_DOWN} or {@value MotionEvent#ACTION_MOVE}. On a
+ * stylus button press this performs the view's {@link View#performLongClick()} method, if the view
+ * is long clickable.
+ */
+public class StylusEventHelper {
+    private boolean mIsButtonPressed;
+    private View mView;
+
+    public StylusEventHelper(View view) {
+        mView = view;
+    }
+
+    /**
+     * Call this in onTouchEvent method of a view to identify a stylus button press and perform a
+     * long click (if the view is long clickable).
+     *
+     * @param event The event to check for a stylus button press.
+     * @return Whether a stylus event occurred and was handled.
+     */
+    public boolean checkAndPerformStylusEvent(MotionEvent event) {
+        final float slop = ViewConfiguration.get(mView.getContext()).getScaledTouchSlop();
+
+        if (!mView.isLongClickable()) {
+            // We don't do anything unless the view is long clickable.
+            return false;
+        }
+
+        final boolean stylusButtonPressed = isStylusButtonPressed(event);
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mIsButtonPressed = false;
+                if (stylusButtonPressed && mView.performLongClick()) {
+                    mIsButtonPressed = true;
+                    return true;
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (Utilities.pointInView(mView, event.getX(), event.getY(), slop)) {
+                    if (!mIsButtonPressed && stylusButtonPressed && mView.performLongClick()) {
+                        mIsButtonPressed = true;
+                        return true;
+                    } else if (mIsButtonPressed && !stylusButtonPressed) {
+                        mIsButtonPressed = false;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mIsButtonPressed = false;
+                break;
+        }
+        return false;
+    }
+
+    /**
+     * Whether a stylus button press is occurring.
+     */
+    public boolean inStylusButtonPressed() {
+        return mIsButtonPressed;
+    }
+
+    /**
+     * Identifies if the provided {@link MotionEvent} is a stylus with the primary stylus button
+     * pressed.
+     *
+     * @param event The event to check.
+     * @return Whether a stylus button press occurred.
+     */
+    public static boolean isStylusButtonPressed(MotionEvent event) {
+        return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS
+                && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
new file mode 100644
index 0000000..0819f8c
--- /dev/null
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -0,0 +1,132 @@
+package com.android.launcher3;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.util.Pair;
+import com.android.launcher3.R;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.Thunk;
+
+public class UninstallDropTarget extends ButtonDropTarget {
+
+    public UninstallDropTarget(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public UninstallDropTarget(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        // Get the hover color
+        mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
+
+        setDrawable(R.drawable.ic_uninstall_launcher);
+    }
+
+    @Override
+    protected boolean supportsDrop(DragSource source, Object info) {
+        return supportsDrop(getContext(), info);
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+    public static boolean supportsDrop(Context context, Object info) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+            Bundle restrictions = userManager.getUserRestrictions();
+            if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
+                    || restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
+                return false;
+            }
+        }
+
+        Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
+        return componentInfo != null && (componentInfo.second & AppInfo.DOWNLOADED_FLAG) != 0;
+    }
+
+    /**
+     * @return the component name and flags if {@param info} is an AppInfo or an app shortcut.
+     */
+    private static Pair<ComponentName, Integer> getAppInfoFlags(Object item) {
+        if (item instanceof AppInfo) {
+            AppInfo info = (AppInfo) item;
+            return Pair.create(info.componentName, info.flags);
+        } else if (item instanceof ShortcutInfo) {
+            ShortcutInfo info = (ShortcutInfo) item;
+            ComponentName component = info.getTargetComponent();
+            if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION
+                    && component != null) {
+                return Pair.create(component, info.flags);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void onDrop(DragObject d) {
+        // Differ item deletion
+        if (d.dragSource instanceof UninstallSource) {
+            ((UninstallSource) d.dragSource).deferCompleteDropAfterUninstallActivity();
+        }
+        super.onDrop(d);
+    }
+
+    @Override
+    void completeDrop(final DragObject d) {
+        final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
+        final UserHandleCompat user = ((ItemInfo) d.dragInfo).user;
+        if (startUninstallActivity(mLauncher, d.dragInfo)) {
+
+            final Runnable checkIfUninstallWasSuccess = new Runnable() {
+                @Override
+                public void run() {
+                    String packageName = componentInfo.first.getPackageName();
+                    boolean uninstallSuccessful = !AllAppsList.packageHasActivities(
+                            getContext(), packageName, user);
+                    sendUninstallResult(d.dragSource, uninstallSuccessful);
+                }
+            };
+            mLauncher.addOnResumeCallback(checkIfUninstallWasSuccess);
+        } else {
+            sendUninstallResult(d.dragSource, false);
+        }
+    }
+
+    public static boolean startUninstallActivity(Launcher launcher, Object info) {
+        final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
+        final UserHandleCompat user = ((ItemInfo) info).user;
+        return launcher.startApplicationUninstallActivity(
+                componentInfo.first, componentInfo.second, user);
+    }
+
+    @Thunk void sendUninstallResult(DragSource target, boolean result) {
+        if (target instanceof UninstallSource) {
+            ((UninstallSource) target).onUninstallActivityReturned(result);
+        }
+    }
+
+    /**
+     * Interface defining an object that can provide uninstallable drag objects.
+     */
+    public static interface UninstallSource {
+
+        /**
+         * A pending uninstall operation was complete.
+         * @param result true if uninstall was successful, false otherwise.
+         */
+        void onUninstallActivityReturned(boolean result);
+
+        /**
+         * Indicates that an uninstall request are made and the actual result may come
+         * after some time.
+         */
+        void deferCompleteDropAfterUninstallActivity();
+    }
+}
diff --git a/src/com/android/launcher3/UninstallShortcutReceiver.java b/src/com/android/launcher3/UninstallShortcutReceiver.java
deleted file mode 100644
index ccea4ec..0000000
--- a/src/com/android/launcher3/UninstallShortcutReceiver.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.widget.Toast;
-
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-public class UninstallShortcutReceiver extends BroadcastReceiver {
-    private static final String ACTION_UNINSTALL_SHORTCUT =
-            "com.android.launcher.action.UNINSTALL_SHORTCUT";
-
-    // The set of shortcuts that are pending uninstall
-    private static ArrayList<PendingUninstallShortcutInfo> mUninstallQueue =
-            new ArrayList<PendingUninstallShortcutInfo>();
-
-    // Determines whether to defer uninstalling shortcuts immediately until
-    // disableAndFlushUninstallQueue() is called.
-    private static boolean mUseUninstallQueue = false;
-
-    private static class PendingUninstallShortcutInfo {
-        Intent data;
-
-        public PendingUninstallShortcutInfo(Intent rawData) {
-            data = rawData;
-        }
-    }
-
-    public void onReceive(Context context, Intent data) {
-        if (!ACTION_UNINSTALL_SHORTCUT.equals(data.getAction())) {
-            return;
-        }
-
-        PendingUninstallShortcutInfo info = new PendingUninstallShortcutInfo(data);
-        if (mUseUninstallQueue) {
-            mUninstallQueue.add(info);
-        } else {
-            processUninstallShortcut(context, info);
-        }
-    }
-
-    static void enableUninstallQueue() {
-        mUseUninstallQueue = true;
-    }
-
-    static void disableAndFlushUninstallQueue(Context context) {
-        mUseUninstallQueue = false;
-        Iterator<PendingUninstallShortcutInfo> iter = mUninstallQueue.iterator();
-        while (iter.hasNext()) {
-            processUninstallShortcut(context, iter.next());
-            iter.remove();
-        }
-    }
-
-    private static void processUninstallShortcut(Context context,
-            PendingUninstallShortcutInfo pendingInfo) {
-        final Intent data = pendingInfo.data;
-
-        LauncherAppState.setApplicationContext(context.getApplicationContext());
-        LauncherAppState app = LauncherAppState.getInstance();
-        synchronized (app) { // TODO: make removeShortcut internally threadsafe
-            removeShortcut(context, data);
-        }
-    }
-
-    private static void removeShortcut(Context context, Intent data) {
-        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
-        String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-        boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
-
-        if (intent != null && name != null) {
-            final ContentResolver cr = context.getContentResolver();
-            Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
-                new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT },
-                LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null);
-
-            final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
-            final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
-
-            boolean changed = false;
-
-            try {
-                while (c.moveToNext()) {
-                    try {
-                        if (intent.filterEquals(Intent.parseUri(c.getString(intentIndex), 0))) {
-                            final long id = c.getLong(idIndex);
-                            final Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
-                            cr.delete(uri, null, null);
-                            changed = true;
-                            if (!duplicate) {
-                                break;
-                            }
-                        }
-                    } catch (URISyntaxException e) {
-                        // Ignore
-                    }
-                }
-            } finally {
-                c.close();
-            }
-
-            if (changed) {
-                cr.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null);
-                Toast.makeText(context, context.getString(R.string.shortcut_uninstalled, name),
-                        Toast.LENGTH_SHORT).show();
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/UserInitializeReceiver.java b/src/com/android/launcher3/UserInitializeReceiver.java
deleted file mode 100644
index d8e17b1..0000000
--- a/src/com/android/launcher3/UserInitializeReceiver.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Takes care of setting initial wallpaper for a user, by selecting the
- * first wallpaper that is not in use by another user.
- */
-public class UserInitializeReceiver extends BroadcastReceiver {
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        // TODO: initial wallpaper now that wallpapers are owned by another app
-    }
-}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 215d63d..8fd298d 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -25,13 +25,16 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
+import android.database.Cursor;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -42,26 +45,38 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
 import android.os.Build;
+import android.os.Bundle;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.Toast;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Various utilities shared amongst the Launcher's classes.
  */
 public final class Utilities {
-    private static final String TAG = "Launcher.Utilities";
 
-    private static int sIconWidth = -1;
-    private static int sIconHeight = -1;
+    private static final String TAG = "Launcher.Utilities";
 
     private static final Rect sOldBounds = new Rect();
     private static final Canvas sCanvas = new Canvas();
 
+    private static final Pattern sTrimPattern =
+            Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$");
+
     static {
         sCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
                 Paint.FILTER_BITMAP_FLAG));
@@ -69,39 +84,30 @@
     static int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
     static int sColorIndex = 0;
 
-    static int[] sLoc0 = new int[2];
-    static int[] sLoc1 = new int[2];
+    private static final int[] sLoc0 = new int[2];
+    private static final int[] sLoc1 = new int[2];
 
     // To turn on these properties, type
     // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS]
-    static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
-    public static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
+    private static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate";
+    private static boolean sForceEnableRotation = isPropertyEnabled(FORCE_ENABLE_ROTATION_PROPERTY);
 
-    /**
-     * Returns a FastBitmapDrawable with the icon, accurately sized.
-     */
-    public static FastBitmapDrawable createIconDrawable(Bitmap icon) {
-        FastBitmapDrawable d = new FastBitmapDrawable(icon);
-        d.setFilterBitmap(true);
-        resizeIconDrawable(d);
-        return d;
-    }
-
-    /**
-     * Resizes an icon drawable to the correct icon size.
-     */
-    static void resizeIconDrawable(Drawable icon) {
-        icon.setBounds(0, 0, sIconWidth, sIconHeight);
-    }
+    public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
 
     public static boolean isPropertyEnabled(String propertyName) {
         return Log.isLoggable(propertyName, Log.VERBOSE);
     }
 
-    public static boolean isRotationEnabled(Context c) {
-        boolean enableRotation = sForceEnableRotation ||
-                c.getResources().getBoolean(R.bool.allow_rotation);
-        return enableRotation;
+    public static boolean isAllowRotationPrefEnabled(Context context, boolean multiProcess) {
+        SharedPreferences sharedPrefs = context.getSharedPreferences(
+                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE | (multiProcess ?
+                        Context.MODE_MULTI_PROCESS : 0));
+        boolean allowRotationPref = sharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, false);
+        return sForceEnableRotation || allowRotationPref;
+    }
+
+    public static boolean isRotationAllowedForDevice(Context context) {
+        return sForceEnableRotation || context.getResources().getBoolean(R.bool.allow_rotation);
     }
 
     /**
@@ -111,11 +117,30 @@
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
     }
 
+    public static boolean isLmpMR1OrAbove() {
+        // TODO(adamcohen): update to Build.VERSION_CODES.LOLLIPOP_MR1 once building against 22;
+        return Build.VERSION.SDK_INT >= 22;
+    }
+
+    public static boolean isLmpMR1() {
+        // TODO(adamcohen): update to Build.VERSION_CODES.LOLLIPOP_MR1 once building against 22;
+        return Build.VERSION.SDK_INT == 22;
+    }
+
+    public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
+        byte[] data = c.getBlob(iconIndex);
+        try {
+            return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     /**
      * Returns a bitmap suitable for the all apps view. If the package or the resource do not
      * exist, it returns null.
      */
-    static Bitmap createIconBitmap(String packageName, String resourceName, IconCache cache,
+    public static Bitmap createIconBitmap(String packageName, String resourceName,
             Context context) {
         PackageManager packageManager = context.getPackageManager();
         // the resource
@@ -124,7 +149,8 @@
             if (resources != null) {
                 final int id = resources.getIdentifier(resourceName, null, null);
                 return createIconBitmap(
-                        resources.getDrawableForDensity(id, cache.getFullResIconDpi()), context);
+                        resources.getDrawableForDensity(id, LauncherAppState.getInstance()
+                                .getInvariantDeviceProfile().fillResIconDpi), context);
             }
         } catch (Exception e) {
             // Icon not found.
@@ -132,16 +158,16 @@
         return null;
     }
 
+    private static int getIconBitmapSize() {
+        return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+    }
+
     /**
      * Returns a bitmap which is of the appropriate size to be displayed as an icon
      */
-    static Bitmap createIconBitmap(Bitmap icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
-        }
-        if (sIconWidth == icon.getWidth() && sIconHeight == icon.getHeight()) {
+    public static Bitmap createIconBitmap(Bitmap icon, Context context) {
+        final int iconBitmapSize = getIconBitmapSize();
+        if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
             return icon;
         }
         return createIconBitmap(new BitmapDrawable(context.getResources(), icon), context);
@@ -151,13 +177,11 @@
      * Returns a bitmap suitable for the all apps view.
      */
     public static Bitmap createIconBitmap(Drawable icon, Context context) {
-        synchronized (sCanvas) { // we share the statics :-(
-            if (sIconWidth == -1) {
-                initStatics(context);
-            }
+        synchronized (sCanvas) {
+            final int iconBitmapSize = getIconBitmapSize();
 
-            int width = sIconWidth;
-            int height = sIconHeight;
+            int width = iconBitmapSize;
+            int height = iconBitmapSize;
 
             if (icon instanceof PaintDrawable) {
                 PaintDrawable painter = (PaintDrawable) icon;
@@ -184,8 +208,8 @@
             }
 
             // no intrinsic size --> use default size
-            int textureWidth = sIconWidth;
-            int textureHeight = sIconHeight;
+            int textureWidth = iconBitmapSize;
+            int textureHeight = iconBitmapSize;
 
             final Bitmap bitmap = Bitmap.createBitmap(textureWidth, textureHeight,
                     Bitmap.Config.ARGB_8888);
@@ -315,15 +339,6 @@
                 localY < (v.getHeight() + slop);
     }
 
-    private static void initStatics(Context context) {
-        final Resources resources = context.getResources();
-        sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
-    }
-
-    public static void setIconSize(int widthPx) {
-        sIconWidth = sIconHeight = widthPx;
-    }
-
     public static void scaleRect(Rect r, float scale) {
         if (scale != 1.0f) {
             r.left = (int) (r.left * scale + 0.5f);
@@ -542,4 +557,156 @@
         }
         return defaultWidgetForSearchPackage;
     }
+
+    /**
+     * Compresses the bitmap to a byte array for serialization.
+     */
+    public static byte[] flattenBitmap(Bitmap bitmap) {
+        // Try go guesstimate how much space the icon will take when serialized
+        // to avoid unnecessary allocations/copies during the write.
+        int size = bitmap.getWidth() * bitmap.getHeight() * 4;
+        ByteArrayOutputStream out = new ByteArrayOutputStream(size);
+        try {
+            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+            out.flush();
+            out.close();
+            return out.toByteArray();
+        } catch (IOException e) {
+            Log.w(TAG, "Could not write bitmap");
+            return null;
+        }
+    }
+
+    /**
+     * Find the first vacant cell, if there is one.
+     *
+     * @param vacant Holds the x and y coordinate of the vacant cell
+     * @param spanX Horizontal cell span.
+     * @param spanY Vertical cell span.
+     *
+     * @return true if a vacant cell was found
+     */
+    public static boolean findVacantCell(int[] vacant, int spanX, int spanY,
+            int xCount, int yCount, boolean[][] occupied) {
+
+        for (int y = 0; (y + spanY) <= yCount; y++) {
+            for (int x = 0; (x + spanX) <= xCount; x++) {
+                boolean available = !occupied[x][y];
+                out:            for (int i = x; i < x + spanX; i++) {
+                    for (int j = y; j < y + spanY; j++) {
+                        available = available && !occupied[i][j];
+                        if (!available) break out;
+                    }
+                }
+
+                if (available) {
+                    vacant[0] = x;
+                    vacant[1] = y;
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Trims the string, removing all whitespace at the beginning and end of the string.
+     * Non-breaking whitespaces are also removed.
+     */
+    public static String trim(CharSequence s) {
+        if (s == null) {
+            return null;
+        }
+
+        // Just strip any sequence of whitespace or java space characters from the beginning and end
+        Matcher m = sTrimPattern.matcher(s);
+        return m.replaceAll("$1");
+    }
+
+    /**
+     * Calculates the height of a given string at a specific text size.
+     */
+    public static float calculateTextHeight(float textSizePx) {
+        Paint p = new Paint();
+        p.setTextSize(textSizePx);
+        Paint.FontMetrics fm = p.getFontMetrics();
+        return -fm.top + fm.bottom;
+    }
+
+    /**
+     * Convenience println with multiple args.
+     */
+    public static void println(String key, Object... args) {
+        StringBuilder b = new StringBuilder();
+        b.append(key);
+        b.append(": ");
+        boolean isFirstArgument = true;
+        for (Object arg : args) {
+            if (isFirstArgument) {
+                isFirstArgument = false;
+            } else {
+                b.append(", ");
+            }
+            b.append(arg);
+        }
+        System.out.println(b.toString());
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    public static boolean isRtl(Resources res) {
+        return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) &&
+                (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
+    }
+
+    public static void assertWorkerThread() {
+        if (LauncherAppState.isDogfoodBuild() &&
+                (LauncherModel.sWorkerThread.getThreadId() != Process.myTid())) {
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * Returns true if the intent is a valid launch intent for a launcher activity of an app.
+     * This is used to identify shortcuts which are different from the ones exposed by the
+     * applications' manifest file.
+     *
+     * @param launchIntent The intent that will be launched when the shortcut is clicked.
+     */
+    public static boolean isLauncherAppTarget(Intent launchIntent) {
+        if (launchIntent != null
+                && Intent.ACTION_MAIN.equals(launchIntent.getAction())
+                && launchIntent.getComponent() != null
+                && launchIntent.getCategories() != null
+                && launchIntent.getCategories().size() == 1
+                && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
+                && TextUtils.isEmpty(launchIntent.getDataString())) {
+            // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE.
+            Bundle extras = launchIntent.getExtras();
+            if (extras == null) {
+                return true;
+            } else {
+                Set<String> keys = extras.keySet();
+                return keys.size() == 1 && keys.contains(ItemInfo.EXTRA_PROFILE);
+            }
+        };
+        return false;
+    }
+
+    public static float dpiFromPx(int size, DisplayMetrics metrics){
+        float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+        return (size / densityRatio);
+    }
+    public static int pxFromDp(float size, DisplayMetrics metrics) {
+        return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                size, metrics));
+    }
+    public static int pxFromSp(float size, DisplayMetrics metrics) {
+        return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                size, metrics));
+    }
+
+    public static String createDbSelectionQuery(String columnName, Iterable<?> values) {
+        return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, TextUtils.join(", ", values));
+    }
 }
diff --git a/src/com/android/launcher3/WeightWatcher.java b/src/com/android/launcher3/WeightWatcher.java
index 70b8afe..7568479 100644
--- a/src/com/android/launcher3/WeightWatcher.java
+++ b/src/com/android/launcher3/WeightWatcher.java
@@ -34,6 +34,8 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.util.Thunk;
+
 public class WeightWatcher extends LinearLayout {
     private static final int RAM_GRAPH_RSS_COLOR = 0xFF990000;
     private static final int RAM_GRAPH_PSS_COLOR = 0xFF99CC00;
@@ -81,7 +83,7 @@
             }
         }
     };
-    private MemoryTracker mMemoryService;
+    @Thunk MemoryTracker mMemoryService;
 
     public WeightWatcher(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -134,7 +136,7 @@
         GraphView mRamGraph;
         TextView mText;
         int mPid;
-        private MemoryTracker.ProcessMemInfo mMemInfo;
+        @Thunk MemoryTracker.ProcessMemInfo mMemInfo;
 
         public ProcessWatcher(Context context) {
             this(context, null);
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 4e6fe1f..629387e 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -1,526 +1,353 @@
 package com.android.launcher3;
 
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.database.sqlite.SQLiteCantOpenDatabaseException;
+import android.database.SQLException;
 import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDiskIOException;
 import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteReadOnlyDatabaseException;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.BitmapFactory;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
-import android.graphics.Shader;
+import android.graphics.RectF;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
-import android.os.Build;
+import android.os.Handler;
 import android.util.Log;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
+import android.util.LongSparseArray;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.lang.ref.SoftReference;
-import java.lang.ref.WeakReference;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetCell;
+
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
+import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 
 public class WidgetPreviewLoader {
 
-    private static abstract class SoftReferenceThreadLocal<T> {
-        private ThreadLocal<SoftReference<T>> mThreadLocal;
-        public SoftReferenceThreadLocal() {
-            mThreadLocal = new ThreadLocal<SoftReference<T>>();
-        }
-
-        abstract T initialValue();
-
-        public void set(T t) {
-            mThreadLocal.set(new SoftReference<T>(t));
-        }
-
-        public T get() {
-            SoftReference<T> reference = mThreadLocal.get();
-            T obj;
-            if (reference == null) {
-                obj = initialValue();
-                mThreadLocal.set(new SoftReference<T>(obj));
-                return obj;
-            } else {
-                obj = reference.get();
-                if (obj == null) {
-                    obj = initialValue();
-                    mThreadLocal.set(new SoftReference<T>(obj));
-                }
-                return obj;
-            }
-        }
-    }
-
-    private static class CanvasCache extends SoftReferenceThreadLocal<Canvas> {
-        @Override
-        protected Canvas initialValue() {
-            return new Canvas();
-        }
-    }
-
-    private static class PaintCache extends SoftReferenceThreadLocal<Paint> {
-        @Override
-        protected Paint initialValue() {
-            return null;
-        }
-    }
-
-    private static class BitmapCache extends SoftReferenceThreadLocal<Bitmap> {
-        @Override
-        protected Bitmap initialValue() {
-            return null;
-        }
-    }
-
-    private static class RectCache extends SoftReferenceThreadLocal<Rect> {
-        @Override
-        protected Rect initialValue() {
-            return new Rect();
-        }
-    }
-
-    private static class BitmapFactoryOptionsCache extends
-            SoftReferenceThreadLocal<BitmapFactory.Options> {
-        @Override
-        protected BitmapFactory.Options initialValue() {
-            return new BitmapFactory.Options();
-        }
-    }
-
     private static final String TAG = "WidgetPreviewLoader";
-    private static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version";
+    private static final boolean DEBUG = false;
 
     private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
-    private static final HashSet<String> sInvalidPackages = new HashSet<String>();
 
-    // Used for drawing shortcut previews
-    private final BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache();
-    private final PaintCache mCachedShortcutPreviewPaint = new PaintCache();
-    private final CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache();
+    private final HashMap<String, long[]> mPackageVersions = new HashMap<>();
 
-    // Used for drawing widget previews
-    private final CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache();
-    private final RectCache mCachedAppWidgetPreviewSrcRect = new RectCache();
-    private final RectCache mCachedAppWidgetPreviewDestRect = new RectCache();
-    private final PaintCache mCachedAppWidgetPreviewPaint = new PaintCache();
-    private final PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache();
-    private final BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache();
-
-    private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>();
-    private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>();
+    /**
+     * Weak reference objects, do not prevent their referents from being made finalizable,
+     * finalized, and then reclaimed.
+     * Note: synchronized block used for this variable is expensive and the block should always
+     * be posted to a background thread.
+     */
+    @Thunk final Set<Bitmap> mUnusedBitmaps =
+            Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>());
 
     private final Context mContext;
-    private final int mAppIconSize;
     private final IconCache mIconCache;
+    private final UserManagerCompat mUserManager;
     private final AppWidgetManagerCompat mManager;
-
-    private int mPreviewBitmapWidth;
-    private int mPreviewBitmapHeight;
-    private String mSize;
-    private PagedViewCellLayout mWidgetSpacingLayout;
-
-    private String mCachedSelectQuery;
-
-
-    private CacheDb mDb;
+    private final CacheDb mDb;
+    private final int mProfileBadgeMargin;
 
     private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
+    @Thunk final Handler mWorkerHandler;
 
-    public WidgetPreviewLoader(Context context) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
+    public WidgetPreviewLoader(Context context, IconCache iconCache) {
         mContext = context;
-        mAppIconSize = grid.iconSizePx;
-        mIconCache = app.getIconCache();
+        mIconCache = iconCache;
         mManager = AppWidgetManagerCompat.getInstance(context);
-
-        mDb = app.getWidgetPreviewCacheDb();
-
-        SharedPreferences sp = context.getSharedPreferences(
-                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
-        final String lastVersionName = sp.getString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, null);
-        final String versionName = android.os.Build.VERSION.INCREMENTAL;
-        final boolean isLollipopOrGreater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
-        if (!versionName.equals(lastVersionName)) {
-            try {
-                // clear all the previews whenever the system version changes, to ensure that
-                // previews are up-to-date for any apps that might have been updated with the system
-                clearDb();
-            } catch (SQLiteReadOnlyDatabaseException e) {
-                if (isLollipopOrGreater) {
-                    // Workaround for Bug. 18554839, if we fail to clear the db due to the read-only
-                    // issue, then ignore this error and leave the old previews
-                } else {
-                    throw e;
-                }
-            } finally {
-                SharedPreferences.Editor editor = sp.edit();
-                editor.putString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, versionName);
-                editor.commit();
-            }
-        }
+        mUserManager = UserManagerCompat.getInstance(context);
+        mDb = new CacheDb(context);
+        mWorkerHandler = new Handler(LauncherModel.getWorkerLooper());
+        mProfileBadgeMargin = context.getResources()
+                .getDimensionPixelSize(R.dimen.profile_badge_margin);
     }
 
-    public void recreateDb() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        app.recreateWidgetPreviewDb();
-        mDb = app.getWidgetPreviewCacheDb();
+    /**
+     * Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be
+     * called on UI thread
+     *
+     * @param o either {@link LauncherAppWidgetProviderInfo} or {@link ResolveInfo}
+     * @return a request id which can be used to cancel the request.
+     */
+    public PreviewLoadRequest getPreview(final Object o, int previewWidth,
+            int previewHeight, WidgetCell caller) {
+        String size = previewWidth + "x" + previewHeight;
+        WidgetCacheKey key = getObjectKey(o, size);
+
+        PreviewLoadTask task = new PreviewLoadTask(key, o, previewWidth, previewHeight, caller);
+        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        return new PreviewLoadRequest(task);
     }
 
-    public void setPreviewSize(int previewWidth, int previewHeight,
-            PagedViewCellLayout widgetSpacingLayout) {
-        mPreviewBitmapWidth = previewWidth;
-        mPreviewBitmapHeight = previewHeight;
-        mSize = previewWidth + "x" + previewHeight;
-        mWidgetSpacingLayout = widgetSpacingLayout;
-    }
+    /**
+     * The DB holds the generated previews for various components. Previews can also have different
+     * sizes (landscape vs portrait).
+     */
+    private static class CacheDb extends SQLiteOpenHelper {
+        private static final int DB_VERSION = 3;
 
-    public Bitmap getPreview(final Object o) {
-        final String name = getObjectName(o);
-        final String packageName = getObjectPackage(o);
-        // check if the package is valid
-        synchronized(sInvalidPackages) {
-            boolean packageValid = !sInvalidPackages.contains(packageName);
-            if (!packageValid) {
-                return null;
-            }
-        }
-        synchronized(mLoadedPreviews) {
-            // check if it exists in our existing cache
-            if (mLoadedPreviews.containsKey(name)) {
-                WeakReference<Bitmap> bitmapReference = mLoadedPreviews.get(name);
-                Bitmap bitmap = bitmapReference.get();
-                if (bitmap != null) {
-                    return bitmap;
-                }
-            }
-        }
-
-        Bitmap unusedBitmap = null;
-        synchronized(mUnusedBitmaps) {
-            // not in cache; we need to load it from the db
-            while (unusedBitmap == null && mUnusedBitmaps.size() > 0) {
-                Bitmap candidate = mUnusedBitmaps.remove(0).get();
-                if (candidate != null && candidate.isMutable() &&
-                        candidate.getWidth() == mPreviewBitmapWidth &&
-                        candidate.getHeight() == mPreviewBitmapHeight) {
-                    unusedBitmap = candidate;
-                }
-            }
-            if (unusedBitmap != null) {
-                final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-                c.setBitmap(unusedBitmap);
-                c.drawColor(0, PorterDuff.Mode.CLEAR);
-                c.setBitmap(null);
-            }
-        }
-
-        if (unusedBitmap == null) {
-            unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight,
-                    Bitmap.Config.ARGB_8888);
-        }
-        Bitmap preview = readFromDb(name, unusedBitmap);
-
-        if (preview != null) {
-            synchronized(mLoadedPreviews) {
-                mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
-            }
-            return preview;
-        } else {
-            // it's not in the db... we need to generate it
-            final Bitmap generatedPreview = generatePreview(o, unusedBitmap);
-            preview = generatedPreview;
-            if (preview != unusedBitmap) {
-                throw new RuntimeException("generatePreview is not recycling the bitmap " + o);
-            }
-
-            synchronized(mLoadedPreviews) {
-                mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview));
-            }
-
-            // write to db on a thread pool... this can be done lazily and improves the performance
-            // of the first time widget previews are loaded
-            new AsyncTask<Void, Void, Void>() {
-                public Void doInBackground(Void ... args) {
-                    writeToDb(o, generatedPreview);
-                    return null;
-                }
-            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
-
-            return preview;
-        }
-    }
-
-    public void recycleBitmap(Object o, Bitmap bitmapToRecycle) {
-        String name = getObjectName(o);
-        synchronized (mLoadedPreviews) {
-            if (mLoadedPreviews.containsKey(name)) {
-                Bitmap b = mLoadedPreviews.get(name).get();
-                if (b == bitmapToRecycle) {
-                    mLoadedPreviews.remove(name);
-                    if (bitmapToRecycle.isMutable()) {
-                        synchronized (mUnusedBitmaps) {
-                            mUnusedBitmaps.add(new SoftReference<Bitmap>(b));
-                        }
-                    }
-                } else {
-                    throw new RuntimeException("Bitmap passed in doesn't match up");
-                }
-            }
-        }
-    }
-
-    static class CacheDb extends SQLiteOpenHelper {
-        final static int DB_VERSION = 2;
-        final static String TABLE_NAME = "shortcut_and_widget_previews";
-        final static String COLUMN_NAME = "name";
-        final static String COLUMN_SIZE = "size";
-        final static String COLUMN_PREVIEW_BITMAP = "preview_bitmap";
-        Context mContext;
+        private static final String TABLE_NAME = "shortcut_and_widget_previews";
+        private static final String COLUMN_COMPONENT = "componentName";
+        private static final String COLUMN_USER = "profileId";
+        private static final String COLUMN_SIZE = "size";
+        private static final String COLUMN_PACKAGE = "packageName";
+        private static final String COLUMN_LAST_UPDATED = "lastUpdated";
+        private static final String COLUMN_VERSION = "version";
+        private static final String COLUMN_PREVIEW_BITMAP = "preview_bitmap";
 
         public CacheDb(Context context) {
-            super(context, new File(context.getCacheDir(),
-                    LauncherFiles.WIDGET_PREVIEWS_DB).getPath(), null, DB_VERSION);
-            // Store the context for later use
-            mContext = context;
+            super(context, LauncherFiles.WIDGET_PREVIEWS_DB, null, DB_VERSION);
         }
 
         @Override
         public void onCreate(SQLiteDatabase database) {
             database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
-                    COLUMN_NAME + " TEXT NOT NULL, " +
+                    COLUMN_COMPONENT + " TEXT NOT NULL, " +
+                    COLUMN_USER + " INTEGER NOT NULL, " +
                     COLUMN_SIZE + " TEXT NOT NULL, " +
-                    COLUMN_PREVIEW_BITMAP + " BLOB NOT NULL, " +
-                    "PRIMARY KEY (" + COLUMN_NAME + ", " + COLUMN_SIZE + ") " +
+                    COLUMN_PACKAGE + " TEXT NOT NULL, " +
+                    COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " +
+                    COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " +
+                    COLUMN_PREVIEW_BITMAP + " BLOB, " +
+                    "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ", " + COLUMN_SIZE + ") " +
                     ");");
         }
 
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
             if (oldVersion != newVersion) {
-                // Delete all the records; they'll be repopulated as this is a cache
-                db.execSQL("DELETE FROM " + TABLE_NAME);
+                clearDB(db);
             }
         }
+
+        @Override
+        public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            if (oldVersion != newVersion) {
+                clearDB(db);
+            }
+        }
+
+        private void clearDB(SQLiteDatabase db) {
+            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
+            onCreate(db);
+        }
     }
 
-    private static final String WIDGET_PREFIX = "Widget:";
-    private static final String SHORTCUT_PREFIX = "Shortcut:";
-
-    private static String getObjectName(Object o) {
+    private WidgetCacheKey getObjectKey(Object o, String size) {
         // should cache the string builder
-        StringBuilder sb = new StringBuilder();
-        String output;
-        if (o instanceof AppWidgetProviderInfo) {
-            sb.append(WIDGET_PREFIX);
-            sb.append(((AppWidgetProviderInfo) o).toString());
-            output = sb.toString();
-            sb.setLength(0);
-        } else {
-            sb.append(SHORTCUT_PREFIX);
-
-            ResolveInfo info = (ResolveInfo) o;
-            sb.append(new ComponentName(info.activityInfo.packageName,
-                    info.activityInfo.name).flattenToString());
-            output = sb.toString();
-            sb.setLength(0);
-        }
-        return output;
-    }
-
-    private String getObjectPackage(Object o) {
-        if (o instanceof AppWidgetProviderInfo) {
-            return ((AppWidgetProviderInfo) o).provider.getPackageName();
+        if (o instanceof LauncherAppWidgetProviderInfo) {
+            LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) o;
+            return new WidgetCacheKey(info.provider, mManager.getUser(info), size);
         } else {
             ResolveInfo info = (ResolveInfo) o;
-            return info.activityInfo.packageName;
+            return new WidgetCacheKey(
+                    new ComponentName(info.activityInfo.packageName, info.activityInfo.name),
+                    UserHandleCompat.myUserHandle(), size);
         }
     }
 
-    private void writeToDb(Object o, Bitmap preview) {
-        String name = getObjectName(o);
-        SQLiteDatabase db = mDb.getWritableDatabase();
+    @Thunk void writeToDb(WidgetCacheKey key, long[] versions, Bitmap preview) {
         ContentValues values = new ContentValues();
+        values.put(CacheDb.COLUMN_COMPONENT, key.componentName.flattenToShortString());
+        values.put(CacheDb.COLUMN_USER, mUserManager.getSerialNumberForUser(key.user));
+        values.put(CacheDb.COLUMN_SIZE, key.size);
+        values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName());
+        values.put(CacheDb.COLUMN_VERSION, versions[0]);
+        values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]);
+        values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview));
 
-        values.put(CacheDb.COLUMN_NAME, name);
-        ByteArrayOutputStream stream = new ByteArrayOutputStream();
-        preview.compress(Bitmap.CompressFormat.PNG, 100, stream);
-        values.put(CacheDb.COLUMN_PREVIEW_BITMAP, stream.toByteArray());
-        values.put(CacheDb.COLUMN_SIZE, mSize);
         try {
-            db.insert(CacheDb.TABLE_NAME, null, values);
-        } catch (SQLiteDiskIOException e) {
-            recreateDb();
-        } catch (SQLiteCantOpenDatabaseException e) {
-            dumpOpenFiles();
-            throw e;
+            mDb.getWritableDatabase().insertWithOnConflict(CacheDb.TABLE_NAME, null, values,
+                    SQLiteDatabase.CONFLICT_REPLACE);
+        } catch (SQLException e) {
+            Log.e(TAG, "Error saving image to DB", e);
         }
     }
 
-    private void clearDb() {
-        SQLiteDatabase db = mDb.getWritableDatabase();
-        // Delete everything
+    public void removePackage(String packageName, UserHandleCompat user) {
+        removePackage(packageName, user, mUserManager.getSerialNumberForUser(user));
+    }
+
+    private void removePackage(String packageName, UserHandleCompat user, long userSerial) {
+        synchronized(mPackageVersions) {
+            mPackageVersions.remove(packageName);
+        }
+
         try {
-            db.delete(CacheDb.TABLE_NAME, null, null);
-        } catch (SQLiteDiskIOException e) {
-        } catch (SQLiteCantOpenDatabaseException e) {
-            dumpOpenFiles();
-            throw e;
+            mDb.getWritableDatabase().delete(CacheDb.TABLE_NAME,
+                    CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?",
+                    new String[] {packageName, Long.toString(userSerial)});
+        } catch (SQLException e) {
+            Log.e(TAG, "Unable to delete items from DB", e);
         }
     }
 
-    public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) {
-        synchronized(sInvalidPackages) {
-            sInvalidPackages.add(packageName);
+    /**
+     * Updates the persistent DB:
+     *   1. Any preview generated for an old package version is removed
+     *   2. Any preview for an absent package is removed
+     * This ensures that we remove entries for packages which changed while the launcher was dead.
+     */
+    public void removeObsoletePreviews(ArrayList<Object> list) {
+        Utilities.assertWorkerThread();
+
+        LongSparseArray<UserHandleCompat> userIdCache = new LongSparseArray<>();
+        LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>();
+
+        for (Object obj : list) {
+            final UserHandleCompat user;
+            final String pkg;
+            if (obj instanceof ResolveInfo) {
+                user = UserHandleCompat.myUserHandle();
+                pkg = ((ResolveInfo) obj).activityInfo.packageName;
+            } else {
+                LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) obj;
+                user = mManager.getUser(info);
+                pkg = info.provider.getPackageName();
+            }
+
+            int userIdIndex = userIdCache.indexOfValue(user);
+            final long userId;
+            if (userIdIndex < 0) {
+                userId = mUserManager.getSerialNumberForUser(user);
+                userIdCache.put(userId, user);
+            } else {
+                userId = userIdCache.keyAt(userIdIndex);
+            }
+
+            HashSet<String> packages = validPackages.get(userId);
+            if (packages == null) {
+                packages = new HashSet<>();
+                validPackages.put(userId, packages);
+            }
+            packages.add(pkg);
         }
-        new AsyncTask<Void, Void, Void>() {
-            public Void doInBackground(Void ... args) {
-                SQLiteDatabase db = cacheDb.getWritableDatabase();
+
+        LongSparseArray<HashSet<String>> packagesToDelete = new LongSparseArray<>();
+        Cursor c = null;
+        try {
+            c = mDb.getReadableDatabase().query(CacheDb.TABLE_NAME,
+                    new String[] {CacheDb.COLUMN_USER, CacheDb.COLUMN_PACKAGE,
+                        CacheDb.COLUMN_LAST_UPDATED, CacheDb.COLUMN_VERSION},
+                    null, null, null, null, null);
+            while (c.moveToNext()) {
+                long userId = c.getLong(0);
+                String pkg = c.getString(1);
+                long lastUpdated = c.getLong(2);
+                long version = c.getLong(3);
+
+                HashSet<String> packages = validPackages.get(userId);
+                if (packages != null && packages.contains(pkg)) {
+                    long[] versions = getPackageVersion(pkg);
+                    if (versions[0] == version && versions[1] == lastUpdated) {
+                        // Every thing checks out
+                        continue;
+                    }
+                }
+
+                // We need to delete this package.
+                packages = packagesToDelete.get(userId);
+                if (packages == null) {
+                    packages = new HashSet<>();
+                    packagesToDelete.put(userId, packages);
+                }
+                packages.add(pkg);
+            }
+
+            for (int i = 0; i < packagesToDelete.size(); i++) {
+                long userId = packagesToDelete.keyAt(i);
+                UserHandleCompat user = mUserManager.getUserForSerialNumber(userId);
+                for (String pkg : packagesToDelete.valueAt(i)) {
+                    removePackage(pkg, user, userId);
+                }
+            }
+        } catch (SQLException e) {
+            Log.e(TAG, "Error updatating widget previews", e);
+        } finally {
+            if (c != null) {
+                c.close();
+            }
+        }
+    }
+
+    /**
+     * Reads the preview bitmap from the DB or null if the preview is not in the DB.
+     */
+    @Thunk Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) {
+        Cursor cursor = null;
+        try {
+            cursor = mDb.getReadableDatabase().query(
+                    CacheDb.TABLE_NAME,
+                    new String[] { CacheDb.COLUMN_PREVIEW_BITMAP },
+                    CacheDb.COLUMN_COMPONENT + " = ? AND " + CacheDb.COLUMN_USER + " = ? AND " + CacheDb.COLUMN_SIZE + " = ?",
+                    new String[] {
+                            key.componentName.flattenToString(),
+                            Long.toString(mUserManager.getSerialNumberForUser(key.user)),
+                            key.size
+                    },
+                    null, null, null);
+            // If cancelled, skip getting the blob and decoding it into a bitmap
+            if (loadTask.isCancelled()) {
+                return null;
+            }
+            if (cursor.moveToNext()) {
+                byte[] blob = cursor.getBlob(0);
+                BitmapFactory.Options opts = new BitmapFactory.Options();
+                opts.inBitmap = recycle;
                 try {
-                    db.delete(CacheDb.TABLE_NAME,
-                            CacheDb.COLUMN_NAME + " LIKE ? OR " +
-                            CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query
-                            new String[] {
-                                    WIDGET_PREFIX + packageName + "/%",
-                                    SHORTCUT_PREFIX + packageName + "/%"
-                            } // args to SELECT query
-                    );
-                } catch (SQLiteDiskIOException e) {
-                } catch (SQLiteCantOpenDatabaseException e) {
-                    dumpOpenFiles();
-                    throw e;
+                    if (!loadTask.isCancelled()) {
+                        return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts);
+                    }
+                } catch (Exception e) {
+                    return null;
                 }
-                synchronized(sInvalidPackages) {
-                    sInvalidPackages.remove(packageName);
-                }
-                return null;
             }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+        } catch (SQLException e) {
+            Log.w(TAG, "Error loading preview from DB", e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return null;
     }
 
-    private static void removeItemFromDb(final CacheDb cacheDb, final String objectName) {
-        new AsyncTask<Void, Void, Void>() {
-            public Void doInBackground(Void ... args) {
-                SQLiteDatabase db = cacheDb.getWritableDatabase();
-                try {
-                    db.delete(CacheDb.TABLE_NAME,
-                            CacheDb.COLUMN_NAME + " = ? ", // SELECT query
-                            new String[] { objectName }); // args to SELECT query
-                } catch (SQLiteDiskIOException e) {
-                } catch (SQLiteCantOpenDatabaseException e) {
-                    dumpOpenFiles();
-                    throw e;
-                }
-                return null;
-            }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
-    }
-
-    private Bitmap readFromDb(String name, Bitmap b) {
-        if (mCachedSelectQuery == null) {
-            mCachedSelectQuery = CacheDb.COLUMN_NAME + " = ? AND " +
-                    CacheDb.COLUMN_SIZE + " = ?";
-        }
-        SQLiteDatabase db = mDb.getReadableDatabase();
-        Cursor result;
-        try {
-            result = db.query(CacheDb.TABLE_NAME,
-                    new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return
-                    mCachedSelectQuery, // select query
-                    new String[] { name, mSize }, // args to select query
-                    null,
-                    null,
-                    null,
-                    null);
-        } catch (SQLiteDiskIOException e) {
-            recreateDb();
-            return null;
-        } catch (SQLiteCantOpenDatabaseException e) {
-            dumpOpenFiles();
-            throw e;
-        }
-        if (result.getCount() > 0) {
-            result.moveToFirst();
-            byte[] blob = result.getBlob(0);
-            result.close();
-            final BitmapFactory.Options opts = mCachedBitmapFactoryOptions.get();
-            opts.inBitmap = b;
-            opts.inSampleSize = 1;
-            try {
-                return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts);
-            } catch (IllegalArgumentException e) {
-                removeItemFromDb(mDb, name);
-                return null;
-            }
+    @Thunk Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle,
+            int previewWidth, int previewHeight) {
+        if (info instanceof LauncherAppWidgetProviderInfo) {
+            return generateWidgetPreview(launcher, (LauncherAppWidgetProviderInfo) info,
+                    previewWidth, recycle, null);
         } else {
-            result.close();
-            return null;
+            return generateShortcutPreview(launcher,
+                    (ResolveInfo) info, previewWidth, previewHeight, recycle);
         }
     }
 
-    private Bitmap generatePreview(Object info, Bitmap preview) {
-        if (preview != null &&
-                (preview.getWidth() != mPreviewBitmapWidth ||
-                preview.getHeight() != mPreviewBitmapHeight)) {
-            throw new RuntimeException("Improperly sized bitmap passed as argument");
-        }
-        if (info instanceof AppWidgetProviderInfo) {
-            return generateWidgetPreview((AppWidgetProviderInfo) info, preview);
-        } else {
-            return generateShortcutPreview(
-                    (ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview);
-        }
-    }
-
-    public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, Bitmap preview) {
-        int[] cellSpans = Launcher.getSpanForWidget(mContext, info);
-        int maxWidth = maxWidthForWidgetPreview(cellSpans[0]);
-        int maxHeight = maxHeightForWidgetPreview(cellSpans[1]);
-        return generateWidgetPreview(info, cellSpans[0], cellSpans[1],
-                maxWidth, maxHeight, preview, null);
-    }
-
-    public int maxWidthForWidgetPreview(int spanX) {
-        return Math.min(mPreviewBitmapWidth,
-                mWidgetSpacingLayout.estimateCellWidth(spanX));
-    }
-
-    public int maxHeightForWidgetPreview(int spanY) {
-        return Math.min(mPreviewBitmapHeight,
-                mWidgetSpacingLayout.estimateCellHeight(spanY));
-    }
-
-    public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, int cellHSpan, int cellVSpan,
-            int maxPreviewWidth, int maxPreviewHeight, Bitmap preview, int[] preScaledWidthOut) {
+    public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info,
+            int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) {
         // Load the preview image if possible
         if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE;
-        if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE;
 
         Drawable drawable = null;
         if (info.previewImage != 0) {
@@ -533,61 +360,23 @@
             }
         }
 
+        final boolean widgetPreviewExists = (drawable != null);
+        final int spanX = info.getSpanX(launcher) < 1 ? 1 : info.getSpanX(launcher);
+        final int spanY = info.getSpanY(launcher) < 1 ? 1 : info.getSpanY(launcher);
+
         int previewWidth;
         int previewHeight;
-        Bitmap defaultPreview = null;
-        boolean widgetPreviewExists = (drawable != null);
+        Bitmap tileBitmap = null;
+
         if (widgetPreviewExists) {
             previewWidth = drawable.getIntrinsicWidth();
             previewHeight = drawable.getIntrinsicHeight();
         } else {
             // Generate a preview image if we couldn't load one
-            if (cellHSpan < 1) cellHSpan = 1;
-            if (cellVSpan < 1) cellVSpan = 1;
-
-            // This Drawable is not directly drawn, so there's no need to mutate it.
-            BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources()
-                    .getDrawable(R.drawable.widget_tile);
-            final int previewDrawableWidth = previewDrawable
-                    .getIntrinsicWidth();
-            final int previewDrawableHeight = previewDrawable
-                    .getIntrinsicHeight();
-            previewWidth = previewDrawableWidth * cellHSpan;
-            previewHeight = previewDrawableHeight * cellVSpan;
-
-            defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
-            final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-            c.setBitmap(defaultPreview);
-            Paint p = mDefaultAppWidgetPreviewPaint.get();
-            if (p == null) {
-                p = new Paint();
-                p.setShader(new BitmapShader(previewDrawable.getBitmap(),
-                        Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
-                mDefaultAppWidgetPreviewPaint.set(p);
-            }
-            final Rect dest = mCachedAppWidgetPreviewDestRect.get();
-            dest.set(0, 0, previewWidth, previewHeight);
-            c.drawRect(dest, p);
-            c.setBitmap(null);
-
-            // Draw the icon in the top left corner
-            int minOffset = (int) (mAppIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE);
-            int smallestSide = Math.min(previewWidth, previewHeight);
-            float iconScale = Math.min((float) smallestSide
-                    / (mAppIconSize + 2 * minOffset), 1f);
-
-            try {
-                Drawable icon = mManager.loadIcon(info, mIconCache);
-                if (icon != null) {
-                    int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
-                    int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
-                    icon = mutateOnMainThread(icon);
-                    renderDrawableToBitmap(icon, defaultPreview, hoffset,
-                            yoffset, (int) (mAppIconSize * iconScale),
-                            (int) (mAppIconSize * iconScale));
-                }
-            } catch (Resources.NotFoundException e) {
-            }
+            tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable(
+                    R.drawable.widget_tile)).getBitmap();
+            previewWidth = tileBitmap.getWidth() * spanX;
+            previewHeight = tileBitmap.getHeight() * spanY;
         }
 
         // Scale to fit width only - let the widget preview be clipped in the
@@ -605,102 +394,110 @@
         }
 
         // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size
+        final Canvas c = new Canvas();
         if (preview == null) {
             preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888);
+            c.setBitmap(preview);
+        } else {
+            // Reusing bitmap. Clear it.
+            c.setBitmap(preview);
+            c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
 
         // Draw the scaled preview into the final bitmap
-        int x = (preview.getWidth() - previewWidth) / 2;
+        int x = (preview.getWidth() - previewWidth - mProfileBadgeMargin) / 2;
         if (widgetPreviewExists) {
-            renderDrawableToBitmap(drawable, preview, x, 0, previewWidth,
-                    previewHeight);
+            drawable.setBounds(x, 0, x + previewWidth, previewHeight);
+            drawable.draw(c);
         } else {
-            final Canvas c = mCachedAppWidgetPreviewCanvas.get();
-            final Rect src = mCachedAppWidgetPreviewSrcRect.get();
-            final Rect dest = mCachedAppWidgetPreviewDestRect.get();
-            c.setBitmap(preview);
-            src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight());
-            dest.set(x, 0, x + previewWidth, previewHeight);
+            final Paint p = new Paint();
+            p.setFilterBitmap(true);
+            int appIconSize = launcher.getDeviceProfile().iconSizePx;
 
-            Paint p = mCachedAppWidgetPreviewPaint.get();
-            if (p == null) {
-                p = new Paint();
-                p.setFilterBitmap(true);
-                mCachedAppWidgetPreviewPaint.set(p);
+            // draw the spanX x spanY tiles
+            final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight());
+
+            float tileW = scale * tileBitmap.getWidth();
+            float tileH = scale * tileBitmap.getHeight();
+            final RectF dst = new RectF(0, 0, tileW, tileH);
+
+            float tx = x;
+            for (int i = 0; i < spanX; i++, tx += tileW) {
+                float ty = 0;
+                for (int j = 0; j < spanY; j++, ty += tileH) {
+                    dst.offsetTo(tx, ty);
+                    c.drawBitmap(tileBitmap, src, dst, p);
+                }
             }
-            c.drawBitmap(defaultPreview, src, dest, p);
+
+            // Draw the icon in the top left corner
+            // TODO: use top right for RTL
+            int minOffset = (int) (appIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE);
+            int smallestSide = Math.min(previewWidth, previewHeight);
+            float iconScale = Math.min((float) smallestSide / (appIconSize + 2 * minOffset), scale);
+
+            try {
+                Drawable icon = mutateOnMainThread(mManager.loadIcon(info, mIconCache));
+                if (icon != null) {
+                    int hoffset = (int) ((tileW - appIconSize * iconScale) / 2) + x;
+                    int yoffset = (int) ((tileH - appIconSize * iconScale) / 2);
+                    icon.setBounds(hoffset, yoffset,
+                            hoffset + (int) (appIconSize * iconScale),
+                            yoffset + (int) (appIconSize * iconScale));
+                    icon.draw(c);
+                }
+            } catch (Resources.NotFoundException e) { }
             c.setBitmap(null);
         }
-        return mManager.getBadgeBitmap(info, preview);
+        int imageHeight = Math.min(preview.getHeight(), previewHeight + mProfileBadgeMargin);
+        return mManager.getBadgeBitmap(info, preview, imageHeight);
     }
 
     private Bitmap generateShortcutPreview(
-            ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) {
-        Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get();
-        final Canvas c = mCachedShortcutPreviewCanvas.get();
-        if (tempBitmap == null ||
-                tempBitmap.getWidth() != maxWidth ||
-                tempBitmap.getHeight() != maxHeight) {
-            tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
-            mCachedShortcutPreviewBitmap.set(tempBitmap);
-        } else {
-            c.setBitmap(tempBitmap);
-            c.drawColor(0, PorterDuff.Mode.CLEAR);
-            c.setBitmap(null);
-        }
-        // Render the icon
-        Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo));
-
-        int paddingTop = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
-        int paddingLeft = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left);
-        int paddingRight = mContext.
-                getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
-
-        int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
-
-        renderDrawableToBitmap(
-                icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth);
-
-        if (preview != null &&
-                (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight)) {
-            throw new RuntimeException("Improperly sized bitmap passed as argument");
-        } else if (preview == null) {
+            Launcher launcher, ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) {
+        final Canvas c = new Canvas();
+        if (preview == null) {
             preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888);
+            c.setBitmap(preview);
+        } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) {
+            throw new RuntimeException("Improperly sized bitmap passed as argument");
+        } else {
+            // Reusing bitmap. Clear it.
+            c.setBitmap(preview);
+            c.drawColor(0, PorterDuff.Mode.CLEAR);
         }
 
-        c.setBitmap(preview);
+        Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo));
+        icon.setFilterBitmap(true);
+
         // Draw a desaturated/scaled version of the icon in the background as a watermark
-        Paint p = mCachedShortcutPreviewPaint.get();
-        if (p == null) {
-            p = new Paint();
-            ColorMatrix colorMatrix = new ColorMatrix();
-            colorMatrix.setSaturation(0);
-            p.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
-            p.setAlpha((int) (255 * 0.06f));
-            mCachedShortcutPreviewPaint.set(p);
-        }
-        c.drawBitmap(tempBitmap, 0, 0, p);
+        ColorMatrix colorMatrix = new ColorMatrix();
+        colorMatrix.setSaturation(0);
+        icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
+        icon.setAlpha((int) (255 * 0.06f));
+
+        Resources res = mContext.getResources();
+        int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top);
+        int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left);
+        int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right);
+        int scaledIconWidth = (maxWidth - paddingLeft - paddingRight);
+        icon.setBounds(paddingLeft, paddingTop,
+                paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth);
+        icon.draw(c);
+
+        // Draw the final icon at top left corner.
+        // TODO: use top right for RTL
+        int appIconSize = launcher.getDeviceProfile().iconSizePx;
+
+        icon.setAlpha(255);
+        icon.setColorFilter(null);
+        icon.setBounds(0, 0, appIconSize, appIconSize);
+        icon.draw(c);
+
         c.setBitmap(null);
-
-        renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize);
-
         return preview;
     }
 
-    private static void renderDrawableToBitmap(
-            Drawable d, Bitmap bitmap, int x, int y, int w, int h) {
-        if (bitmap != null) {
-            Canvas c = new Canvas(bitmap);
-            Rect oldBounds = d.copyBounds();
-            d.setBounds(x, y, x + w, y + h);
-            d.draw(c);
-            d.setBounds(oldBounds); // Restore the bounds
-            c.setBitmap(null);
-        }
-    }
-
     private Drawable mutateOnMainThread(final Drawable drawable) {
         try {
             return mMainThreadExecutor.submit(new Callable<Drawable>() {
@@ -717,82 +514,195 @@
         }
     }
 
-    private static final int MAX_OPEN_FILES = 1024;
-    private static final int SAMPLE_RATE = 23;
     /**
-     * Dumps all files that are open in this process without allocating a file descriptor.
+     * @return an array of containing versionCode and lastUpdatedTime for the package.
      */
-    private static void dumpOpenFiles() {
-        try {
-            Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):");
-            final String TYPE_APK = "apk";
-            final String TYPE_JAR = "jar";
-            final String TYPE_PIPE = "pipe";
-            final String TYPE_SOCKET = "socket";
-            final String TYPE_DB = "db";
-            final String TYPE_ANON_INODE = "anon_inode";
-            final String TYPE_DEV = "dev";
-            final String TYPE_NON_FS = "non-fs";
-            final String TYPE_OTHER = "other";
-            List<String> types = Arrays.asList(TYPE_APK, TYPE_JAR, TYPE_PIPE, TYPE_SOCKET, TYPE_DB,
-                    TYPE_ANON_INODE, TYPE_DEV, TYPE_NON_FS, TYPE_OTHER);
-            int[] count = new int[types.size()];
-            int[] duplicates = new int[types.size()];
-            HashSet<String> files = new HashSet<String>();
-            int total = 0;
-            for (int i = 0; i < MAX_OPEN_FILES; i++) {
-                // This is a gigantic hack but unfortunately the only way to resolve an fd
-                // to a file name. Note that we have to loop over all possible fds because
-                // reading the directory would require allocating a new fd. The kernel is
-                // currently implemented such that no fd is larger then the current rlimit,
-                // which is why it's safe to loop over them in such a way.
-                String fd = "/proc/self/fd/" + i;
+    @Thunk long[] getPackageVersion(String packageName) {
+        synchronized (mPackageVersions) {
+            long[] versions = mPackageVersions.get(packageName);
+            if (versions == null) {
+                versions = new long[2];
                 try {
-                    // getCanonicalPath() uses readlink behind the scene which doesn't require
-                    // a file descriptor.
-                    String resolved = new File(fd).getCanonicalPath();
-                    int type = types.indexOf(TYPE_OTHER);
-                    if (resolved.startsWith("/dev/")) {
-                        type = types.indexOf(TYPE_DEV);
-                    } else if (resolved.endsWith(".apk")) {
-                        type = types.indexOf(TYPE_APK);
-                    } else if (resolved.endsWith(".jar")) {
-                        type = types.indexOf(TYPE_JAR);
-                    } else if (resolved.contains("/fd/pipe:")) {
-                        type = types.indexOf(TYPE_PIPE);
-                    } else if (resolved.contains("/fd/socket:")) {
-                        type = types.indexOf(TYPE_SOCKET);
-                    } else if (resolved.contains("/fd/anon_inode:")) {
-                        type = types.indexOf(TYPE_ANON_INODE);
-                    } else if (resolved.endsWith(".db") || resolved.contains("/databases/")) {
-                        type = types.indexOf(TYPE_DB);
-                    } else if (resolved.startsWith("/proc/") && resolved.contains("/fd/")) {
-                        // Those are the files that don't point anywhere on the file system.
-                        // getCanonicalPath() wrongly interprets these as relative symlinks and
-                        // resolves them within /proc/<pid>/fd/.
-                        type = types.indexOf(TYPE_NON_FS);
+                    PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
+                    versions[0] = info.versionCode;
+                    versions[1] = info.lastUpdateTime;
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "PackageInfo not found", e);
+                }
+                mPackageVersions.put(packageName, versions);
+            }
+            return versions;
+        }
+    }
+
+    /**
+     * A request Id which can be used by the client to cancel any request.
+     */
+    public class PreviewLoadRequest {
+
+        @Thunk final PreviewLoadTask mTask;
+
+        public PreviewLoadRequest(PreviewLoadTask task) {
+            mTask = task;
+        }
+
+        public void cleanup() {
+            if (mTask != null) {
+                mTask.cancel(true);
+            }
+
+            // This only handles the case where the PreviewLoadTask is cancelled after the task has
+            // successfully completed (including having written to disk when necessary).  In the
+            // other cases where it is cancelled while the task is running, it will be cleaned up
+            // in the tasks's onCancelled() call, and if cancelled while the task is writing to
+            // disk, it will be cancelled in the task's onPostExecute() call.
+            if (mTask.mBitmapToRecycle != null) {
+                mWorkerHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        synchronized (mUnusedBitmaps) {
+                            mUnusedBitmaps.add(mTask.mBitmapToRecycle);
+                        }
+                        mTask.mBitmapToRecycle = null;
                     }
-                    count[type]++;
-                    total++;
-                    if (files.contains(resolved)) {
-                        duplicates[type]++;
+                });
+            }
+        }
+    }
+
+    public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> {
+        @Thunk final WidgetCacheKey mKey;
+        private final Object mInfo;
+        private final int mPreviewHeight;
+        private final int mPreviewWidth;
+        private final WidgetCell mCaller;
+        @Thunk long[] mVersions;
+        @Thunk Bitmap mBitmapToRecycle;
+
+        PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
+                int previewHeight, WidgetCell caller) {
+            mKey = key;
+            mInfo = info;
+            mPreviewHeight = previewHeight;
+            mPreviewWidth = previewWidth;
+            mCaller = caller;
+            if (DEBUG) {
+                Log.d(TAG, String.format("%s, %s, %d, %d",
+                        mKey, mInfo, mPreviewHeight, mPreviewWidth));
+            }
+        }
+
+        @Override
+        protected Bitmap doInBackground(Void... params) {
+            Bitmap unusedBitmap = null;
+
+            // If already cancelled before this gets to run in the background, then return early
+            if (isCancelled()) {
+                return null;
+            }
+            synchronized (mUnusedBitmaps) {
+                // Check if we can re-use a bitmap
+                for (Bitmap candidate : mUnusedBitmaps) {
+                    if (candidate != null && candidate.isMutable() &&
+                            candidate.getWidth() == mPreviewWidth &&
+                            candidate.getHeight() == mPreviewHeight) {
+                        unusedBitmap = candidate;
+                        mUnusedBitmaps.remove(unusedBitmap);
+                        break;
                     }
-                    files.add(resolved);
-                    if (total % SAMPLE_RATE == 0) {
-                        Log.i(TAG, " fd " + i + ": " + resolved
-                                + " (" + types.get(type) + ")");
-                    }
-                } catch (IOException e) {
-                    // Ignoring exceptions for non-existing file descriptors.
                 }
             }
-            for (int i = 0; i < types.size(); i++) {
-                Log.i(TAG, String.format("Open %10s files: %4d total, %4d duplicates",
-                        types.get(i), count[i], duplicates[i]));
+
+            // creating a bitmap is expensive. Do not do this inside synchronized block.
+            if (unusedBitmap == null) {
+                unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888);
             }
-        } catch (Throwable t) {
-            // Catch everything. This is called from an exception handler that we shouldn't upset.
-            Log.e(TAG, "Unable to log open files.", t);
+            // If cancelled now, don't bother reading the preview from the DB
+            if (isCancelled()) {
+                return unusedBitmap;
+            }
+            Bitmap preview = readFromDb(mKey, unusedBitmap, this);
+            // Only consider generating the preview if we have not cancelled the task already
+            if (!isCancelled() && preview == null) {
+                // Fetch the version info before we generate the preview, so that, in-case the
+                // app was updated while we are generating the preview, we use the old version info,
+                // which would gets re-written next time.
+                mVersions = getPackageVersion(mKey.componentName.getPackageName());
+
+                Launcher launcher = (Launcher) mCaller.getContext();
+
+                // it's not in the db... we need to generate it
+                preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight);
+            }
+            return preview;
+        }
+
+        @Override
+        protected void onPostExecute(final Bitmap preview) {
+            mCaller.applyPreview(preview);
+
+            // Write the generated preview to the DB in the worker thread
+            if (mVersions != null) {
+                mWorkerHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (!isCancelled()) {
+                            // If we are still using this preview, then write it to the DB and then
+                            // let the normal clear mechanism recycle the bitmap
+                            writeToDb(mKey, mVersions, preview);
+                            mBitmapToRecycle = preview;
+                        } else {
+                            // If we've already cancelled, then skip writing the bitmap to the DB
+                            // and manually add the bitmap back to the recycled set
+                            synchronized (mUnusedBitmaps) {
+                                mUnusedBitmaps.add(preview);
+                            }
+                        }
+                    }
+                });
+            } else {
+                // If we don't need to write to disk, then ensure the preview gets recycled by
+                // the normal clear mechanism
+                mBitmapToRecycle = preview;
+            }
+        }
+
+        @Override
+        protected void onCancelled(final Bitmap preview) {
+            // If we've cancelled while the task is running, then can return the bitmap to the
+            // recycled set immediately. Otherwise, it will be recycled after the preview is written
+            // to disk.
+            if (preview != null) {
+                mWorkerHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        synchronized (mUnusedBitmaps) {
+                            mUnusedBitmaps.add(preview);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    private static final class WidgetCacheKey extends ComponentKey {
+
+        // TODO: remove dependency on size
+        @Thunk final String size;
+
+        public WidgetCacheKey(ComponentName componentName, UserHandleCompat user, String size) {
+            super(componentName, user);
+            this.size = size;
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode() ^ size.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return super.equals(o) && ((WidgetCacheKey) o).size.equals(size);
         }
     }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8bd7991..4a6b90a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -17,24 +17,18 @@
 package com.android.launcher3;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
 import android.app.WallpaperManager;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -46,12 +40,12 @@
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcelable;
-import android.support.v4.view.ViewCompat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -69,16 +63,20 @@
 import com.android.launcher3.Launcher.CustomContentCallbacks;
 import com.android.launcher3.Launcher.LauncherOverlay;
 import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
+import com.android.launcher3.UninstallDropTarget.UninstallSource;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
+import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
 import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.util.WallpaperUtils;
+import com.android.launcher3.widget.PendingAddShortcutInfo;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -86,63 +84,45 @@
  * 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 SmoothPagedView
+public class Workspace extends PagedView
         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,
-        Insettable {
+        Insettable, UninstallSource, AccessibilityDragSource, Stats.LaunchSourceProvider {
     private static final String TAG = "Launcher.Workspace";
 
-    // Y rotation to apply to the workspace screens
-    private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;
-
-    private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;
-    private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
-    private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
+    private static boolean ENFORCE_DRAG_EVENT_ORDER = false;
 
     protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
     protected static final int FADE_EMPTY_SCREEN_DURATION = 150;
 
-    private static final int BACKGROUND_FADE_OUT_DURATION = 350;
     private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
-    private static final int FLING_THRESHOLD_VELOCITY = 500;
-
-    private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
 
     static final boolean MAP_NO_RECURSE = false;
     static final boolean MAP_RECURSE = true;
 
-    // These animators are used to fade the children's outlines
-    private ObjectAnimator mChildrenOutlineFadeInAnimation;
-    private ObjectAnimator mChildrenOutlineFadeOutAnimation;
-    private float mChildrenOutlineAlpha = 0;
-
-    // These properties refer to the background protection gradient used for AllApps and Customize
-    private ValueAnimator mBackgroundFadeInAnimation;
-    private ValueAnimator mBackgroundFadeOutAnimation;
-
     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
     private long mTouchDownTime = -1;
     private long mCustomContentShowTime = -1;
 
     private LayoutTransition mLayoutTransition;
-    private final WallpaperManager mWallpaperManager;
-    private IBinder mWindowToken;
+    @Thunk final WallpaperManager mWallpaperManager;
+    @Thunk IBinder mWindowToken;
 
     private int mOriginalDefaultPage;
     private int mDefaultPage;
 
     private ShortcutAndWidgetContainer mDragSourceInternal;
-    private static boolean sAccessibilityEnabled;
 
     // The screen id used for the empty screen always present to the right.
     final static long EXTRA_EMPTY_SCREEN_ID = -201;
     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
 
-    private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
-    private ArrayList<Long> mScreenOrder = new ArrayList<Long>();
+    @Thunk LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>();
+    @Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>();
 
-    private Runnable mRemoveEmptyScreenRunnable;
-    private boolean mDeferRemoveExtraEmptyScreen = false;
+    @Thunk Runnable mRemoveEmptyScreenRunnable;
+    @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
+    @Thunk boolean mAddNewPageOnDrag = true;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -152,7 +132,7 @@
     /**
      * Target drop area calculated during last acceptDrop call.
      */
-    private int[] mTargetCell = new int[2];
+    @Thunk int[] mTargetCell = new int[2];
     private int mDragOverX = -1;
     private int mDragOverY = -1;
 
@@ -167,7 +147,7 @@
     /**
      * The CellLayout that is currently being dragged over
      */
-    private CellLayout mDragTargetLayout = null;
+    @Thunk CellLayout mDragTargetLayout = null;
     /**
      * The CellLayout that we will show as glowing
      */
@@ -178,16 +158,16 @@
      */
     private CellLayout mDropToLayout = null;
 
-    private Launcher mLauncher;
-    private IconCache mIconCache;
-    private DragController mDragController;
+    @Thunk Launcher mLauncher;
+    @Thunk IconCache mIconCache;
+    @Thunk DragController mDragController;
 
     // These are temporary variables to prevent having to allocate a new object just to
     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
     private int[] mTempCell = new int[2];
     private int[] mTempPt = new int[2];
     private int[] mTempEstimate = new int[2];
-    private float[] mDragViewVisualCenter = new float[2];
+    @Thunk float[] mDragViewVisualCenter = new float[2];
     private float[] mTempCellLayoutCenterCoordinates = new float[2];
     private Matrix mTempInverseMatrix = new Matrix();
 
@@ -212,34 +192,31 @@
     private boolean mInScrollArea = false;
 
     private HolographicOutlineHelper mOutlineHelper;
-    private Bitmap mDragOutline = null;
+    @Thunk Bitmap mDragOutline = null;
     private static final Rect sTempRect = new Rect();
     private final int[] mTempXY = new int[2];
     private int[] mTempVisiblePagesRange = new int[2];
-    private boolean mOverscrollEffectSet;
     public static final int DRAG_BITMAP_PADDING = 2;
     private boolean mWorkspaceFadeInAdjacentScreens;
 
     WallpaperOffsetInterpolator mWallpaperOffset;
-    private boolean mWallpaperIsLiveWallpaper;
-    private int mNumPagesForWallpaperParallax;
-    private float mLastSetWallpaperOffsetSteps = 0;
+    @Thunk boolean mWallpaperIsLiveWallpaper;
+    @Thunk int mNumPagesForWallpaperParallax;
+    @Thunk float mLastSetWallpaperOffsetSteps = 0;
 
-    private Runnable mDelayedResizeRunnable;
+    @Thunk Runnable mDelayedResizeRunnable;
     private Runnable mDelayedSnapToPageRunnable;
     private Point mDisplaySize = new Point();
-    private int mCameraDistance;
 
     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
     private static final int FOLDER_CREATION_TIMEOUT = 0;
     public static final int REORDER_TIMEOUT = 350;
     private final Alarm mFolderCreationAlarm = new Alarm();
     private final Alarm mReorderAlarm = new Alarm();
-    private FolderRingAnimator mDragFolderRingAnimator = null;
+    @Thunk FolderRingAnimator mDragFolderRingAnimator = null;
     private FolderIcon mDragOverFolderIcon = null;
     private boolean mCreateUserFolderOnDrop = false;
     private boolean mAddToExistingFolderOnDrop = false;
-    private DropTarget.DragEnforcer mDragEnforcer;
     private float mMaxDistanceForFolderCreation;
 
     private final Canvas mCanvas = new Canvas();
@@ -264,30 +241,16 @@
     private static final int DRAG_MODE_ADD_TO_FOLDER = 2;
     private static final int DRAG_MODE_REORDER = 3;
     private int mDragMode = DRAG_MODE_NONE;
-    private int mLastReorderX = -1;
-    private int mLastReorderY = -1;
+    @Thunk int mLastReorderX = -1;
+    @Thunk int mLastReorderY = -1;
 
     private SparseArray<Parcelable> mSavedStates;
     private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();
 
-    // These variables are used for storing the initial and final values during workspace animations
-    private int mSavedScrollX;
-    private float mSavedRotationY;
-    private float mSavedTranslationX;
-
     private float mCurrentScale;
-    private float mNewScale;
-    private float[] mOldBackgroundAlphas;
-    private float[] mOldAlphas;
-    private float[] mNewBackgroundAlphas;
-    private float[] mNewAlphas;
-    private int mLastChildCount = -1;
     private float mTransitionProgress;
-    private Animator mStateAnimator = null;
 
-    float mOverScrollEffect = 0f;
-
-    private Runnable mDeferredAction;
+    @Thunk Runnable mDeferredAction;
     private boolean mDeferDropAfterUninstall;
     private boolean mUninstallSuccessful;
 
@@ -298,6 +261,11 @@
     boolean mShouldSendPageSettled;
     int mLastOverlaySroll = 0;
 
+    // Handles workspace state transitions
+    private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
+
+    private AccessibilityDelegate mPagesAccessibilityDelegate;
+
     private final Runnable mBindPages = new Runnable() {
         @Override
         public void run() {
@@ -324,29 +292,22 @@
      */
     public Workspace(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mContentIsRefreshable = false;
 
         mOutlineHelper = HolographicOutlineHelper.obtain(context);
 
-        mDragEnforcer = new DropTarget.DragEnforcer(context);
-        // With workspace, data is available straight from the get-go
-        setDataIsReady();
-
         mLauncher = (Launcher) context;
+        mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
         final Resources res = getResources();
-        mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().
-                getDeviceProfile().shouldFadeAdjacentWorkspaceScreens();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
         mFadeInAdjacentScreens = false;
         mWallpaperManager = WallpaperManager.getInstance(context);
 
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
         TypedArray a = context.obtainStyledAttributes(attrs,
                 R.styleable.Workspace, defStyle, 0);
         mSpringLoadedShrinkFactor =
             res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
-        mOverviewModeShrinkFactor = grid.getOverviewModeScale();
-        mCameraDistance = res.getInteger(R.integer.config_cameraDistance);
+        mOverviewModeShrinkFactor = grid.getOverviewModeScale(mIsRtl);
         mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);
         a.recycle();
 
@@ -357,7 +318,6 @@
 
         // Disable multitouch across the workspace/all apps/customize tray
         setMotionEventSplittingEnabled(true);
-        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
     }
 
     @Override
@@ -375,13 +335,12 @@
 
     // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each
     // dimension if unsuccessful
-    public int[] estimateItemSize(int hSpan, int vSpan,
-            ItemInfo itemInfo, boolean springLoaded) {
+    public int[] estimateItemSize(ItemInfo itemInfo, boolean springLoaded) {
         int[] size = new int[2];
         if (getChildCount() > 0) {
             // Use the first non-custom page to estimate the child position
             CellLayout cl = (CellLayout) getChildAt(numCustomPages());
-            Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);
+            Rect r = estimateItemPosition(cl, itemInfo, 0, 0, itemInfo.spanX, itemInfo.spanY);
             size[0] = r.width();
             size[1] = r.height();
             if (springLoaded) {
@@ -403,32 +362,39 @@
         return r;
     }
 
+    @Override
     public void onDragStart(final DragSource source, Object info, int dragAction) {
+        if (ENFORCE_DRAG_EVENT_ORDER) {
+            enfoceDragParity("onDragStart", 0, 0);
+        }
+
         mIsDragOccuring = true;
         updateChildrenLayersEnabled(false);
         mLauncher.lockScreenOrientation();
         mLauncher.onInteractionBegin();
-        setChildrenBackgroundAlphaMultipliers(1f);
         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging
         InstallShortcutReceiver.enableInstallQueue();
-        UninstallShortcutReceiver.enableUninstallQueue();
-        post(new Runnable() {
-            @Override
-            public void run() {
-                if (mIsDragOccuring) {
-                    mDeferRemoveExtraEmptyScreen = false;
-                    addExtraEmptyScreenOnDrag();
-                }
-            }
-        });
+
+        if (mAddNewPageOnDrag) {
+            mDeferRemoveExtraEmptyScreen = false;
+            addExtraEmptyScreenOnDrag();
+        }
     }
 
+    public void setAddNewPageOnDrag(boolean addPage) {
+        mAddNewPageOnDrag = addPage;
+    }
 
     public void deferRemoveExtraEmptyScreen() {
         mDeferRemoveExtraEmptyScreen = true;
     }
 
+    @Override
     public void onDragEnd() {
+        if (ENFORCE_DRAG_EVENT_ORDER) {
+            enfoceDragParity("onDragEnd", 0, 0);
+        }
+
         if (!mDeferRemoveExtraEmptyScreen) {
             removeExtraEmptyScreen(true, mDragSourceInternal != null);
         }
@@ -439,7 +405,6 @@
 
         // Re-enable any Un/InstallShortcutReceiver and now process any queued items
         InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());
-        UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());
 
         mDragSourceInternal = null;
         mLauncher.onInteractionEnd();
@@ -450,9 +415,8 @@
      */
     protected void initWorkspace() {
         mCurrentPage = mDefaultPage;
-        Launcher.setScreen(mCurrentPage);
         LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         mIconCache = app.getIconCache();
         setWillNotDraw(false);
         setClipChildren(false);
@@ -467,10 +431,11 @@
         display.getSize(mDisplaySize);
 
         mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);
-        mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);
 
         // Set the wallpaper dimensions when Launcher starts up
         setWallpaperDimension();
+
+        setEdgeGlowColor(getResources().getColor(R.color.workspace_edge_effect_color));
     }
 
     private void setupLayoutTransition() {
@@ -491,11 +456,6 @@
     }
 
     @Override
-    protected int getScrollMode() {
-        return SmoothPagedView.X_LARGE_MODE;
-    }
-
-    @Override
     public void onChildViewAdded(View parent, View child) {
         if (!(child instanceof CellLayout)) {
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
@@ -503,7 +463,7 @@
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
         cl.setClickable(true);
-        cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
         super.onChildViewAdded(parent, child);
     }
 
@@ -518,7 +478,7 @@
     /**
      * @return The open folder on the current screen, or null if there is none
      */
-    Folder getOpenFolder() {
+    public Folder getOpenFolder() {
         DragLayer dragLayer = mLauncher.getDragLayer();
         int count = dragLayer.getChildCount();
         for (int i = 0; i < count; i++) {
@@ -572,16 +532,14 @@
     }
 
     public long insertNewWorkspaceScreen(long screenId, int insertIndex) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +
-                " at index: " + insertIndex, true);
-
         if (mWorkspaceScreens.containsKey(screenId)) {
             throw new RuntimeException("Screen id " + screenId + " already exists!");
         }
 
-        CellLayout newScreen = (CellLayout)
-                mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
+        // Inflate the cell layout, but do not add it automatically so that we can get the newly
+        // created CellLayout.
+        CellLayout newScreen = (CellLayout) mLauncher.getLayoutInflater().inflate(
+                        R.layout.workspace_screen, this, false /* attachToRoot */);
 
         newScreen.setOnLongClickListener(mLongClickListener);
         newScreen.setOnClickListener(mLauncher);
@@ -589,13 +547,18 @@
         mWorkspaceScreens.put(screenId, newScreen);
         mScreenOrder.add(insertIndex, screenId);
         addView(newScreen, insertIndex);
+
+        LauncherAccessibilityDelegate delegate =
+                LauncherAppState.getInstance().getAccessibilityDelegate();
+        if (delegate != null && delegate.isInAccessibleDrag()) {
+            newScreen.enableAccessibleDrag(true, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
+        }
         return screenId;
     }
 
     public void createCustomContentContainer() {
         CellLayout customScreen = (CellLayout)
-                mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
-        customScreen.disableBackground();
+                mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, this, false);
         customScreen.disableDragTarget();
 
         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);
@@ -675,9 +638,6 @@
     }
 
     public void addExtraEmptyScreenOnDrag() {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);
-
         boolean lastChildOnScreen = false;
         boolean childOnFinalScreen = false;
 
@@ -704,9 +664,6 @@
     }
 
     public boolean addExtraEmptyScreen() {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);
-
         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {
             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);
             return true;
@@ -715,9 +672,6 @@
     }
 
     private void convertFinalScreenToEmptyScreenIfNecessary() {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);
-
         if (mLauncher.isWorkspaceLoading()) {
             // Invalid and dangerous operation if workspace is loading
             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);
@@ -742,7 +696,6 @@
 
             // Update the model if we have changed any screens
             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
-            Launcher.addDumpLog(TAG, "11683562 -   extra empty screen: " + finalScreenId, true);
         }
     }
 
@@ -752,8 +705,6 @@
 
     public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,
             final int delay, final boolean stripEmptyScreens) {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);
         if (mLauncher.isWorkspaceLoading()) {
             // Don't strip empty screens if the workspace is still loading
             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);
@@ -778,6 +729,7 @@
                 fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,
                         onComplete, stripEmptyScreens);
             } else {
+                snapToPage(getNextPage(), 0);
                 fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,
                         onComplete, stripEmptyScreens);
             }
@@ -795,9 +747,7 @@
 
     private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,
             final boolean stripEmptyScreens) {
-        // Log to disk
         // XXX: Do we need to update LM workspace screens below?
-        Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);
         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
         PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);
 
@@ -841,8 +791,6 @@
     }
 
     public long commitExtraEmptyScreen() {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);
         if (mLauncher.isWorkspaceLoading()) {
             // Invalid and dangerous operation if workspace is loading
             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);
@@ -875,12 +823,9 @@
     }
 
     public long getIdForScreen(CellLayout layout) {
-        Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
-        while (iter.hasNext()) {
-            long id = iter.next();
-            if (mWorkspaceScreens.get(id) == layout) {
-                return id;
-            }
+        int index = mWorkspaceScreens.indexOfValue(layout);
+        if (index != -1) {
+            return mWorkspaceScreens.keyAt(index);
         }
         return -1;
     }
@@ -896,14 +841,11 @@
         return -1;
     }
 
-    ArrayList<Long> getScreenOrder() {
+    public ArrayList<Long> getScreenOrder() {
         return mScreenOrder;
     }
 
     public void stripEmptyScreens() {
-        // Log to disk
-        Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);
-
         if (mLauncher.isWorkspaceLoading()) {
             // Don't strip empty screens if the workspace is still loading.
             // This is dangerous and can result in data loss.
@@ -918,8 +860,10 @@
 
         int currentPage = getNextPage();
         ArrayList<Long> removeScreens = new ArrayList<Long>();
-        for (Long id: mWorkspaceScreens.keySet()) {
-            CellLayout cl = mWorkspaceScreens.get(id);
+        int total = mWorkspaceScreens.size();
+        for (int i = 0; i < total; i++) {
+            long id = mWorkspaceScreens.keyAt(i);
+            CellLayout cl = mWorkspaceScreens.valueAt(i);
             if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
                 removeScreens.add(id);
             }
@@ -931,7 +875,6 @@
 
         int pageShift = 0;
         for (Long id: removeScreens) {
-            Launcher.addDumpLog(TAG, "11683562 -   removing id: " + id, true);
             CellLayout cl = mWorkspaceScreens.get(id);
             mWorkspaceScreens.remove(id);
             mScreenOrder.remove(id);
@@ -1075,6 +1018,7 @@
      * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout
      * that it should intercept touch events, which is not something that is normally supported.
      */
+    @SuppressLint("ClickableViewAccessibility")
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         return (workspaceInModalState() || !isFinishedSwitchingState())
@@ -1116,7 +1060,7 @@
         case MotionEvent.ACTION_UP:
             if (mTouchState == TOUCH_STATE_REST) {
                 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
-                if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) {
+                if (currentPage != null) {
                     onWallpaperTap(ev);
                 }
             }
@@ -1178,7 +1122,7 @@
         boolean passRightSwipesToCustomContent =
                 (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY;
 
-        boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0;
+        boolean swipeInIgnoreDirection = mIsRtl ? deltaX < 0 : deltaX > 0;
         boolean onCustomContentScreen =
                 getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID;
         if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) {
@@ -1285,15 +1229,14 @@
 
     @Override
     protected void overScroll(float amount) {
-        boolean isRtl = isLayoutRtl();
-        boolean shouldOverScroll = (amount <= 0 && (!hasCustomContent() || isRtl)) ||
-                (amount >= 0 && (!hasCustomContent() || !isRtl));
+        boolean shouldOverScroll = (amount <= 0 && (!hasCustomContent() || mIsRtl)) ||
+                (amount >= 0 && (!hasCustomContent() || !mIsRtl));
 
         boolean shouldScrollOverlay = mLauncherOverlay != null &&
-                ((amount <= 0 && !isRtl) || (amount >= 0 && isRtl));
+                ((amount <= 0 && !mIsRtl) || (amount >= 0 && mIsRtl));
 
         boolean shouldZeroOverlay = mLauncherOverlay != null && mLastOverlaySroll != 0 &&
-                ((amount >= 0 && !isRtl) || (amount <= 0 && isRtl));
+                ((amount >= 0 && !mIsRtl) || (amount <= 0 && mIsRtl));
 
         if (shouldScrollOverlay) {
             if (!mStartedSendingScrollEvents && mScrollInteractionBegan) {
@@ -1307,23 +1250,26 @@
             int progress = (int) Math.abs((f * 100));
 
             mLastOverlaySroll = progress;
-            mLauncherOverlay.onScrollChange(progress, isRtl);
+            mLauncherOverlay.onScrollChange(progress, mIsRtl);
         } else if (shouldOverScroll) {
             dampedOverScroll(amount);
-            mOverScrollEffect = acceleratedOverFactor(amount);
-        } else {
-            mOverScrollEffect = 0;
         }
 
         if (shouldZeroOverlay) {
-            mLauncherOverlay.onScrollChange(0, isRtl);
+            mLauncherOverlay.onScrollChange(0, mIsRtl);
         }
     }
 
     @Override
+    protected void getEdgeVerticalPostion(int[] pos) {
+        View child = getChildAt(getPageCount() - 1);
+        pos[0] = child.getTop();
+        pos[1] = child.getBottom();
+    }
+
+    @Override
     protected void notifyPageSwitchListener() {
         super.notifyPageSwitchListener();
-        Launcher.setScreen(getNextPage());
 
         if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {
             mCustomContentShowing = true;
@@ -1346,10 +1292,10 @@
     protected void setWallpaperDimension() {
         new AsyncTask<Void, Void, Void>() {
             public Void doInBackground(Void ... args) {
-                String spKey = WallpaperCropActivity.getSharedPreferencesKey();
+                String spKey = LauncherFiles.WALLPAPER_CROP_PREFERENCES_KEY;
                 SharedPreferences sp =
                         mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
-                LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(),
+                WallpaperUtils.suggestWallpaperDimension(mLauncher.getResources(),
                         sp, mLauncher.getWindowManager(), mWallpaperManager,
                         mLauncher.overrideWallpaperDimensions());
                 return null;
@@ -1439,7 +1385,22 @@
         }
 
         private float wallpaperOffsetForCurrentScroll() {
+            // TODO: do different behavior if it's  a live wallpaper?
+            // Don't use up all the wallpaper parallax until you have at least
+            // MIN_PARALLAX_PAGE_SPAN pages
+            int numScrollingPages = getNumScreensExcludingEmptyAndCustom();
+            int parallaxPageSpan;
+            if (mWallpaperIsLiveWallpaper) {
+                parallaxPageSpan = numScrollingPages - 1;
+            } else {
+                parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);
+            }
+            mNumPagesForWallpaperParallax = parallaxPageSpan;
+
             if (getChildCount() <= 1) {
+                if (mIsRtl) {
+                    return 1 - 1.0f/mNumPagesForWallpaperParallax;
+                }
                 return 0;
             }
 
@@ -1448,7 +1409,7 @@
             int firstIndex = numCustomPages();
             // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)
             int lastIndex = getChildCount() - 1 - emptyExtraPages;
-            if (isLayoutRtl()) {
+            if (mIsRtl) {
                 int temp = firstIndex;
                 firstIndex = lastIndex;
                 lastIndex = temp;
@@ -1459,28 +1420,20 @@
             if (scrollRange == 0) {
                 return 0;
             } else {
-                // TODO: do different behavior if it's  a live wallpaper?
                 // Sometimes the left parameter of the pages is animated during a layout transition;
                 // this parameter offsets it to keep the wallpaper from animating as well
                 int adjustedScroll =
                         getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0);
                 float offset = Math.min(1, adjustedScroll / (float) scrollRange);
                 offset = Math.max(0, offset);
-                // Don't use up all the wallpaper parallax until you have at least
-                // MIN_PARALLAX_PAGE_SPAN pages
-                int numScrollingPages = getNumScreensExcludingEmptyAndCustom();
-                int parallaxPageSpan;
-                if (mWallpaperIsLiveWallpaper) {
-                    parallaxPageSpan = numScrollingPages - 1;
-                } else {
-                    parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);
-                }
-                mNumPagesForWallpaperParallax = parallaxPageSpan;
 
                 // On RTL devices, push the wallpaper offset to the right if we don't have enough
                 // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)
-                int padding = isLayoutRtl() ? parallaxPageSpan - numScrollingPages + 1 : 0;
-                return offset * (padding + numScrollingPages - 1) / parallaxPageSpan;
+                if (!mWallpaperIsLiveWallpaper && numScrollingPages < MIN_PARALLAX_PAGE_SPAN
+                        && mIsRtl) {
+                    return offset * (parallaxPageSpan - numScrollingPages + 1) / parallaxPageSpan;
+                }
+                return offset * (numScrollingPages - 1) / parallaxPageSpan;
             }
         }
 
@@ -1560,81 +1513,17 @@
     @Override
     public void announceForAccessibility(CharSequence text) {
         // Don't announce if apps is on top of us.
-        if (!mLauncher.isAllAppsVisible()) {
+        if (!mLauncher.isAppsViewVisible()) {
             super.announceForAccessibility(text);
         }
     }
 
-    void showOutlines() {
-        if (!workspaceInModalState() && !mIsSwitchingState) {
-            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
-            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
-            mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);
-            mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);
-            mChildrenOutlineFadeInAnimation.start();
-        }
-    }
-
-    void hideOutlines() {
-        if (!workspaceInModalState() && !mIsSwitchingState) {
-            if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();
-            if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();
-            mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);
-            mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);
-            mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);
-            mChildrenOutlineFadeOutAnimation.start();
-        }
-    }
-
     public void showOutlinesTemporarily() {
         if (!mIsPageMoving && !isTouchActive()) {
             snapToPage(mCurrentPage);
         }
     }
 
-    public void setChildrenOutlineAlpha(float alpha) {
-        mChildrenOutlineAlpha = alpha;
-        for (int i = 0; i < getChildCount(); i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            cl.setBackgroundAlpha(alpha);
-        }
-    }
-
-    public float getChildrenOutlineAlpha() {
-        return mChildrenOutlineAlpha;
-    }
-
-    private void animateBackgroundGradient(float finalAlpha, boolean animated) {
-        final DragLayer dragLayer = mLauncher.getDragLayer();
-
-        if (mBackgroundFadeInAnimation != null) {
-            mBackgroundFadeInAnimation.cancel();
-            mBackgroundFadeInAnimation = null;
-        }
-        if (mBackgroundFadeOutAnimation != null) {
-            mBackgroundFadeOutAnimation.cancel();
-            mBackgroundFadeOutAnimation = null;
-        }
-        float startAlpha = dragLayer.getBackgroundAlpha();
-        if (finalAlpha != startAlpha) {
-            if (animated) {
-                mBackgroundFadeOutAnimation =
-                        LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);
-                mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        dragLayer.setBackgroundAlpha(
-                                ((Float)animation.getAnimatedValue()).floatValue());
-                    }
-                });
-                mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
-                mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
-                mBackgroundFadeOutAnimation.start();
-            } else {
-                dragLayer.setBackgroundAlpha(finalAlpha);
-            }
-        }
-    }
-
     float backgroundAlphaInterpolator(float r) {
         float pivotA = 0.1f;
         float pivotB = 0.4f;
@@ -1648,28 +1537,38 @@
     }
 
     private void updatePageAlphaValues(int screenCenter) {
-        boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
         if (mWorkspaceFadeInAdjacentScreens &&
                 !workspaceInModalState() &&
-                !mIsSwitchingState &&
-                !isInOverscroll) {
+                !mIsSwitchingState) {
             for (int i = numCustomPages(); i < getChildCount(); i++) {
                 CellLayout child = (CellLayout) getChildAt(i);
                 if (child != null) {
                     float scrollProgress = getScrollProgress(screenCenter, child, i);
                     float alpha = 1 - Math.abs(scrollProgress);
                     child.getShortcutsAndWidgets().setAlpha(alpha);
-                    //child.setBackgroundAlphaMultiplier(1 - alpha);
                 }
             }
         }
     }
 
-    private void setChildrenBackgroundAlphaMultipliers(float a) {
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    @Override
+    public void enableAccessibleDrag(boolean enable) {
         for (int i = 0; i < getChildCount(); i++) {
             CellLayout child = (CellLayout) getChildAt(i);
-            child.setBackgroundAlphaMultiplier(a);
+            child.enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
         }
+
+        if (enable) {
+            // We need to allow our individual children to become click handlers in this case
+            setOnClickListener(null);
+        } else {
+            // Reset our click listener
+            setOnClickListener(mLauncher);
+        }
+        mLauncher.getSearchBar().enableAccessibleDrag(enable);
+        mLauncher.getHotseat().getLayout()
+            .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG);
     }
 
     public boolean hasCustomContent() {
@@ -1696,7 +1595,7 @@
             translationX = scrollRange - scrollDelta;
             progress = (scrollRange - scrollDelta) / scrollRange;
 
-            if (isLayoutRtl()) {
+            if (mIsRtl) {
                 translationX = Math.min(0, translationX);
             } else {
                 translationX = Math.max(0, translationX);
@@ -1713,7 +1612,11 @@
 
         mLastCustomContentScrollProgress = progress;
 
-        mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+        // We should only update the drag layer background alpha if we are not in all apps or the
+        // widgets tray
+        if (mState == State.NORMAL) {
+            mLauncher.getDragLayer().setBackgroundAlpha(progress == 1 ? 0 : progress * 0.8f);
+        }
 
         if (mLauncher.getHotseat() != null) {
             mLauncher.getHotseat().setTranslationX(translationX);
@@ -1738,7 +1641,7 @@
         OnClickListener listener = new OnClickListener() {
             @Override
             public void onClick(View arg0) {
-                enterOverviewMode();
+                mLauncher.showOverviewMode(true);
             }
         };
         return listener;
@@ -1746,35 +1649,9 @@
 
     @Override
     protected void screenScrolled(int screenCenter) {
-        final boolean isRtl = isLayoutRtl();
-        super.screenScrolled(screenCenter);
-
         updatePageAlphaValues(screenCenter);
         updateStateForCustomContent(screenCenter);
         enableHwLayersOnVisiblePages();
-
-        boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
-
-        if (shouldOverScroll) {
-            int index = 0;
-            final int lowerIndex = 0;
-            final int upperIndex = getChildCount() - 1;
-
-            final boolean isLeftPage = mOverScrollX < 0;
-            index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex;
-
-            CellLayout cl = (CellLayout) getChildAt(index);
-            float effect = Math.abs(mOverScrollEffect);
-            cl.setOverScrollAmount(Math.abs(effect), isLeftPage);
-
-            mOverscrollEffectSet = true;
-        } else {
-            if (mOverscrollEffectSet && getChildCount() > 0) {
-                mOverscrollEffectSet = false;
-                ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false);
-                ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false);
-            }
-        }
     }
 
     protected void onAttachedToWindow() {
@@ -1798,9 +1675,6 @@
                 getPageIndicator().setOnClickListener(listener);
             }
         }
-        AccessibilityManager am = (AccessibilityManager)
-                getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-        sAccessibilityEnabled = am.isEnabled();
 
         // Update wallpaper dimensions if they were changed since last onResume
         // (we also always set the wallpaper dimensions in the constructor)
@@ -1832,7 +1706,7 @@
 
     @Override
     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-        if (!mLauncher.isAllAppsVisible()) {
+        if (!mLauncher.isAppsViewVisible()) {
             final Folder openFolder = getOpenFolder();
             if (openFolder != null) {
                 return openFolder.requestFocus(direction, previouslyFocusedRect);
@@ -1853,7 +1727,7 @@
 
     @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (!mLauncher.isAllAppsVisible()) {
+        if (!mLauncher.isAppsViewVisible()) {
             final Folder openFolder = getOpenFolder();
             if (openFolder != null) {
                 openFolder.addFocusables(views, direction);
@@ -1898,7 +1772,7 @@
         }
     }
 
-    private void updateChildrenLayersEnabled(boolean force) {
+    @Thunk void updateChildrenLayersEnabled(boolean force) {
         boolean small = mState == State.OVERVIEW || mIsSwitchingState;
         boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();
 
@@ -1971,64 +1845,6 @@
     }
 
     /*
-     * This interpolator emulates the rate at which the perceived scale of an object changes
-     * as its distance from a camera increases. When this interpolator is applied to a scale
-     * animation on a view, it evokes the sense that the object is shrinking due to moving away
-     * from the camera.
-     */
-    static class ZInterpolator implements TimeInterpolator {
-        private float focalLength;
-
-        public ZInterpolator(float foc) {
-            focalLength = foc;
-        }
-
-        public float getInterpolation(float input) {
-            return (1.0f - focalLength / (focalLength + input)) /
-                (1.0f - focalLength / (focalLength + 1.0f));
-        }
-    }
-
-    /*
-     * The exact reverse of ZInterpolator.
-     */
-    static class InverseZInterpolator implements TimeInterpolator {
-        private ZInterpolator zInterpolator;
-        public InverseZInterpolator(float foc) {
-            zInterpolator = new ZInterpolator(foc);
-        }
-        public float getInterpolation(float input) {
-            return 1 - zInterpolator.getInterpolation(1 - input);
-        }
-    }
-
-    /*
-     * ZInterpolator compounded with an ease-out.
-     */
-    static class ZoomOutInterpolator implements TimeInterpolator {
-        private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
-        private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
-
-        public float getInterpolation(float input) {
-            return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
-        }
-    }
-
-    /*
-     * InvereZInterpolator compounded with an ease-out.
-     */
-    static class ZoomInInterpolator implements TimeInterpolator {
-        private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
-        private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
-
-        public float getInterpolation(float input) {
-            return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
-        }
-    }
-
-    private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
-
-    /*
     *
     * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
     * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
@@ -2054,16 +1870,14 @@
 
     public void onExternalDragStartedWithItem(View v) {
         // Compose a drag bitmap with the view scaled to the icon size
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         int iconSize = grid.iconSizePx;
         int bmpWidth = v.getMeasuredWidth();
         int bmpHeight = v.getMeasuredHeight();
 
         // If this is a text view, use its drawable instead
         if (v instanceof TextView) {
-            TextView tv = (TextView) v;
-            Drawable d = tv.getCompoundDrawables()[1];
+            Drawable d = getTextViewIcon((TextView) v);
             Rect bounds = getDrawableBounds(d);
             bmpWidth = bounds.width();
             bmpHeight = bounds.height();
@@ -2081,7 +1895,7 @@
     }
 
     public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {
-        int[] size = estimateItemSize(info.spanX, info.spanY, info, false);
+        int[] size = estimateItemSize(info, false);
 
         // The outline is used to visualize where the item will land if dropped
         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);
@@ -2092,21 +1906,6 @@
         dragLayer.clearAllResizeFrames();
     }
 
-    private void initAnimationArrays() {
-        final int childCount = getChildCount();
-        if (mLastChildCount == childCount) return;
-
-        mOldBackgroundAlphas = new float[childCount];
-        mOldAlphas = new float[childCount];
-        mNewBackgroundAlphas = new float[childCount];
-        mNewAlphas = new float[childCount];
-    }
-
-    Animator getChangeStateAnimation(final State state, boolean animated,
-            ArrayList<View> layerViews) {
-        return getChangeStateAnimation(state, animated, 0, -1, layerViews);
-    }
-
     @Override
     protected void getFreeScrollPageRange(int[] range) {
         getOverviewModePages(range);
@@ -2120,14 +1919,13 @@
         range[1] = Math.max(0,  end);
     }
 
-    protected void onStartReordering() {
+    public void onStartReordering() {
         super.onStartReordering();
-        showOutlines();
         // Reordering handles its own animations, disable the automatic ones.
         disableLayoutTransitions();
     }
 
-    protected void onEndReordering() {
+    public void onEndReordering() {
         super.onEndReordering();
 
         if (mLauncher.isWorkspaceLoading()) {
@@ -2135,7 +1933,6 @@
             return;
         }
 
-        hideOutlines();
         mScreenOrder.clear();
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
@@ -2153,44 +1950,8 @@
         return mState == State.OVERVIEW;
     }
 
-    public boolean enterOverviewMode() {
-        if (mTouchState != TOUCH_STATE_REST) {
-            return false;
-        }
-        enableOverviewMode(true, -1, true);
-        return true;
-    }
-
-    public void exitOverviewMode(boolean animated) {
-        exitOverviewMode(-1, animated);
-    }
-
-    public void exitOverviewMode(int snapPage, boolean animated) {
-        enableOverviewMode(false, snapPage, animated);
-    }
-
-    private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {
-        State finalState = Workspace.State.OVERVIEW;
-        if (!enable) {
-            finalState = Workspace.State.NORMAL;
-        }
-
-        Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);
-        if (workspaceAnim != null) {
-            onTransitionPrepare();
-            workspaceAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator arg0) {
-                    onTransitionEnd();
-                }
-            });
-            workspaceAnim.start();
-        }
-    }
-
     int getOverviewModeTranslationY() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         Rect overviewBar = grid.getOverviewModeButtonBarRect();
 
         int availableHeight = getViewportHeight();
@@ -2202,332 +1963,75 @@
         return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview;
     }
 
-    public void updateInteractionForState() {
-        if (mState != State.NORMAL) {
-            mLauncher.onInteractionBegin();
-        } else {
-            mLauncher.onInteractionEnd();
-        }
-    }
+    /**
+     * Sets the current workspace {@link State}, returning an animation transitioning the workspace
+     * to that new state.
+     */
+    public Animator setStateWithAnimation(State toState, int toPage, boolean animated,
+            boolean hasOverlaySearchBar, HashMap<View, Integer> layerViews) {
+        // Create the animation to the new state
+        Animator workspaceAnim =  mStateTransitionAnimation.getAnimationToState(mState,
+                toState, toPage, animated, hasOverlaySearchBar, layerViews);
 
-    private void setState(State state) {
-        mState = state;
-        updateInteractionForState();
+        // Update the current state
+        mState = toState;
         updateAccessibilityFlags();
+
+        return workspaceAnim;
     }
 
     State getState() {
         return mState;
     }
 
-    private void updateAccessibilityFlags() {
-        int accessible = mState == State.NORMAL ?
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
-        setImportantForAccessibility(accessible);
+    public void updateAccessibilityFlags() {
+        if (Utilities.isLmpOrAbove()) {
+            int total = getPageCount();
+            for (int i = numCustomPages(); i < total; i++) {
+                updateAccessibilityFlags((CellLayout) getPageAt(i), i);
+            }
+            setImportantForAccessibility((mState == State.NORMAL || mState == State.OVERVIEW)
+                    ? IMPORTANT_FOR_ACCESSIBILITY_AUTO
+                            : IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+        } else {
+            int accessible = mState == State.NORMAL ?
+                    IMPORTANT_FOR_ACCESSIBILITY_AUTO :
+                        IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+            setImportantForAccessibility(accessible);
+        }
     }
 
-    private static final int HIDE_WORKSPACE_DURATION = 100;
+    private void updateAccessibilityFlags(CellLayout page, int pageNo) {
+        if (mState == State.OVERVIEW) {
+            page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            page.getShortcutsAndWidgets().setImportantForAccessibility(
+                    IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            page.setContentDescription(getPageDescription(pageNo));
 
-    Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {
-        return getChangeStateAnimation(state, animated, delay, snapPage, null);
-    }
-
-    Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage,
-            ArrayList<View> layerViews) {
-        if (mState == state) {
-            return null;
-        }
-
-        // Initialize animation arrays for the first time if necessary
-        initAnimationArrays();
-
-        AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
-
-        // We only want a single instance of a workspace animation to be running at once, so
-        // we cancel any incomplete transition.
-        if (mStateAnimator != null) {
-            mStateAnimator.cancel();
-        }
-        mStateAnimator = anim;
-
-        final State oldState = mState;
-        final boolean oldStateIsNormal = (oldState == State.NORMAL);
-        final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
-        final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);
-        final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);
-        final boolean oldStateIsOverview = (oldState == State.OVERVIEW);
-        setState(state);
-        final boolean stateIsNormal = (state == State.NORMAL);
-        final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
-        final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);
-        final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);
-        final boolean stateIsOverview = (state == State.OVERVIEW);
-        float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
-        float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
-        float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
-        float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;
-        float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
-                getOverviewModeTranslationY() : 0;
-
-        boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);
-        boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);
-        boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);
-        boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);
-        boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);
-
-        mNewScale = 1.0f;
-
-        if (oldStateIsOverview) {
-            disableFreeScroll();
-        } else if (stateIsOverview) {
-            enableFreeScroll();
-        }
-
-        if (state != State.NORMAL) {
-            if (stateIsSpringLoaded) {
-                mNewScale = mSpringLoadedShrinkFactor;
-            } else if (stateIsOverview || stateIsOverviewHidden) {
-                mNewScale = mOverviewModeShrinkFactor;
+            if (mPagesAccessibilityDelegate == null) {
+                mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this);
             }
-        }
-
-        final int duration;
-        if (workspaceToAllApps || overviewToAllApps) {
-            duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
-        } else if (workspaceToOverview || overviewToWorkspace) {
-            duration = getResources().getInteger(R.integer.config_overviewTransitionTime);
+            page.setAccessibilityDelegate(mPagesAccessibilityDelegate);
         } else {
-            duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
-        }
-
-        if (snapPage == -1) {
-            snapPage = getPageNearestToCenterOfScreen();
-        }
-        snapToPage(snapPage, duration, mZoomInInterpolator);
-
-        for (int i = 0; i < getChildCount(); i++) {
-            final CellLayout cl = (CellLayout) getChildAt(i);
-            boolean isCurrentPage = (i == snapPage);
-            float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
-            float finalAlpha;
-            if (stateIsNormalHidden || stateIsOverviewHidden) {
-                finalAlpha = 0f;
-            } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
-                finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;
-            } else {
-                finalAlpha = 1f;
-            }
-
-            // If we are animating to/from the small state, then hide the side pages and fade the
-            // current page in
-            if (!mIsSwitchingState) {
-                if (workspaceToAllApps || allAppsToWorkspace) {
-                    if (allAppsToWorkspace && isCurrentPage) {
-                        initialAlpha = 0f;
-                    } else if (!isCurrentPage) {
-                        initialAlpha = finalAlpha = 0f;
-                    }
-                    cl.setShortcutAndWidgetAlpha(initialAlpha);
-                }
-            }
-
-            mOldAlphas[i] = initialAlpha;
-            mNewAlphas[i] = finalAlpha;
-            if (animated) {
-                mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
-                mNewBackgroundAlphas[i] = finalBackgroundAlpha;
-            } else {
-                cl.setBackgroundAlpha(finalBackgroundAlpha);
-                cl.setShortcutAndWidgetAlpha(finalAlpha);
-            }
-        }
-
-        final View searchBar = mLauncher.getQsbBar();
-        final View overviewPanel = mLauncher.getOverviewPanel();
-        final View hotseat = mLauncher.getHotseat();
-        final View pageIndicator = getPageIndicator();
-        if (animated) {
-            LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);
-            scale.scaleX(mNewScale)
-                .scaleY(mNewScale)
-                .translationY(finalWorkspaceTranslationY)
-                .setDuration(duration)
-                .setInterpolator(mZoomInInterpolator);
-            anim.play(scale);
-            for (int index = 0; index < getChildCount(); index++) {
-                final int i = index;
-                final CellLayout cl = (CellLayout) getChildAt(i);
-                float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
-                if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
-                    cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
-                    cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
-                } else {
-                    if (layerViews != null) {
-                        layerViews.add(cl);
-                    }
-                    if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
-                        LauncherViewPropertyAnimator alphaAnim =
-                            new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
-                        alphaAnim.alpha(mNewAlphas[i])
-                            .setDuration(duration)
-                            .setInterpolator(mZoomInInterpolator);
-                        anim.play(alphaAnim);
-                    }
-                    if (mOldBackgroundAlphas[i] != 0 ||
-                        mNewBackgroundAlphas[i] != 0) {
-                        ValueAnimator bgAnim =
-                                LauncherAnimUtils.ofFloat(cl, 0f, 1f);
-                        bgAnim.setInterpolator(mZoomInInterpolator);
-                        bgAnim.setDuration(duration);
-                        bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
-                                public void onAnimationUpdate(float a, float b) {
-                                    cl.setBackgroundAlpha(
-                                            a * mOldBackgroundAlphas[i] +
-                                            b * mNewBackgroundAlphas[i]);
-                                }
-                            });
-                        anim.play(bgAnim);
-                    }
-                }
-            }
-            Animator pageIndicatorAlpha = null;
-            if (pageIndicator != null) {
-                pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)
-                    .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
-                pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));
-            } else {
-                // create a dummy animation so we don't need to do null checks later
-                pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);
-            }
-
-            Animator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)
-                .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
-            hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));
-
-            Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)
-                .alpha(finalOverviewPanelAlpha).withLayer();
-            overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));
-
-            // For animation optimations, we may need to provide the Launcher transition
-            // with a set of views on which to force build layers in certain scenarios.
-            hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            if (layerViews != null) {
-                layerViews.add(hotseat);
-                layerViews.add(overviewPanel);
-            }
-
-            if (workspaceToOverview) {
-                pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));
-                hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
-                overviewPanelAlpha.setInterpolator(null);
-            } else if (overviewToWorkspace) {
-                pageIndicatorAlpha.setInterpolator(null);
-                hotseatAlpha.setInterpolator(null);
-                overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
-            }
-
-            overviewPanelAlpha.setDuration(duration);
-            pageIndicatorAlpha.setDuration(duration);
-            hotseatAlpha.setDuration(duration);
-
-            if (searchBar != null) {
-                Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
-                    .alpha(finalSearchBarAlpha).withLayer();
-                searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));
-                searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-                if (layerViews != null) {
-                    layerViews.add(searchBar);
-                }
-                searchBarAlpha.setDuration(duration);
-                anim.play(searchBarAlpha);
-            }
-
-            anim.play(overviewPanelAlpha);
-            anim.play(hotseatAlpha);
-            anim.play(pageIndicatorAlpha);
-            anim.setStartDelay(delay);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mStateAnimator = null;
-                }
-            });
-        } else {
-            overviewPanel.setAlpha(finalOverviewPanelAlpha);
-            AlphaUpdateListener.updateVisibility(overviewPanel);
-            hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);
-            AlphaUpdateListener.updateVisibility(hotseat);
-            if (pageIndicator != null) {
-                pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);
-                AlphaUpdateListener.updateVisibility(pageIndicator);
-            }
-            if (searchBar != null) {
-                searchBar.setAlpha(finalSearchBarAlpha);
-                AlphaUpdateListener.updateVisibility(searchBar);
-            }
-            updateCustomContentVisibility();
-            setScaleX(mNewScale);
-            setScaleY(mNewScale);
-            setTranslationY(finalWorkspaceTranslationY);
-        }
-
-        if (stateIsNormal) {
-            animateBackgroundGradient(0f, animated);
-        } else {
-            animateBackgroundGradient(getResources().getInteger(
-                    R.integer.config_workspaceScrimAlpha) / 100f, animated);
-        }
-        return anim;
-    }
-
-    static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener {
-        View view;
-        public AlphaUpdateListener(View v) {
-            view = v;
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator arg0) {
-            updateVisibility(view);
-        }
-
-        public static void updateVisibility(View view) {
-            // We want to avoid the extra layout pass by setting the views to GONE unless
-            // accessibility is on, in which case not setting them to GONE causes a glitch.
-            int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE;
-            if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
-                view.setVisibility(invisibleState);
-            } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
-                    && view.getVisibility() != VISIBLE) {
-                view.setVisibility(VISIBLE);
-            }
-        }
-
-        @Override
-        public void onAnimationCancel(Animator arg0) {
-        }
-
-        @Override
-        public void onAnimationEnd(Animator arg0) {
-            updateVisibility(view);
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator arg0) {
-        }
-
-        @Override
-        public void onAnimationStart(Animator arg0) {
-            // We want the views to be visible for animation, so fade-in/out is visible
-            view.setVisibility(VISIBLE);
+            int accessible = mState == State.NORMAL ?
+                    IMPORTANT_FOR_ACCESSIBILITY_AUTO :
+                        IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
+            page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
+            page.getShortcutsAndWidgets().setImportantForAccessibility(accessible);
+            page.setContentDescription(null);
+            page.setAccessibilityDelegate(null);
         }
     }
 
     @Override
     public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
-        onTransitionPrepare();
+        mIsSwitchingState = true;
+
+        // Invalidate here to ensure that the pages are rendered during the state change transition.
+        invalidate();
+
+        updateChildrenLayersEnabled(false);
+        hideCustomContentIfNecessary();
     }
 
     @Override
@@ -2541,17 +2045,9 @@
 
     @Override
     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        onTransitionEnd();
-    }
-
-    private void onTransitionPrepare() {
-        mIsSwitchingState = true;
-
-        // Invalidate here to ensure that the pages are rendered during the state change transition.
-        invalidate();
-
+        mIsSwitchingState = false;
         updateChildrenLayersEnabled(false);
-        hideCustomContentIfNecessary();
+        showCustomContentIfNecessary();
     }
 
     void updateCustomContentVisibility() {
@@ -2577,15 +2073,17 @@
         }
     }
 
-    private void onTransitionEnd() {
-        mIsSwitchingState = false;
-        updateChildrenLayersEnabled(false);
-        showCustomContentIfNecessary();
-    }
-
-    @Override
-    public View getContent() {
-        return this;
+    /**
+     * Returns the drawable for the given text view.
+     */
+    public static Drawable getTextViewIcon(TextView tv) {
+        final Drawable[] drawables = tv.getCompoundDrawables();
+        for (int i = 0; i < drawables.length; i++) {
+            if (drawables[i] != null) {
+                return drawables[i];
+            }
+        }
+        return null;
     }
 
     /**
@@ -2603,7 +2101,7 @@
 
         destCanvas.save();
         if (v instanceof TextView) {
-            Drawable d = ((TextView) v).getCompoundDrawables()[1];
+            Drawable d = getTextViewIcon((TextView) v);
             Rect bounds = getDrawableBounds(d);
             clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);
             destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);
@@ -2640,7 +2138,7 @@
 
         int padding = expectedPadding.get();
         if (v instanceof TextView) {
-            Drawable d = ((TextView) v).getCompoundDrawables()[1];
+            Drawable d = getTextViewIcon((TextView) v);
             Rect bounds = getDrawableBounds(d);
             b = Bitmap.createBitmap(bounds.width() + padding,
                     bounds.height() + padding, Bitmap.Config.ARGB_8888);
@@ -2701,7 +2199,12 @@
         return b;
     }
 
-    void startDrag(CellLayout.CellInfo cellInfo) {
+    public void startDrag(CellLayout.CellInfo cellInfo) {
+        startDrag(cellInfo, false);
+    }
+
+    @Override
+    public void startDrag(CellLayout.CellInfo cellInfo, boolean accessible) {
         View child = cellInfo.cell;
 
         // Make sure the drag was started by a long press as opposed to a long click.
@@ -2714,10 +2217,15 @@
         CellLayout layout = (CellLayout) child.getParent().getParent();
         layout.prepareChildForDrag(child);
 
-        beginDragShared(child, this);
+        beginDragShared(child, this, accessible);
     }
 
-    public void beginDragShared(View child, DragSource source) {
+    public void beginDragShared(View child, DragSource source, boolean accessible) {
+        beginDragShared(child, new Point(), source, accessible);
+    }
+
+    public void beginDragShared(View child, Point relativeTouchPos, DragSource source,
+            boolean accessible) {
         child.clearFocus();
         child.setPressed(false);
 
@@ -2737,16 +2245,27 @@
         int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2
                         - padding.get() / 2);
 
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         Point dragVisualizeOffset = null;
         Rect dragRect = null;
         if (child instanceof BubbleTextView) {
+            BubbleTextView icon = (BubbleTextView) child;
             int iconSize = grid.iconSizePx;
             int top = child.getPaddingTop();
             int left = (bmpWidth - iconSize) / 2;
             int right = left + iconSize;
             int bottom = top + iconSize;
+            if (icon.isLayoutHorizontal()) {
+                // If the layout is horizontal, then if we are just picking up the icon, then just
+                // use the child position since the icon is top-left aligned.  Otherwise, offset
+                // the drag layer position horizontally so that the icon is under the current
+                // touch position.
+                if (icon.getIcon().getBounds().contains(relativeTouchPos.x, relativeTouchPos.y)) {
+                    dragLayerX = Math.round(mTempXY[0]);
+                } else {
+                    dragLayerX = Math.round(mTempXY[0] + relativeTouchPos.x - (bmpWidth / 2));
+                }
+            }
             dragLayerY += top;
             // Note: The drag region is used to calculate drag layer offsets, but the
             // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
@@ -2771,7 +2290,7 @@
         }
 
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
-                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
+                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, accessible);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
 
         if (child.getParent() instanceof ShortcutAndWidgetContainer) {
@@ -2782,8 +2301,7 @@
     }
 
     public void beginExternalDragShared(View child, DragSource source) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        DeviceProfile grid = mLauncher.getDeviceProfile();
         int iconSize = grid.iconSizePx;
 
         // Notify launcher of drag start
@@ -2821,25 +2339,13 @@
 
         // Start the drag
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
-                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
+                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, false);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
 
         // Recycle temporary bitmaps
         tmpB.recycle();
     }
 
-    void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,
-            int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {
-        View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);
-
-        final int[] cellXY = new int[2];
-        target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);
-        addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);
-
-        LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],
-                cellXY[1]);
-    }
-
     public boolean transitionStateShouldAllowDrop() {
         return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&
                 (mState == State.NORMAL || mState == State.SPRING_LOADED));
@@ -2858,8 +2364,7 @@
             }
             if (!transitionStateShouldAllowDrop()) return false;
 
-            mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
-                    d.dragView, mDragViewVisualCenter);
+            mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
 
             // We want the point to be mapped to the dragTarget.
             if (mLauncher.isHotseatLayout(dropTargetLayout)) {
@@ -3060,10 +2565,11 @@
         return false;
     }
 
-    public void onDrop(final DragObject d) {
-        mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,
-                mDragViewVisualCenter);
+    @Override
+    public void prepareAccessibilityDrop() { }
 
+    public void onDrop(final DragObject d) {
+        mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
         CellLayout dropTargetLayout = mDropToLayout;
 
         // We want the point to be mapped to the dragTarget.
@@ -3075,7 +2581,7 @@
             }
         }
 
-        int snapScreen = -1;
+        int snapScreen = WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE;
         boolean resizeOnDrop = false;
         if (d.dragSource != this) {
             final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
@@ -3178,9 +2684,9 @@
                         // in its final location
 
                         final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
-                        AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
-                        if (pinfo != null &&
-                                pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
+                        AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
+                        if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE
+                                && !d.accessibleDrag) {
                             final Runnable addResizeFrame = new Runnable() {
                                 public void run() {
                                     DragLayer dragLayer = mLauncher.getDragLayer();
@@ -3228,13 +2734,17 @@
             mAnimatingViewIntoPlace = true;
             if (d.dragView.hasDrawn()) {
                 final ItemInfo info = (ItemInfo) cell.getTag();
-                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
+                boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                        || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+                if (isWidget) {
                     int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :
                             ANIMATE_INTO_POSITION_AND_DISAPPEAR;
                     animateWidgetDrop(info, parent, d.dragView,
                             onCompleteRunnable, animationType, cell, false);
                 } else {
-                    int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
+                    int duration = snapScreen < 0 ?
+                            WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE :
+                                    ADJACENT_SCREEN_DROP_DURATION;
                     mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
                             onCompleteRunnable, this);
                 }
@@ -3246,26 +2756,26 @@
         }
     }
 
-    public void setFinalScrollForPageChange(int pageIndex) {
-        CellLayout cl = (CellLayout) getChildAt(pageIndex);
-        if (cl != null) {
-            mSavedScrollX = getScrollX();
-            mSavedTranslationX = cl.getTranslationX();
-            mSavedRotationY = cl.getRotationY();
-            final int newX = getScrollForPage(pageIndex);
-            setScrollX(newX);
-            cl.setTranslationX(0f);
-            cl.setRotationY(0f);
+    /**
+     * Computes the area relative to dragLayer which is used to display a page.
+     */
+    public void getPageAreaRelativeToDragLayer(Rect outArea) {
+        CellLayout child = (CellLayout) getChildAt(getNextPage());
+        if (child == null) {
+            return;
         }
-    }
+        ShortcutAndWidgetContainer boundingLayout = child.getShortcutsAndWidgets();
 
-    public void resetFinalScrollForPageChange(int pageIndex) {
-        if (pageIndex >= 0) {
-            CellLayout cl = (CellLayout) getChildAt(pageIndex);
-            setScrollX(mSavedScrollX);
-            cl.setTranslationX(mSavedTranslationX);
-            cl.setRotationY(mSavedRotationY);
-        }
+        // Use the absolute left instead of the child left, as we want the visible area
+        // irrespective of the visible child. Since the view can only scroll horizontally, the
+        // top position is not affected.
+        mTempXY[0] = getViewportOffsetX() + getPaddingLeft() + boundingLayout.getLeft();
+        mTempXY[1] = child.getTop() + boundingLayout.getTop();
+
+        float scale = mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempXY);
+        outArea.set(mTempXY[0], mTempXY[1],
+                (int) (mTempXY[0] + scale * boundingLayout.getMeasuredWidth()),
+                (int) (mTempXY[1] + scale * boundingLayout.getMeasuredHeight()));
     }
 
     public void getViewLocationRelativeToSelf(View v, int[] location) {
@@ -3281,8 +2791,12 @@
         location[1] = vY - y;
     }
 
+    @Override
     public void onDragEnter(DragObject d) {
-        mDragEnforcer.onDragEnter();
+        if (ENFORCE_DRAG_EVENT_ORDER) {
+            enfoceDragParity("onDragEnter", 1, 1);
+        }
+
         mCreateUserFolderOnDrop = false;
         mAddToExistingFolderOnDrop = false;
 
@@ -3300,42 +2814,46 @@
      * widthGap/heightGap (right, bottom) */
     static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
         LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+        InvariantDeviceProfile inv = app.getInvariantDeviceProfile();
 
         Display display = launcher.getWindowManager().getDefaultDisplay();
         Point smallestSize = new Point();
         Point largestSize = new Point();
         display.getCurrentSizeRange(smallestSize, largestSize);
-        int countX = (int) grid.numColumns;
-        int countY = (int) grid.numRows;
+        int countX = (int) inv.numColumns;
+        int countY = (int) inv.numRows;
+        boolean isLayoutRtl = Utilities.isRtl(launcher.getResources());
         if (orientation == CellLayout.LANDSCAPE) {
             if (mLandscapeCellLayoutMetrics == null) {
-                Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);
+                Rect padding = inv.landscapeProfile.getWorkspacePadding(isLayoutRtl);
                 int width = largestSize.x - padding.left - padding.right;
                 int height = smallestSize.y - padding.top - padding.bottom;
                 mLandscapeCellLayoutMetrics = new Rect();
                 mLandscapeCellLayoutMetrics.set(
-                        grid.calculateCellWidth(width, countX),
-                        grid.calculateCellHeight(height, countY), 0, 0);
+                        DeviceProfile.calculateCellWidth(width, countX),
+                        DeviceProfile.calculateCellHeight(height, countY), 0, 0);
             }
             return mLandscapeCellLayoutMetrics;
         } else if (orientation == CellLayout.PORTRAIT) {
             if (mPortraitCellLayoutMetrics == null) {
-                Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);
+                Rect padding = inv.portraitProfile.getWorkspacePadding(isLayoutRtl);
                 int width = smallestSize.x - padding.left - padding.right;
                 int height = largestSize.y - padding.top - padding.bottom;
                 mPortraitCellLayoutMetrics = new Rect();
                 mPortraitCellLayoutMetrics.set(
-                        grid.calculateCellWidth(width, countX),
-                        grid.calculateCellHeight(height, countY), 0, 0);
+                        DeviceProfile.calculateCellWidth(width, countX),
+                        DeviceProfile.calculateCellHeight(height, countY), 0, 0);
             }
             return mPortraitCellLayoutMetrics;
         }
         return null;
     }
 
+    @Override
     public void onDragExit(DragObject d) {
-        mDragEnforcer.onDragExit();
+        if (ENFORCE_DRAG_EVENT_ORDER) {
+            enfoceDragParity("onDragExit", -1, 0);
+        }
 
         // Here we store the final page that will be dropped to, if the workspace in fact
         // receives the drop
@@ -3364,12 +2882,27 @@
 
         mSpringLoadedDragController.cancel();
 
-        if (!mIsPageMoving) {
-            hideOutlines();
-        }
         mLauncher.getDragLayer().hidePageHints();
     }
 
+    private void enfoceDragParity(String event, int update, int expectedValue) {
+        enfoceDragParity(this, event, update, expectedValue);
+        for (int i = 0; i < getChildCount(); i++) {
+            enfoceDragParity(getChildAt(i), event, update, expectedValue);
+        }
+    }
+
+    private void enfoceDragParity(View v, String event, int update, int expectedValue) {
+        Object tag = v.getTag(R.id.drag_event_parity);
+        int value = tag == null ? 0 : (Integer) tag;
+        value += update;
+        v.setTag(R.id.drag_event_parity, value);
+
+        if (value != expectedValue) {
+            Log.e(TAG, event + ": Drag contract violated: " + value);
+        }
+    }
+
     void setCurrentDropLayout(CellLayout layout) {
         if (mDragTargetLayout != null) {
             mDragTargetLayout.revertTempState();
@@ -3473,8 +3006,7 @@
        mTempPt[1] = y;
        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);
 
-       LauncherAppState app = LauncherAppState.getInstance();
-       DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+       DeviceProfile grid = mLauncher.getDeviceProfile();
        r = grid.getHotseatRect();
        if (r.contains(mTempPt[0], mTempPt[1])) {
            return true;
@@ -3568,38 +3100,6 @@
         return bestMatchingScreen;
     }
 
-    // This is used to compute the visual center of the dragView. This point is then
-    // used to visualize drop locations and determine where to drop an item. The idea is that
-    // the visual center represents the user's interpretation of where the item is, and hence
-    // is the appropriate point to use when determining drop location.
-    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
-            DragView dragView, float[] recycle) {
-        float res[];
-        if (recycle == null) {
-            res = new float[2];
-        } else {
-            res = recycle;
-        }
-
-        // First off, the drag view has been shifted in a way that is not represented in the
-        // x and y values or the x/yOffsets. Here we account for that shift.
-        x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
-        y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
-
-        // These represent the visual top and left of drag view if a dragRect was provided.
-        // If a dragRect was not provided, then they correspond to the actual view left and
-        // top, as the dragRect is in that case taken to be the entire dragView.
-        // R.dimen.dragViewOffsetY.
-        int left = x - xOffset;
-        int top = y - yOffset;
-
-        // In order to find the visual center, we shift by half the dragRect
-        res[0] = left + dragView.getDragRegion().width() / 2;
-        res[1] = top + dragView.getDragRegion().height() / 2;
-
-        return res;
-    }
-
     private boolean isDragWidget(DragObject d) {
         return (d.dragInfo instanceof LauncherAppWidgetInfo ||
                 d.dragInfo instanceof PendingAddWidgetInfo);
@@ -3624,8 +3124,7 @@
 
         // Ensure that we have proper spans for the item that we are dropping
         if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");
-        mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,
-            d.dragView, mDragViewVisualCenter);
+        mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter);
 
         final View child = (mDragInfo == null) ? null : mDragInfo.cell;
         // Identify whether we have dragged over a side page
@@ -3700,7 +3199,7 @@
                     mTargetCell[1]);
 
             manageFolderFeedback(info, mDragTargetLayout, mTargetCell,
-                    targetCellDistance, dragOverView);
+                    targetCellDistance, dragOverView, d.accessibleDrag);
 
             boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)
                     mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,
@@ -3738,15 +3237,21 @@
     }
 
     private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,
-            int[] targetCell, float distance, View dragOverView) {
+            int[] targetCell, float distance, View dragOverView, boolean accessibleDrag) {
         boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,
                 false);
-
         if (mDragMode == DRAG_MODE_NONE && userFolderPending &&
                 !mFolderCreationAlarm.alarmPending()) {
-            mFolderCreationAlarm.setOnAlarmListener(new
-                    FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));
-            mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
+
+            FolderCreationAlarmListener listener = new
+                    FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]);
+
+            if (!accessibleDrag) {
+                mFolderCreationAlarm.setOnAlarmListener(listener);
+                mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
+            } else {
+                listener.onAlarm(mFolderCreationAlarm);
+            }
             return;
         }
 
@@ -3950,26 +3455,14 @@
 
                     // When dragging and dropping from customization tray, we deal with creating
                     // widgets/shortcuts/folders in a slightly different way
-                    switch (pendingInfo.itemType) {
-                    case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        int span[] = new int[2];
-                        span[0] = item.spanX;
-                        span[1] = item.spanY;
-                        mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,
-                                container, screenId, mTargetCell, span, null);
-                        break;
-                    case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        mLauncher.processShortcutFromDrop(pendingInfo.componentName,
-                                container, screenId, mTargetCell, null);
-                        break;
-                    default:
-                        throw new IllegalStateException("Unknown item type: " +
-                                pendingInfo.itemType);
-                    }
+                    mLauncher.addPendingItem(pendingInfo, container, screenId, mTargetCell,
+                            item.spanX, item.spanY);
                 }
             };
-            View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
-                    ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
+            boolean isWidget = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
+                    || pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
+            View finalView = isWidget ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
 
             if (finalView instanceof AppWidgetHostView && updateWidgetSize) {
                 AppWidgetHostView awhv = (AppWidgetHostView) finalView;
@@ -3978,7 +3471,7 @@
             }
 
             int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
-            if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&
+            if (isWidget && ((PendingAddWidgetInfo) pendingInfo).info != null &&
                     ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {
                 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;
             }
@@ -3993,10 +3486,9 @@
             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 if (info.container == NO_ID && info instanceof AppInfo) {
                     // Came from all apps -- make a copy
-                    info = new ShortcutInfo((AppInfo) info);
+                    info = ((AppInfo) info).makeShortcut();
                 }
-                view = mLauncher.createShortcut(R.layout.application, cellLayout,
-                        (ShortcutInfo) info);
+                view = mLauncher.createShortcut(cellLayout, (ShortcutInfo) info);
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,
@@ -4055,8 +3547,7 @@
     }
 
     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {
-        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,
-                widgetInfo.spanY, widgetInfo, false);
+        int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo, false);
         int visibility = layout.getVisibility();
         layout.setVisibility(VISIBLE);
 
@@ -4127,14 +3618,16 @@
 
         // In the case where we've prebound the widget, we remove it from the DragLayer
         if (finalView instanceof AppWidgetHostView && external) {
-            Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");
             mLauncher.getDragLayer().removeView(finalView);
         }
+
+        boolean isWidget = info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET ||
+                info.itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
         if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {
             Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);
             dragView.setCrossFadeBitmap(crossFadeBitmap);
             dragView.crossFade((int) (duration * 0.8f));
-        } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {
+        } else if (isWidget && external) {
             scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);
         }
 
@@ -4170,8 +3663,8 @@
     public void setFinalTransitionTransform(CellLayout layout) {
         if (isSwitchingState()) {
             mCurrentScale = getScaleX();
-            setScaleX(mNewScale);
-            setScaleY(mNewScale);
+            setScaleX(mStateTransitionAnimation.getFinalScale());
+            setScaleY(mStateTransitionAnimation.getFinalScale());
         }
     }
     public void resetTransitionTransform(CellLayout layout) {
@@ -4208,7 +3701,7 @@
      *
      * pixelX and pixelY should be in the coordinate system of layout
      */
-    private int[] findNearestArea(int pixelX, int pixelY,
+    @Thunk int[] findNearestArea(int pixelX, int pixelY,
             int spanX, int spanY, CellLayout layout, int[] recycle) {
         return layout.findNearestArea(
                 pixelX, pixelY, spanX, spanY, recycle);
@@ -4242,30 +3735,17 @@
 
         if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {
             if (target != this && mDragInfo != null) {
-                CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);
-                if (parentCell != null) {
-                    parentCell.removeView(mDragInfo.cell);
-                } else if (LauncherAppState.isDogfoodBuild()) {
-                    throw new NullPointerException("mDragInfo.cell has null parent");
-                }
-                if (mDragInfo.cell instanceof DropTarget) {
-                    mDragController.removeDropTarget((DropTarget) mDragInfo.cell);
-                }
+                removeWorkspaceItem(mDragInfo.cell);
             }
         } else if (mDragInfo != null) {
-            CellLayout cellLayout;
-            if (mLauncher.isHotseatLayout(target)) {
-                cellLayout = mLauncher.getHotseat().getLayout();
-            } else {
-                cellLayout = getScreenWithId(mDragInfo.screenId);
-            }
-            if (cellLayout == null && LauncherAppState.isDogfoodBuild()) {
-                throw new RuntimeException("Invalid state: cellLayout == null in "
-                        + "Workspace#onDropCompleted. Please file a bug. ");
-            }
+            final CellLayout cellLayout = mLauncher.getCellLayout(
+                    mDragInfo.container, mDragInfo.screenId);
             if (cellLayout != null) {
                 cellLayout.onDropChild(mDragInfo.cell);
-            }
+            } else if (LauncherAppState.isDogfoodBuild()) {
+                throw new RuntimeException("Invalid state: cellLayout == null in "
+                        + "Workspace#onDropCompleted. Please file a bug. ");
+            };
         }
         if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))
                 && mDragInfo.cell != null) {
@@ -4275,11 +3755,28 @@
         mDragInfo = null;
     }
 
+    /**
+     * For opposite operation. See {@link #addInScreen}.
+     */
+    public void removeWorkspaceItem(View v) {
+        CellLayout parentCell = getParentCellLayoutForView(v);
+        if (parentCell != null) {
+            parentCell.removeView(v);
+        } else if (LauncherAppState.isDogfoodBuild()) {
+            throw new NullPointerException("mDragInfo.cell has null parent");
+        }
+        if (v instanceof DropTarget) {
+            mDragController.removeDropTarget((DropTarget) v);
+        }
+    }
+
+    @Override
     public void deferCompleteDropAfterUninstallActivity() {
         mDeferDropAfterUninstall = true;
     }
 
     /// maybe move this into a smaller part
+    @Override
     public void onUninstallActivityReturned(boolean success) {
         mDeferDropAfterUninstall = false;
         mUninstallSuccessful = success;
@@ -4311,88 +3808,6 @@
         }
     }
 
-    ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplicates) {
-        ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();
-        getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, false);
-        int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            CellLayout cl = (CellLayout) getChildAt(i);
-            getUniqueIntents(cl, uniqueIntents, duplicates, false);
-        }
-        return uniqueIntents;
-    }
-
-    void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,
-            ArrayList<ComponentName> duplicates, boolean stripDuplicates) {
-        int count = cl.getShortcutsAndWidgets().getChildCount();
-
-        ArrayList<View> children = new ArrayList<View>();
-        for (int i = 0; i < count; i++) {
-            View v = cl.getShortcutsAndWidgets().getChildAt(i);
-            children.add(v);
-        }
-
-        for (int i = 0; i < count; i++) {
-            View v = children.get(i);
-            ItemInfo info = (ItemInfo) v.getTag();
-            // Null check required as the AllApps button doesn't have an item info
-            if (info instanceof ShortcutInfo) {
-                ShortcutInfo si = (ShortcutInfo) info;
-                ComponentName cn = si.intent.getComponent();
-
-                Uri dataUri = si.intent.getData();
-                // If dataUri is not null / empty or if this component isn't one that would
-                // have previously showed up in the AllApps list, then this is a widget-type
-                // shortcut, so ignore it.
-                if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {
-                    continue;
-                }
-
-                if (!uniqueIntents.contains(cn)) {
-                    uniqueIntents.add(cn);
-                } else {
-                    if (stripDuplicates) {
-                        cl.removeViewInLayout(v);
-                        LauncherModel.deleteItemFromDatabase(mLauncher, si);
-                    }
-                    if (duplicates != null) {
-                        duplicates.add(cn);
-                    }
-                }
-            }
-            if (v instanceof FolderIcon) {
-                FolderIcon fi = (FolderIcon) v;
-                ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();
-                for (int j = 0; j < items.size(); j++) {
-                    if (items.get(j).getTag() instanceof ShortcutInfo) {
-                        ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();
-                        ComponentName cn = si.intent.getComponent();
-
-                        Uri dataUri = si.intent.getData();
-                        // If dataUri is not null / empty or if this component isn't one that would
-                        // have previously showed up in the AllApps list, then this is a widget-type
-                        // shortcut, so ignore it.
-                        if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {
-                            continue;
-                        }
-
-                        if (!uniqueIntents.contains(cn)) {
-                            uniqueIntents.add(cn);
-                        }  else {
-                            if (stripDuplicates) {
-                                fi.getFolderInfo().remove(si);
-                                LauncherModel.deleteItemFromDatabase(mLauncher, si);
-                            }
-                            if (duplicates != null) {
-                                duplicates.add(cn);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     void saveWorkspaceToDb() {
         saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
         int count = getChildCount();
@@ -4425,8 +3840,7 @@
                     cellX = hotseat.getCellXFromOrder((int) info.screenId);
                     cellY = hotseat.getCellYFromOrder((int) info.screenId);
                 }
-                LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,
-                        cellY, false);
+                LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX, cellY);
             }
             if (v instanceof FolderIcon) {
                 FolderIcon fi = (FolderIcon) v;
@@ -4456,7 +3870,7 @@
     }
 
     @Override
-    public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {
+    public void onFlingToDelete(DragObject d, PointF vec) {
         // Do nothing
     }
 
@@ -4470,12 +3884,6 @@
     }
 
     @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        super.onRestoreInstanceState(state);
-        Launcher.setScreen(mCurrentPage);
-    }
-
-    @Override
     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
         // We don't dispatch restoreInstanceState to our children using this code path.
         // Some pages will be restored immediately as their items are bound immediately, and
@@ -4529,7 +3937,7 @@
     @Override
     public boolean onEnterScrollArea(int x, int y, int direction) {
         // Ignore the scroll area if we are dragging over the hot seat
-        boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());
+        boolean isPortrait = !mLauncher.getDeviceProfile().isLandscape;
         if (mLauncher.getHotseat() != null && isPortrait) {
             Rect r = new Rect();
             mLauncher.getHotseat().getHitRect(r);
@@ -4706,7 +4114,7 @@
                             && packageNames.contains(cn.getPackageName())) {
                         shortcutInfo.isDisabled |= reason;
                         BubbleTextView shortcut = (BubbleTextView) v;
-                        shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);
+                        shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);
 
                         if (parent != null) {
                             parent.invalidate();
@@ -4890,9 +4298,9 @@
                         updates.contains(info)) {
                     ShortcutInfo si = (ShortcutInfo) info;
                     BubbleTextView shortcut = (BubbleTextView) v;
-                    boolean oldPromiseState = shortcut.getCompoundDrawables()[1]
+                    boolean oldPromiseState = getTextViewIcon(shortcut)
                             instanceof PreloadIconDrawable;
-                    shortcut.applyFromShortcutInfo(si, mIconCache, true,
+                    shortcut.applyFromShortcutInfo(si, mIconCache,
                             si.isPromise() != oldPromiseState);
 
                     if (parent != null) {
@@ -4912,31 +4320,17 @@
         removeItemsByPackageName(packages, user);
     }
 
-    public void updatePackageBadge(final String packageName, final UserHandleCompat user) {
+    public void updateRestoreItems(final HashSet<ItemInfo> updates) {
         mapOverItems(MAP_RECURSE, new ItemOperator() {
             @Override
             public boolean evaluate(ItemInfo info, View v, View parent) {
-                if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
-                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;
-                    ComponentName cn = shortcutInfo.getTargetComponent();
-                    if (user.equals(shortcutInfo.user) && cn != null
-                            && shortcutInfo.isPromise()
-                            && packageName.equals(cn.getPackageName())) {
-                        if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {
-                            // For auto install apps update the icon as well as label.
-                            mIconCache.getTitleAndIcon(shortcutInfo,
-                                    shortcutInfo.promisedIntent, user, true);
-                        } else {
-                            // Only update the icon for restored apps.
-                            shortcutInfo.updateIcon(mIconCache);
-                        }
-                        BubbleTextView shortcut = (BubbleTextView) v;
-                        shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);
-
-                        if (parent != null) {
-                            parent.invalidate();
-                        }
-                    }
+                if (info instanceof ShortcutInfo && v instanceof BubbleTextView
+                        && updates.contains(info)) {
+                    ((BubbleTextView) v).applyState(false);
+                } else if (v instanceof PendingAppWidgetHostView
+                        && info instanceof LauncherAppWidgetInfo
+                        && updates.contains(info)) {
+                    ((PendingAppWidgetHostView) v).applyState();
                 }
                 // process all the shortcuts
                 return false;
@@ -4944,48 +4338,13 @@
         });
     }
 
-    public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {
-        for (final PackageInstallInfo installInfo : installInfos) {
-            if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
-                continue;
-            }
-
-            mapOverItems(MAP_RECURSE, new ItemOperator() {
-                @Override
-                public boolean evaluate(ItemInfo info, View v, View parent) {
-                    if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {
-                        ShortcutInfo si = (ShortcutInfo) info;
-                        ComponentName cn = si.getTargetComponent();
-                        if (si.isPromise() && (cn != null)
-                                && installInfo.packageName.equals(cn.getPackageName())) {
-                            si.setInstallProgress(installInfo.progress);
-                            if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {
-                                // Mark this info as broken.
-                                si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
-                            }
-                            ((BubbleTextView)v).applyState(false);
-                        }
-                    } else if (v instanceof PendingAppWidgetHostView
-                            && info instanceof LauncherAppWidgetInfo
-                            && ((LauncherAppWidgetInfo) info).providerName.getPackageName()
-                                .equals(installInfo.packageName)) {
-                        ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress;
-                        ((PendingAppWidgetHostView) v).applyState();
-                    }
-
-                    // process all the shortcuts
-                    return false;
-                }
-            });
-        }
-    }
-
     void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) {
         if (!changedInfo.isEmpty()) {
             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
                     mLauncher.getAppWidgetHost());
-            if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(),
-                    changedInfo.get(0).providerName) != null) {
+            if (LauncherModel.getProviderInfo(getContext(),
+                    changedInfo.get(0).providerName,
+                    changedInfo.get(0).user) != null) {
                 // Re-inflate the widgets which have changed status
                 widgetRefresh.run();
             } else {
@@ -5049,25 +4408,21 @@
         return super.getPageIndicatorMarker(pageIndex);
     }
 
-    @Override
-    public void syncPages() {
-    }
-
-    @Override
-    public void syncPageItems(int page, boolean immediate) {
-    }
-
     protected String getPageIndicatorDescription() {
         String settings = getResources().getString(R.string.settings_button_text);
         return getCurrentPageDescription() + ", " + settings;
     }
 
     protected String getCurrentPageDescription() {
-        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-        int delta = numCustomPages();
         if (hasCustomContent() && getNextPage() == 0) {
             return mCustomContentDescription;
         }
+        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
+        return getPageDescription(page);
+    }
+
+    private String getPageDescription(int page) {
+        int delta = numCustomPages();
         return String.format(getContext().getString(R.string.workspace_scroll_format),
                 page + 1 - delta, getChildCount() - delta);
     }
@@ -5076,6 +4431,12 @@
         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
     }
 
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_HOMESCREEN);
+        sourceData.putInt(Stats.SOURCE_EXTRA_CONTAINER_PAGE, getCurrentPage());
+    }
+
     /**
      * Used as a workaround to ensure that the AppWidgetService receives the
      * PACKAGE_ADDED broadcast before updating widgets.
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
new file mode 100644
index 0000000..b8916a7
--- /dev/null
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.util.Thunk;
+
+import java.util.HashMap;
+
+/**
+ * A convenience class to update a view's visibility state after an alpha animation.
+ */
+class AlphaUpdateListener extends AnimatorListenerAdapter implements ValueAnimator.AnimatorUpdateListener {
+    private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
+
+    private View mView;
+    private boolean mAccessibilityEnabled;
+
+    public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
+        mView = v;
+        mAccessibilityEnabled = accessibilityEnabled;
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator arg0) {
+        updateVisibility(mView, mAccessibilityEnabled);
+    }
+
+    public static void updateVisibility(View view, boolean accessibilityEnabled) {
+        // We want to avoid the extra layout pass by setting the views to GONE unless
+        // accessibility is on, in which case not setting them to GONE causes a glitch.
+        int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
+        if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
+            view.setVisibility(invisibleState);
+        } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
+                && view.getVisibility() != View.VISIBLE) {
+            view.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @Override
+    public void onAnimationEnd(Animator arg0) {
+        updateVisibility(mView, mAccessibilityEnabled);
+    }
+
+    @Override
+    public void onAnimationStart(Animator arg0) {
+        // We want the views to be visible for animation, so fade-in/out is visible
+        mView.setVisibility(View.VISIBLE);
+    }
+}
+
+/**
+ * This interpolator emulates the rate at which the perceived scale of an object changes
+ * as its distance from a camera increases. When this interpolator is applied to a scale
+ * animation on a view, it evokes the sense that the object is shrinking due to moving away
+ * from the camera.
+ */
+class ZInterpolator implements TimeInterpolator {
+    private float focalLength;
+
+    public ZInterpolator(float foc) {
+        focalLength = foc;
+    }
+
+    public float getInterpolation(float input) {
+        return (1.0f - focalLength / (focalLength + input)) /
+                (1.0f - focalLength / (focalLength + 1.0f));
+    }
+}
+
+/**
+ * The exact reverse of ZInterpolator.
+ */
+class InverseZInterpolator implements TimeInterpolator {
+    private ZInterpolator zInterpolator;
+    public InverseZInterpolator(float foc) {
+        zInterpolator = new ZInterpolator(foc);
+    }
+    public float getInterpolation(float input) {
+        return 1 - zInterpolator.getInterpolation(1 - input);
+    }
+}
+
+/**
+ * InverseZInterpolator compounded with an ease-out.
+ */
+class ZoomInInterpolator implements TimeInterpolator {
+    private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
+    private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
+
+    public float getInterpolation(float input) {
+        return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
+    }
+}
+
+/**
+ * Stores the transition states for convenience.
+ */
+class TransitionStates {
+
+    // Raw states
+    final boolean oldStateIsNormal;
+    final boolean oldStateIsSpringLoaded;
+    final boolean oldStateIsNormalHidden;
+    final boolean oldStateIsOverviewHidden;
+    final boolean oldStateIsOverview;
+
+    final boolean stateIsNormal;
+    final boolean stateIsSpringLoaded;
+    final boolean stateIsNormalHidden;
+    final boolean stateIsOverviewHidden;
+    final boolean stateIsOverview;
+
+    // Convenience members
+    final boolean workspaceToAllApps;
+    final boolean overviewToAllApps;
+    final boolean allAppsToWorkspace;
+    final boolean workspaceToOverview;
+    final boolean overviewToWorkspace;
+
+    public TransitionStates(final Workspace.State fromState, final Workspace.State toState) {
+        oldStateIsNormal = (fromState == Workspace.State.NORMAL);
+        oldStateIsSpringLoaded = (fromState == Workspace.State.SPRING_LOADED);
+        oldStateIsNormalHidden = (fromState == Workspace.State.NORMAL_HIDDEN);
+        oldStateIsOverviewHidden = (fromState == Workspace.State.OVERVIEW_HIDDEN);
+        oldStateIsOverview = (fromState == Workspace.State.OVERVIEW);
+
+        stateIsNormal = (toState == Workspace.State.NORMAL);
+        stateIsSpringLoaded = (toState == Workspace.State.SPRING_LOADED);
+        stateIsNormalHidden = (toState == Workspace.State.NORMAL_HIDDEN);
+        stateIsOverviewHidden = (toState == Workspace.State.OVERVIEW_HIDDEN);
+        stateIsOverview = (toState == Workspace.State.OVERVIEW);
+
+        workspaceToOverview = (oldStateIsNormal && stateIsOverview);
+        workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);
+        overviewToWorkspace = (oldStateIsOverview && stateIsNormal);
+        overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);
+        allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);
+    }
+}
+
+/**
+ * Manages the animations between each of the workspace states.
+ */
+public class WorkspaceStateTransitionAnimation {
+
+    public static final String TAG = "WorkspaceStateTransitionAnimation";
+
+    public static final int SCROLL_TO_CURRENT_PAGE = -1;
+    @Thunk static final int BACKGROUND_FADE_OUT_DURATION = 350;
+
+    final @Thunk Launcher mLauncher;
+    final @Thunk Workspace mWorkspace;
+
+    @Thunk AnimatorSet mStateAnimator;
+    @Thunk float[] mOldBackgroundAlphas;
+    @Thunk float[] mOldAlphas;
+    @Thunk float[] mNewBackgroundAlphas;
+    @Thunk float[] mNewAlphas;
+    @Thunk int mLastChildCount = -1;
+
+    @Thunk float mCurrentScale;
+    @Thunk float mNewScale;
+
+    @Thunk final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
+
+    @Thunk float mSpringLoadedShrinkFactor;
+    @Thunk float mOverviewModeShrinkFactor;
+    @Thunk float mWorkspaceScrimAlpha;
+    @Thunk int mAllAppsTransitionTime;
+    @Thunk int mOverviewTransitionTime;
+    @Thunk int mOverlayTransitionTime;
+    @Thunk boolean mWorkspaceFadeInAdjacentScreens;
+
+    public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
+        mLauncher = launcher;
+        mWorkspace = workspace;
+
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        Resources res = launcher.getResources();
+        mAllAppsTransitionTime = res.getInteger(R.integer.config_allAppsTransitionTime);
+        mOverviewTransitionTime = res.getInteger(R.integer.config_overviewTransitionTime);
+        mOverlayTransitionTime = res.getInteger(R.integer.config_overlayTransitionTime);
+        mSpringLoadedShrinkFactor =
+                res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100f;
+        mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha) / 100f;
+        mOverviewModeShrinkFactor = grid.getOverviewModeScale(Utilities.isRtl(res));
+        mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
+    }
+
+    public AnimatorSet getAnimationToState(Workspace.State fromState, Workspace.State toState,
+            int toPage, boolean animated, boolean hasOverlaySearchBar,
+            HashMap<View, Integer> layerViews) {
+        AccessibilityManager am = (AccessibilityManager)
+                mLauncher.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        final boolean accessibilityEnabled = am.isEnabled();
+        TransitionStates states = new TransitionStates(fromState, toState);
+        int duration = getAnimationDuration(states);
+        animateWorkspace(states, toPage, animated, duration, layerViews,
+                accessibilityEnabled);
+        animateSearchBar(states, animated, duration, hasOverlaySearchBar, layerViews,
+                accessibilityEnabled);
+        animateBackgroundGradient(states, animated, BACKGROUND_FADE_OUT_DURATION);
+        return mStateAnimator;
+    }
+
+    public float getFinalScale() {
+        return mNewScale;
+    }
+
+    /**
+     * Reinitializes the arrays that we need for the animations on each page.
+     */
+    private void reinitializeAnimationArrays() {
+        final int childCount = mWorkspace.getChildCount();
+        if (mLastChildCount == childCount) return;
+
+        mOldBackgroundAlphas = new float[childCount];
+        mOldAlphas = new float[childCount];
+        mNewBackgroundAlphas = new float[childCount];
+        mNewAlphas = new float[childCount];
+    }
+
+    /**
+     * Returns the proper animation duration for a transition.
+     */
+    private int getAnimationDuration(TransitionStates states) {
+        if (states.workspaceToAllApps || states.overviewToAllApps) {
+            return mAllAppsTransitionTime;
+        } else if (states.workspaceToOverview || states.overviewToWorkspace) {
+            return mOverviewTransitionTime;
+        } else {
+            return mOverlayTransitionTime;
+        }
+    }
+
+    /**
+     * Starts a transition animation for the workspace.
+     */
+    private void animateWorkspace(final TransitionStates states, int toPage, final boolean animated,
+                                  final int duration, final HashMap<View, Integer> layerViews,
+                                  final boolean accessibilityEnabled) {
+        // Reinitialize animation arrays for the current workspace state
+        reinitializeAnimationArrays();
+
+        // Cancel existing workspace animations and create a new animator set if requested
+        cancelAnimation();
+        if (animated) {
+            mStateAnimator = LauncherAnimUtils.createAnimatorSet();
+        }
+
+        // Update the workspace state
+        float finalBackgroundAlpha = (states.stateIsSpringLoaded || states.stateIsOverview) ?
+                1.0f : 0f;
+        float finalHotseatAndPageIndicatorAlpha = (states.stateIsNormal || states.stateIsSpringLoaded) ?
+                1f : 0f;
+        float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
+        float finalWorkspaceTranslationY = states.stateIsOverview || states.stateIsOverviewHidden ?
+                mWorkspace.getOverviewModeTranslationY() : 0;
+
+        final int childCount = mWorkspace.getChildCount();
+        final int customPageCount = mWorkspace.numCustomPages();
+
+        mNewScale = 1.0f;
+
+        if (states.oldStateIsOverview) {
+            mWorkspace.disableFreeScroll();
+        } else if (states.stateIsOverview) {
+            mWorkspace.enableFreeScroll();
+        }
+
+        if (!states.stateIsNormal) {
+            if (states.stateIsSpringLoaded) {
+                mNewScale = mSpringLoadedShrinkFactor;
+            } else if (states.stateIsOverview || states.stateIsOverviewHidden) {
+                mNewScale = mOverviewModeShrinkFactor;
+            }
+        }
+
+        if (toPage == SCROLL_TO_CURRENT_PAGE) {
+            toPage = mWorkspace.getPageNearestToCenterOfScreen();
+        }
+        mWorkspace.snapToPage(toPage, duration, mZoomInInterpolator);
+
+        for (int i = 0; i < childCount; i++) {
+            final CellLayout cl = (CellLayout) mWorkspace.getChildAt(i);
+            boolean isCurrentPage = (i == toPage);
+            float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
+            float finalAlpha;
+            if (states.stateIsNormalHidden || states.stateIsOverviewHidden) {
+                finalAlpha = 0f;
+            } else if (states.stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
+                finalAlpha = (i == toPage || i < customPageCount) ? 1f : 0f;
+            } else {
+                finalAlpha = 1f;
+            }
+
+            // If we are animating to/from the small state, then hide the side pages and fade the
+            // current page in
+            if (!mWorkspace.isSwitchingState()) {
+                if (states.workspaceToAllApps || states.allAppsToWorkspace) {
+                    if (states.allAppsToWorkspace && isCurrentPage) {
+                        initialAlpha = 0f;
+                    } else if (!isCurrentPage) {
+                        initialAlpha = finalAlpha = 0f;
+                    }
+                    cl.setShortcutAndWidgetAlpha(initialAlpha);
+                }
+            }
+
+            mOldAlphas[i] = initialAlpha;
+            mNewAlphas[i] = finalAlpha;
+            if (animated) {
+                mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
+                mNewBackgroundAlphas[i] = finalBackgroundAlpha;
+            } else {
+                cl.setBackgroundAlpha(finalBackgroundAlpha);
+                cl.setShortcutAndWidgetAlpha(finalAlpha);
+            }
+        }
+
+        final ViewGroup overviewPanel = mLauncher.getOverviewPanel();
+        final View hotseat = mLauncher.getHotseat();
+        final View pageIndicator = mWorkspace.getPageIndicator();
+        if (animated) {
+            LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mWorkspace);
+            scale.scaleX(mNewScale)
+                    .scaleY(mNewScale)
+                    .translationY(finalWorkspaceTranslationY)
+                    .setDuration(duration)
+                    .setInterpolator(mZoomInInterpolator);
+            mStateAnimator.play(scale);
+            for (int index = 0; index < childCount; index++) {
+                final int i = index;
+                final CellLayout cl = (CellLayout) mWorkspace.getChildAt(i);
+                float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
+                if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
+                    cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
+                    cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
+                } else {
+                    if (layerViews != null) {
+                        layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
+                    }
+                    if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
+                        LauncherViewPropertyAnimator alphaAnim =
+                                new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
+                        alphaAnim.alpha(mNewAlphas[i])
+                                .setDuration(duration)
+                                .setInterpolator(mZoomInInterpolator);
+                        mStateAnimator.play(alphaAnim);
+                    }
+                    if (mOldBackgroundAlphas[i] != 0 ||
+                            mNewBackgroundAlphas[i] != 0) {
+                        ValueAnimator bgAnim = ObjectAnimator.ofFloat(cl, "backgroundAlpha",
+                                mOldBackgroundAlphas[i], mNewBackgroundAlphas[i]);
+                                LauncherAnimUtils.ofFloat(cl, 0f, 1f);
+                        bgAnim.setInterpolator(mZoomInInterpolator);
+                        bgAnim.setDuration(duration);
+                        mStateAnimator.play(bgAnim);
+                    }
+                }
+            }
+            Animator pageIndicatorAlpha;
+            if (pageIndicator != null) {
+                pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)
+                        .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
+                pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator,
+                        accessibilityEnabled));
+            } else {
+                // create a dummy animation so we don't need to do null checks later
+                pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);
+            }
+
+            LauncherViewPropertyAnimator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)
+                    .alpha(finalHotseatAndPageIndicatorAlpha);
+            hotseatAlpha.addListener(new AlphaUpdateListener(hotseat, accessibilityEnabled));
+
+            LauncherViewPropertyAnimator overviewPanelAlpha =
+                    new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOverviewPanelAlpha);
+            overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel,
+                    accessibilityEnabled));
+
+            // For animation optimations, we may need to provide the Launcher transition
+            // with a set of views on which to force build layers in certain scenarios.
+            hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            if (layerViews != null) {
+                // If layerViews is not null, we add these views, and indicate that
+                // the caller can manage layer state.
+                layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+                layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+            } else {
+                // Otherwise let the animator handle layer management.
+                hotseatAlpha.withLayer();
+                overviewPanelAlpha.withLayer();
+            }
+
+            if (states.workspaceToOverview) {
+                pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));
+                hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
+                overviewPanelAlpha.setInterpolator(null);
+            } else if (states.overviewToWorkspace) {
+                pageIndicatorAlpha.setInterpolator(null);
+                hotseatAlpha.setInterpolator(null);
+                overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
+            }
+
+            overviewPanelAlpha.setDuration(duration);
+            pageIndicatorAlpha.setDuration(duration);
+            hotseatAlpha.setDuration(duration);
+
+            mStateAnimator.play(overviewPanelAlpha);
+            mStateAnimator.play(hotseatAlpha);
+            mStateAnimator.play(pageIndicatorAlpha);
+            mStateAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mStateAnimator = null;
+
+                    if (accessibilityEnabled && overviewPanel.getVisibility() == View.VISIBLE) {
+                        overviewPanel.getChildAt(0).performAccessibilityAction(
+                                AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+                    }
+                }
+            });
+        } else {
+            overviewPanel.setAlpha(finalOverviewPanelAlpha);
+            AlphaUpdateListener.updateVisibility(overviewPanel, accessibilityEnabled);
+            hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);
+            AlphaUpdateListener.updateVisibility(hotseat, accessibilityEnabled);
+            if (pageIndicator != null) {
+                pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);
+                AlphaUpdateListener.updateVisibility(pageIndicator, accessibilityEnabled);
+            }
+            mWorkspace.updateCustomContentVisibility();
+            mWorkspace.setScaleX(mNewScale);
+            mWorkspace.setScaleY(mNewScale);
+            mWorkspace.setTranslationY(finalWorkspaceTranslationY);
+
+            if (accessibilityEnabled && overviewPanel.getVisibility() == View.VISIBLE) {
+                overviewPanel.getChildAt(0).performAccessibilityAction(
+                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+            }
+        }
+    }
+
+    /**
+     * Coordinates with the workspace animation to animate the search bar.
+     *
+     * TODO: This should really be coordinated with the SearchDropTargetBar, otherwise the
+     *       bar has no idea that it is hidden, and this has no idea what state the bar is
+     *       actually in.
+     */
+    private void animateSearchBar(TransitionStates states, boolean animated, int duration,
+            boolean hasOverlaySearchBar, final HashMap<View, Integer> layerViews,
+            final boolean accessibilityEnabled) {
+
+        // The search bar is only visible in the workspace
+        final View searchBar = mLauncher.getOrCreateQsbBar();
+        if (searchBar != null) {
+            final boolean searchBarWillBeShown = states.stateIsNormal;
+            final float finalSearchBarAlpha = searchBarWillBeShown ? 1f : 0f;
+            if (animated) {
+                if (hasOverlaySearchBar) {
+                    // If there is an overlay search bar, then we will coordinate with it.
+                    mStateAnimator.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            // If we are transitioning to a visible search bar, show it immediately
+                            // and let the overlay search bar has faded out
+                            if (searchBarWillBeShown) {
+                                searchBar.setAlpha(finalSearchBarAlpha);
+                                AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled);
+                            }
+                        }
+
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            // If we are transitioning to a hidden search bar, hide it only after
+                            // the overlay search bar has faded in
+                            if (!searchBarWillBeShown) {
+                                searchBar.setAlpha(finalSearchBarAlpha);
+                                AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled);
+                            }
+                        }
+                    });
+                } else {
+                    // Otherwise, we can just do the normal animation
+                    LauncherViewPropertyAnimator searchBarAlpha =
+                            new LauncherViewPropertyAnimator(searchBar).alpha(finalSearchBarAlpha);
+                    searchBarAlpha.addListener(new AlphaUpdateListener(searchBar,
+                            accessibilityEnabled));
+                    searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+                    if (layerViews != null) {
+                        // If layerViews is not null, we add these views, and indicate that
+                        // the caller can manage layer state.
+                        layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+                    } else {
+                        // Otherwise let the animator handle layer management.
+                        searchBarAlpha.withLayer();
+                    }
+                    searchBarAlpha.setDuration(duration);
+                    mStateAnimator.play(searchBarAlpha);
+                }
+            } else {
+                // Set the search bar state immediately
+                searchBar.setAlpha(finalSearchBarAlpha);
+                AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled);
+            }
+        }
+    }
+
+    /**
+     * Animates the background scrim. Add to the state animator to prevent jankiness.
+     *
+     * @param finalAlpha the final alpha for the background scrim
+     * @param animated whether or not to set the background alpha immediately
+     * @duration duration of the animation
+     */
+    private void animateBackgroundGradient(TransitionStates states,
+            boolean animated, int duration) {
+
+        final DragLayer dragLayer = mLauncher.getDragLayer();
+        final float startAlpha = dragLayer.getBackgroundAlpha();
+        float finalAlpha = states.stateIsNormal ? 0 : mWorkspaceScrimAlpha;
+
+        if (finalAlpha != startAlpha) {
+            if (animated) {
+                // These properties refer to the background protection gradient used for AllApps
+                // and Widget tray.
+                ValueAnimator bgFadeOutAnimation =
+                        LauncherAnimUtils.ofFloat(mWorkspace, startAlpha, finalAlpha);
+                bgFadeOutAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator animation) {
+                        dragLayer.setBackgroundAlpha(
+                                ((Float)animation.getAnimatedValue()).floatValue());
+                    }
+                });
+                bgFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
+                bgFadeOutAnimation.setDuration(duration);
+                mStateAnimator.play(bgFadeOutAnimation);
+            } else {
+                dragLayer.setBackgroundAlpha(finalAlpha);
+            }
+        }
+    }
+
+    /**
+     * Cancels the current animation.
+     */
+    private void cancelAnimation() {
+        if (mStateAnimator != null) {
+            mStateAnimator.setDuration(0);
+            mStateAnimator.cancel();
+        }
+        mStateAnimator = null;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
new file mode 100644
index 0000000..78accf7
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/DragAndDropAccessibilityDelegate.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.widget.ExploreByTouchHelper;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+
+import java.util.List;
+
+/**
+ * Helper class to make drag-and-drop in a {@link CellLayout} accessible.
+ */
+public abstract class DragAndDropAccessibilityDelegate extends ExploreByTouchHelper
+        implements OnClickListener {
+    protected static final int INVALID_POSITION = -1;
+
+    private static final int[] sTempArray = new int[2];
+
+    protected final CellLayout mView;
+    protected final Context mContext;
+    protected final LauncherAccessibilityDelegate mDelegate;
+
+    private final Rect mTempRect = new Rect();
+
+    public DragAndDropAccessibilityDelegate(CellLayout forView) {
+        super(forView);
+        mView = forView;
+        mContext = mView.getContext();
+        mDelegate = LauncherAppState.getInstance().getAccessibilityDelegate();
+    }
+
+    @Override
+    protected int getVirtualViewAt(float x, float y) {
+        if (x < 0 || y < 0 || x > mView.getMeasuredWidth() || y > mView.getMeasuredHeight()) {
+            return INVALID_ID;
+        }
+        mView.pointToCellExact((int) x, (int) y, sTempArray);
+
+        // Map cell to id
+        int id = sTempArray[0] + sTempArray[1] * mView.getCountX();
+        return intersectsValidDropTarget(id);
+    }
+
+    /**
+     * @return the view id of the top left corner of a valid drop region or
+     * {@link #INVALID_POSITION} if there is no such valid region.
+     */
+    protected abstract int intersectsValidDropTarget(int id);
+
+    @Override
+    protected void getVisibleVirtualViews(List<Integer> virtualViews) {
+        // We create a virtual view for each cell of the grid
+        // The cell ids correspond to cells in reading order.
+        int nCells = mView.getCountX() * mView.getCountY();
+
+        for (int i = 0; i < nCells; i++) {
+            if (intersectsValidDropTarget(i) == i) {
+                virtualViews.add(i);
+            }
+        }
+    }
+
+    @Override
+    protected boolean onPerformActionForVirtualView(int viewId, int action, Bundle args) {
+        if (action == AccessibilityNodeInfoCompat.ACTION_CLICK && viewId != INVALID_ID) {
+            String confirmation = getConfirmationForIconDrop(viewId);
+            mDelegate.handleAccessibleDrop(mView, getItemBounds(viewId), confirmation);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onClick(View v) {
+        onPerformActionForVirtualView(getFocusedVirtualView(),
+                AccessibilityNodeInfoCompat.ACTION_CLICK, null);
+    }
+
+    @Override
+    protected void onPopulateEventForVirtualView(int id, AccessibilityEvent event) {
+        if (id == INVALID_ID) {
+            throw new IllegalArgumentException("Invalid virtual view id");
+        }
+        event.setContentDescription(mContext.getString(R.string.action_move_here));
+    }
+
+    @Override
+    protected void onPopulateNodeForVirtualView(int id, AccessibilityNodeInfoCompat node) {
+        if (id == INVALID_ID) {
+            throw new IllegalArgumentException("Invalid virtual view id");
+        }
+
+        node.setContentDescription(getLocationDescriptionForIconDrop(id));
+        node.setBoundsInParent(getItemBounds(id));
+
+        node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+        node.setClickable(true);
+        node.setFocusable(true);
+    }
+
+    protected abstract String getLocationDescriptionForIconDrop(int id);
+
+    protected abstract String getConfirmationForIconDrop(int id);
+
+    private Rect getItemBounds(int id) {
+        int cellX = id % mView.getCountX();
+        int cellY = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+        mView.cellToRect(cellX, cellY, dragInfo.info.spanX, dragInfo.info.spanY, mTempRect);
+        return mTempRect;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
new file mode 100644
index 0000000..ff99890
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/FolderAccessibilityHelper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.FolderPagedView;
+import com.android.launcher3.R;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD in a folder.
+ */
+public class FolderAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+
+    /**
+     * 0-index position for the first cell in {@link #mView} in {@link #mParent}.
+     */
+    private final int mStartPosition;
+
+    private final FolderPagedView mParent;
+
+    public FolderAccessibilityHelper(CellLayout layout) {
+        super(layout);
+        mParent = (FolderPagedView) layout.getParent();
+
+        int index = mParent.indexOfChild(layout);
+        mStartPosition = index * layout.getCountX() * layout.getCountY();
+    }
+    @Override
+    protected int intersectsValidDropTarget(int id) {
+        return Math.min(id, mParent.getAllocatedContentSize() - mStartPosition - 1);
+    }
+
+    @Override
+    protected String getLocationDescriptionForIconDrop(int id) {
+        return mContext.getString(R.string.move_to_position, id + mStartPosition + 1);
+    }
+
+    @Override
+    protected String getConfirmationForIconDrop(int id) {
+        return mContext.getString(R.string.item_moved);
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
new file mode 100644
index 0000000..fe7b25e
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -0,0 +1,434 @@
+package com.android.launcher3.accessibility;
+
+import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.DialogInterface;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DragController.DragListener;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.Folder;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.InfoDropTarget;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetHostView;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.UninstallDropTarget;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.util.Thunk;
+
+import java.util.ArrayList;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class LauncherAccessibilityDelegate extends AccessibilityDelegate implements DragListener {
+
+    private static final String TAG = "LauncherAccessibilityDelegate";
+
+    private static final int REMOVE = R.id.action_remove;
+    private static final int INFO = R.id.action_info;
+    private static final int UNINSTALL = R.id.action_uninstall;
+    private static final int ADD_TO_WORKSPACE = R.id.action_add_to_workspace;
+    private static final int MOVE = R.id.action_move;
+    private static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
+    private static final int RESIZE = R.id.action_resize;
+
+    public enum DragType {
+        ICON,
+        FOLDER,
+        WIDGET
+    }
+
+    public static class DragInfo {
+        public DragType dragType;
+        public ItemInfo info;
+        public View item;
+    }
+
+    private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
+    @Thunk final Launcher mLauncher;
+
+    private DragInfo mDragInfo = null;
+    private AccessibilityDragSource mDragSource = null;
+
+    public LauncherAccessibilityDelegate(Launcher launcher) {
+        mLauncher = launcher;
+
+        mActions.put(REMOVE, new AccessibilityAction(REMOVE,
+                launcher.getText(R.string.delete_target_label)));
+        mActions.put(INFO, new AccessibilityAction(INFO,
+                launcher.getText(R.string.info_target_label)));
+        mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL,
+                launcher.getText(R.string.delete_target_uninstall_label)));
+        mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE,
+                launcher.getText(R.string.action_add_to_workspace)));
+        mActions.put(MOVE, new AccessibilityAction(MOVE,
+                launcher.getText(R.string.action_move)));
+        mActions.put(MOVE_TO_WORKSPACE, new AccessibilityAction(MOVE_TO_WORKSPACE,
+                launcher.getText(R.string.action_move_to_workspace)));
+        mActions.put(RESIZE, new AccessibilityAction(RESIZE,
+                        launcher.getText(R.string.action_resize)));
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+        if (!(host.getTag() instanceof ItemInfo)) return;
+        ItemInfo item = (ItemInfo) host.getTag();
+
+        if (DeleteDropTarget.supportsDrop(item)) {
+            info.addAction(mActions.get(REMOVE));
+        }
+        if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
+            info.addAction(mActions.get(UNINSTALL));
+        }
+        if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
+            info.addAction(mActions.get(INFO));
+        }
+
+        if ((item instanceof ShortcutInfo)
+                || (item instanceof LauncherAppWidgetInfo)
+                || (item instanceof FolderInfo)) {
+            info.addAction(mActions.get(MOVE));
+
+            if (item.container >= 0) {
+                info.addAction(mActions.get(MOVE_TO_WORKSPACE));
+            } else if (item instanceof LauncherAppWidgetInfo) {
+                if (!getSupportedResizeActions(host, (LauncherAppWidgetInfo) item).isEmpty()) {
+                    info.addAction(mActions.get(RESIZE));
+                }
+            }
+        } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
+            info.addAction(mActions.get(ADD_TO_WORKSPACE));
+        }
+    }
+
+    @Override
+    public boolean performAccessibilityAction(View host, int action, Bundle args) {
+        if ((host.getTag() instanceof ItemInfo)
+                && performAction(host, (ItemInfo) host.getTag(), action)) {
+            return true;
+        }
+        return super.performAccessibilityAction(host, action, args);
+    }
+
+    public boolean performAction(final View host, final ItemInfo item, int action) {
+        if (action == REMOVE) {
+            if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
+                announceConfirmation(R.string.item_removed);
+                return true;
+            }
+            return false;
+        } else if (action == INFO) {
+            InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
+            return true;
+        } else if (action == UNINSTALL) {
+            return UninstallDropTarget.startUninstallActivity(mLauncher, item);
+        } else if (action == MOVE) {
+            beginAccessibleDrag(host, item);
+        } else if (action == ADD_TO_WORKSPACE) {
+            final int[] coordinates = new int[2];
+            final long screenId = findSpaceOnWorkspace(item, coordinates);
+            mLauncher.showWorkspace(true, new Runnable() {
+
+                @Override
+                public void run() {
+                    if (item instanceof AppInfo) {
+                        ShortcutInfo info = ((AppInfo) item).makeShortcut();
+                        LauncherModel.addItemToDatabase(mLauncher, info,
+                                LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                screenId, coordinates[0], coordinates[1]);
+
+                        ArrayList<ItemInfo> itemList = new ArrayList<>();
+                        itemList.add(info);
+                        mLauncher.bindItems(itemList, 0, itemList.size(), true);
+                    } else if (item instanceof PendingAddItemInfo) {
+                        PendingAddItemInfo info = (PendingAddItemInfo) item;
+                        Workspace workspace = mLauncher.getWorkspace();
+                        workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+                        mLauncher.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                screenId, coordinates, info.spanX, info.spanY);
+                    }
+                    announceConfirmation(R.string.item_added_to_workspace);
+                }
+            });
+            return true;
+        } else if (action == MOVE_TO_WORKSPACE) {
+            Folder folder = mLauncher.getWorkspace().getOpenFolder();
+            mLauncher.closeFolder(folder);
+            ShortcutInfo info = (ShortcutInfo) item;
+            folder.getInfo().remove(info);
+
+            final int[] coordinates = new int[2];
+            final long screenId = findSpaceOnWorkspace(item, coordinates);
+            LauncherModel.moveItemInDatabase(mLauncher, info,
+                    LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                    screenId, coordinates[0], coordinates[1]);
+
+            // Bind the item in next frame so that if a new workspace page was created,
+            // it will get laid out.
+            new Handler().post(new Runnable() {
+
+                @Override
+                public void run() {
+                    ArrayList<ItemInfo> itemList = new ArrayList<>();
+                    itemList.add(item);
+                    mLauncher.bindItems(itemList, 0, itemList.size(), true);
+                    announceConfirmation(R.string.item_moved);
+                }
+            });
+        } else if (action == RESIZE) {
+            final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
+            final ArrayList<Integer> actions = getSupportedResizeActions(host, info);
+            CharSequence[] labels = new CharSequence[actions.size()];
+            for (int i = 0; i < actions.size(); i++) {
+                labels[i] = mLauncher.getText(actions.get(i));
+            }
+
+            new AlertDialog.Builder(mLauncher)
+                .setTitle(R.string.action_resize)
+                .setItems(labels, new DialogInterface.OnClickListener() {
+
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        performResizeAction(actions.get(which), host, info);
+                        dialog.dismiss();
+                    }
+                })
+                .show();
+        }
+        return false;
+    }
+
+    private ArrayList<Integer> getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
+        ArrayList<Integer> actions = new ArrayList<>();
+
+        AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo();
+        if (providerInfo == null) {
+            return actions;
+        }
+
+        CellLayout layout = (CellLayout) host.getParent().getParent();
+        if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
+            if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
+                    layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
+                actions.add(R.string.action_increase_width);
+            }
+
+            if (info.spanX > info.minSpanX && info.spanX > 1) {
+                actions.add(R.string.action_decrease_width);
+            }
+        }
+
+        if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
+            if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) ||
+                    layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) {
+                actions.add(R.string.action_increase_height);
+            }
+
+            if (info.spanY > info.minSpanY && info.spanY > 1) {
+                actions.add(R.string.action_decrease_height);
+            }
+        }
+        return actions;
+    }
+
+    @Thunk void performResizeAction(int action, View host, LauncherAppWidgetInfo info) {
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams();
+        CellLayout layout = (CellLayout) host.getParent().getParent();
+        layout.markCellsAsUnoccupiedForView(host);
+
+        if (action == R.string.action_increase_width) {
+            if (((host.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL)
+                    && layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY))
+                    || !layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY)) {
+                lp.cellX --;
+                info.cellX --;
+            }
+            lp.cellHSpan ++;
+            info.spanX ++;
+        } else if (action == R.string.action_decrease_width) {
+            lp.cellHSpan --;
+            info.spanX --;
+        } else if (action == R.string.action_increase_height) {
+            if (!layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1)) {
+                lp.cellY --;
+                info.cellY --;
+            }
+            lp.cellVSpan ++;
+            info.spanY ++;
+        } else if (action == R.string.action_decrease_height) {
+            lp.cellVSpan --;
+            info.spanY --;
+        }
+
+        layout.markCellsAsOccupiedForView(host);
+        Rect sizeRange = new Rect();
+        AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, sizeRange);
+        ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null,
+                sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom);
+        host.requestLayout();
+        LauncherModel.updateItemInDatabase(mLauncher, info);
+        announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY));
+    }
+
+    @Thunk void announceConfirmation(int resId) {
+        announceConfirmation(mLauncher.getResources().getString(resId));
+    }
+
+    @Thunk void announceConfirmation(String confirmation) {
+        mLauncher.getDragLayer().announceForAccessibility(confirmation);
+
+    }
+
+    public boolean isInAccessibleDrag() {
+        return mDragInfo != null;
+    }
+
+    public DragInfo getDragInfo() {
+        return mDragInfo;
+    }
+
+    /**
+     * @param clickedTarget the actual view that was clicked
+     * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
+     * as the actual drop location otherwise the views center is used.
+     */
+    public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
+            String confirmation) {
+        if (!isInAccessibleDrag()) return;
+
+        int[] loc = new int[2];
+        if (dropLocation == null) {
+            loc[0] = clickedTarget.getWidth() / 2;
+            loc[1] = clickedTarget.getHeight() / 2;
+        } else {
+            loc[0] = dropLocation.centerX();
+            loc[1] = dropLocation.centerY();
+        }
+
+        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
+        mLauncher.getDragController().completeAccessibleDrag(loc);
+
+        if (!TextUtils.isEmpty(confirmation)) {
+            announceConfirmation(confirmation);
+        }
+    }
+
+    public void beginAccessibleDrag(View item, ItemInfo info) {
+        mDragInfo = new DragInfo();
+        mDragInfo.info = info;
+        mDragInfo.item = item;
+        mDragInfo.dragType = DragType.ICON;
+        if (info instanceof FolderInfo) {
+            mDragInfo.dragType = DragType.FOLDER;
+        } else if (info instanceof LauncherAppWidgetInfo) {
+            mDragInfo.dragType = DragType.WIDGET;
+        }
+
+        CellLayout.CellInfo cellInfo = new CellLayout.CellInfo(item, info);
+
+        Rect pos = new Rect();
+        mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
+        mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY());
+
+        Workspace workspace = mLauncher.getWorkspace();
+
+        Folder folder = workspace.getOpenFolder();
+        if (folder != null) {
+            if (folder.getItemsInReadingOrder().contains(item)) {
+                mDragSource = folder;
+            } else {
+                mLauncher.closeFolder();
+            }
+        }
+        if (mDragSource == null) {
+            mDragSource = workspace;
+        }
+        mDragSource.enableAccessibleDrag(true);
+        mDragSource.startDrag(cellInfo, true);
+
+        if (mLauncher.getDragController().isDragging()) {
+            mLauncher.getDragController().addDragListener(this);
+        }
+    }
+
+
+    @Override
+    public void onDragStart(DragSource source, Object info, int dragAction) {
+        // No-op
+    }
+
+    @Override
+    public void onDragEnd() {
+        mLauncher.getDragController().removeDragListener(this);
+        mDragInfo = null;
+        if (mDragSource != null) {
+            mDragSource.enableAccessibleDrag(false);
+            mDragSource = null;
+        }
+    }
+
+    public static interface AccessibilityDragSource {
+        void startDrag(CellLayout.CellInfo cellInfo, boolean accessible);
+
+        void enableAccessibleDrag(boolean enable);
+    }
+
+    /**
+     * Find empty space on the workspace and returns the screenId.
+     */
+    private long findSpaceOnWorkspace(ItemInfo info, int[] outCoordinates) {
+        Workspace workspace = mLauncher.getWorkspace();
+        ArrayList<Long> workspaceScreens = workspace.getScreenOrder();
+        long screenId;
+
+        // First check if there is space on the current screen.
+        int screenIndex = workspace.getCurrentPage();
+        screenId = workspaceScreens.get(screenIndex);
+        CellLayout layout = (CellLayout) workspace.getPageAt(screenIndex);
+
+        boolean found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+        screenIndex = workspace.hasCustomContent() ? 1 : 0;
+        while (!found && screenIndex < workspaceScreens.size()) {
+            screenId = workspaceScreens.get(screenIndex);
+            layout = (CellLayout) workspace.getPageAt(screenIndex);
+            found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+            screenIndex++;
+        }
+
+        if (found) {
+            return screenId;
+        }
+
+        workspace.addExtraEmptyScreen();
+        screenId = workspace.commitExtraEmptyScreen();
+        layout = workspace.getScreenWithId(screenId);
+        found = layout.findCellForSpan(outCoordinates, info.spanX, info.spanY);
+
+        if (!found) {
+            Log.wtf(TAG, "Not enough space on an empty screen");
+        }
+        return screenId;
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
new file mode 100644
index 0000000..c5b52de
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate {
+
+    private static final int MOVE_BACKWARD = R.id.action_move_screen_backwards;
+    private static final int MOVE_FORWARD = R.id.action_move_screen_forwards;
+
+    private final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
+    private final Workspace mWorkspace;
+
+    public OverviewScreenAccessibilityDelegate(Workspace workspace) {
+        mWorkspace = workspace;
+
+        Context context = mWorkspace.getContext();
+        boolean isRtl = Utilities.isRtl(context.getResources());
+        mActions.put(MOVE_BACKWARD, new AccessibilityAction(MOVE_BACKWARD,
+                context.getText(isRtl ? R.string.action_move_screen_right :
+                    R.string.action_move_screen_left)));
+        mActions.put(MOVE_FORWARD, new AccessibilityAction(MOVE_FORWARD,
+                context.getText(isRtl ? R.string.action_move_screen_left :
+                    R.string.action_move_screen_right)));
+    }
+
+    @Override
+    public boolean performAccessibilityAction(View host, int action, Bundle args) {
+        if (host != null) {
+            if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS ) {
+                int index = mWorkspace.indexOfChild(host);
+                mWorkspace.setCurrentPage(index);
+            } else if (action == MOVE_FORWARD) {
+                movePage(mWorkspace.indexOfChild(host) + 1, host);
+                return true;
+            } else if (action == MOVE_BACKWARD) {
+                movePage(mWorkspace.indexOfChild(host) - 1, host);
+                return true;
+            }
+        }
+
+        return super.performAccessibilityAction(host, action, args);
+    }
+
+    private void movePage(int finalIndex, View view) {
+        mWorkspace.onStartReordering();
+        mWorkspace.removeView(view);
+        mWorkspace.addView(view, finalIndex);
+        mWorkspace.onEndReordering();
+        mWorkspace.announceForAccessibility(mWorkspace.getContext().getText(R.string.screen_moved));
+
+        mWorkspace.updateAccessibilityFlags();
+        view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+
+        int index = mWorkspace.indexOfChild(host);
+        if (index < mWorkspace.getChildCount() - 1) {
+            info.addAction(mActions.get(MOVE_FORWARD));
+        }
+        if (index > mWorkspace.numCustomPages()) {
+            info.addAction(mActions.get(MOVE_BACKWARD));
+        }
+    }
+}
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
new file mode 100644
index 0000000..80ddc13
--- /dev/null
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.accessibility;
+
+import android.text.TextUtils;
+import android.view.View;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DragType;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+
+/**
+ * Implementation of {@link DragAndDropAccessibilityDelegate} to support DnD on workspace.
+ */
+public class WorkspaceAccessibilityHelper extends DragAndDropAccessibilityDelegate {
+
+    public WorkspaceAccessibilityHelper(CellLayout layout) {
+        super(layout);
+    }
+
+    /**
+     * Find the virtual view id corresponding to the top left corner of any drop region by which
+     * the passed id is contained. For an icon, this is simply
+     */
+    @Override
+    protected int intersectsValidDropTarget(int id) {
+        int mCountX = mView.getCountX();
+        int mCountY = mView.getCountY();
+
+        int x = id % mCountX;
+        int y = id / mCountX;
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        if (dragInfo.dragType == DragType.WIDGET && mView.isHotseat()) {
+            return INVALID_POSITION;
+        }
+
+        if (dragInfo.dragType == DragType.WIDGET) {
+            // For a widget, every cell must be vacant. In addition, we will return any valid
+            // drop target by which the passed id is contained.
+            boolean fits = false;
+
+            // These represent the amount that we can back off if we hit a problem. They
+            // get consumed as we move up and to the right, trying new regions.
+            int spanX = dragInfo.info.spanX;
+            int spanY = dragInfo.info.spanY;
+
+            for (int m = 0; m < spanX; m++) {
+                for (int n = 0; n < spanY; n++) {
+
+                    fits = true;
+                    int x0 = x - m;
+                    int y0 = y - n;
+
+                    if (x0 < 0 || y0 < 0) continue;
+
+                    for (int i = x0; i < x0 + spanX; i++) {
+                        if (!fits) break;
+                        for (int j = y0; j < y0 + spanY; j++) {
+                            if (i >= mCountX || j >= mCountY || mView.isOccupied(i, j)) {
+                                fits = false;
+                                break;
+                            }
+                        }
+                    }
+                    if (fits) {
+                        return x0 + mCountX * y0;
+                    }
+                }
+            }
+            return INVALID_POSITION;
+        } else {
+            // For an icon, we simply check the view directly below
+            View child = mView.getChildAt(x, y);
+            if (child == null || child == dragInfo.item) {
+                // Empty cell. Good for an icon or folder.
+                return id;
+            } else if (dragInfo.dragType != DragType.FOLDER) {
+                // For icons, we can consider cells that have another icon or a folder.
+                ItemInfo info = (ItemInfo) child.getTag();
+                if (info instanceof AppInfo || info instanceof FolderInfo ||
+                        info instanceof ShortcutInfo) {
+                    return id;
+                }
+            }
+            return INVALID_POSITION;
+        }
+    }
+
+    @Override
+    protected String getConfirmationForIconDrop(int id) {
+        int x = id % mView.getCountX();
+        int y = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        View child = mView.getChildAt(x, y);
+        if (child == null || child == dragInfo.item) {
+            return mContext.getString(R.string.item_moved);
+        } else {
+            ItemInfo info = (ItemInfo) child.getTag();
+            if (info instanceof AppInfo || info instanceof ShortcutInfo) {
+                return mContext.getString(R.string.folder_created);
+
+            } else if (info instanceof FolderInfo) {
+                return mContext.getString(R.string.added_to_folder);
+            }
+        }
+        return "";
+    }
+
+    @Override
+    protected String getLocationDescriptionForIconDrop(int id) {
+        int x = id % mView.getCountX();
+        int y = id / mView.getCountX();
+        LauncherAccessibilityDelegate.DragInfo dragInfo = mDelegate.getDragInfo();
+
+        View child = mView.getChildAt(x, y);
+        if (child == null || child == dragInfo.item) {
+            if (mView.isHotseat()) {
+                return mContext.getString(R.string.move_to_hotseat_position, id + 1);
+            } else {
+                return mContext.getString(R.string.move_to_empty_cell, y + 1, x + 1);
+            }
+        } else {
+            ItemInfo info = (ItemInfo) child.getTag();
+            if (info instanceof ShortcutInfo) {
+                return mContext.getString(R.string.create_folder_with, info.title);
+            } else if (info instanceof FolderInfo) {
+                if (TextUtils.isEmpty(info.title)) {
+                    // Find the first item in the folder.
+                    FolderInfo folder = (FolderInfo) info;
+                    ShortcutInfo firstItem = null;
+                    for (ShortcutInfo shortcut : folder.contents) {
+                        if (firstItem == null || firstItem.rank > shortcut.rank) {
+                            firstItem = shortcut;
+                        }
+                    }
+
+                    if (firstItem != null) {
+                        return mContext.getString(R.string.add_to_folder_with_app, firstItem.title);
+                    }
+                }
+                return mContext.getString(R.string.add_to_folder, info.title);
+            }
+        }
+        return "";
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
new file mode 100644
index 0000000..67d5728
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.InsetDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.method.TextKeyListener;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BaseContainerView;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.Folder;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherTransitionable;
+import com.android.launcher3.R;
+import com.android.launcher3.Stats;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Thunk;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+
+
+/**
+ * A merge algorithm that merges every section indiscriminately.
+ */
+final class FullMergeAlgorithm implements AlphabeticalAppsList.MergeAlgorithm {
+
+    @Override
+    public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
+           AlphabeticalAppsList.SectionInfo withSection,
+           int sectionAppCount, int numAppsPerRow, int mergeCount) {
+        // Don't merge the predicted apps
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+            return false;
+        }
+        // Otherwise, merge every other section
+        return true;
+    }
+}
+
+/**
+ * The logic we use to merge multiple sections.  We only merge sections when their final row
+ * contains less than a certain number of icons, and stop at a specified max number of merges.
+ * In addition, we will try and not merge sections that identify apps from different scripts.
+ */
+final class SimpleSectionMergeAlgorithm implements AlphabeticalAppsList.MergeAlgorithm {
+
+    private int mMinAppsPerRow;
+    private int mMinRowsInMergedSection;
+    private int mMaxAllowableMerges;
+    private CharsetEncoder mAsciiEncoder;
+
+    public SimpleSectionMergeAlgorithm(int minAppsPerRow, int minRowsInMergedSection, int maxNumMerges) {
+        mMinAppsPerRow = minAppsPerRow;
+        mMinRowsInMergedSection = minRowsInMergedSection;
+        mMaxAllowableMerges = maxNumMerges;
+        mAsciiEncoder = Charset.forName("US-ASCII").newEncoder();
+    }
+
+    @Override
+    public boolean continueMerging(AlphabeticalAppsList.SectionInfo section,
+           AlphabeticalAppsList.SectionInfo withSection,
+           int sectionAppCount, int numAppsPerRow, int mergeCount) {
+        // Don't merge the predicted apps
+        if (section.firstAppItem.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+            return false;
+        }
+
+        // Continue merging if the number of hanging apps on the final row is less than some
+        // fixed number (ragged), the merged rows has yet to exceed some minimum row count,
+        // and while the number of merged sections is less than some fixed number of merges
+        int rows = sectionAppCount / numAppsPerRow;
+        int cols = sectionAppCount % numAppsPerRow;
+
+        // Ensure that we do not merge across scripts, currently we only allow for english and
+        // native scripts so we can test if both can just be ascii encoded
+        boolean isCrossScript = false;
+        if (section.firstAppItem != null && withSection.firstAppItem != null) {
+            isCrossScript = mAsciiEncoder.canEncode(section.firstAppItem.sectionName) !=
+                    mAsciiEncoder.canEncode(withSection.firstAppItem.sectionName);
+        }
+        return (0 < cols && cols < mMinAppsPerRow) &&
+                rows < mMinRowsInMergedSection &&
+                mergeCount < mMaxAllowableMerges &&
+                !isCrossScript;
+    }
+}
+
+/**
+ * The all apps view container.
+ */
+public class AllAppsContainerView extends BaseContainerView implements DragSource,
+        LauncherTransitionable, View.OnTouchListener, View.OnLongClickListener,
+        AllAppsSearchBarController.Callbacks {
+
+    private static final int MIN_ROWS_IN_MERGED_SECTION_PHONE = 3;
+    private static final int MAX_NUM_MERGES_PHONE = 2;
+
+    @Thunk Launcher mLauncher;
+    @Thunk AlphabeticalAppsList mApps;
+    private AllAppsGridAdapter mAdapter;
+    private RecyclerView.LayoutManager mLayoutManager;
+    private RecyclerView.ItemDecoration mItemDecoration;
+
+    @Thunk View mContent;
+    @Thunk View mContainerView;
+    @Thunk View mRevealView;
+    @Thunk AllAppsRecyclerView mAppsRecyclerView;
+    @Thunk AllAppsSearchBarController mSearchBarController;
+    private ViewGroup mSearchBarContainerView;
+    private View mSearchBarView;
+
+    private int mSectionNamesMargin;
+    private int mNumAppsPerRow;
+    private int mNumPredictedAppsPerRow;
+    private int mRecyclerViewTopBottomPadding;
+    // This coordinate is relative to this container view
+    private final Point mBoundsCheckLastTouchDownPos = new Point(-1, -1);
+    // This coordinate is relative to its parent
+    private final Point mIconLastTouchPos = new Point();
+
+    private SpannableStringBuilder mSearchQueryBuilder = null;
+
+    public AllAppsContainerView(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        Resources res = context.getResources();
+
+        mLauncher = (Launcher) context;
+        mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
+        mApps = new AlphabeticalAppsList(context);
+        mAdapter = new AllAppsGridAdapter(context, mApps, this, mLauncher, this);
+        mAdapter.setEmptySearchText(res.getString(R.string.all_apps_loading_message));
+        mApps.setAdapter(mAdapter);
+        mLayoutManager = mAdapter.getLayoutManager();
+        mItemDecoration = mAdapter.getItemDecoration();
+        mRecyclerViewTopBottomPadding =
+                res.getDimensionPixelSize(R.dimen.all_apps_list_top_bottom_padding);
+
+        mSearchQueryBuilder = new SpannableStringBuilder();
+        Selection.setSelection(mSearchQueryBuilder, 0);
+    }
+
+    /**
+     * Sets the current set of predicted apps.
+     */
+    public void setPredictedApps(List<ComponentKey> apps) {
+        mApps.setPredictedApps(apps);
+    }
+
+    /**
+     * Sets the current set of apps.
+     */
+    public void setApps(List<AppInfo> apps) {
+        mApps.setApps(apps);
+    }
+
+    /**
+     * Adds new apps to the list.
+     */
+    public void addApps(List<AppInfo> apps) {
+        mApps.addApps(apps);
+    }
+
+    /**
+     * Updates existing apps in the list
+     */
+    public void updateApps(List<AppInfo> apps) {
+        mApps.updateApps(apps);
+    }
+
+    /**
+     * Removes some apps from the list.
+     */
+    public void removeApps(List<AppInfo> apps) {
+        mApps.removeApps(apps);
+    }
+
+    /**
+     * Sets the search bar that shows above the a-z list.
+     */
+    public void setSearchBarController(AllAppsSearchBarController searchController) {
+        if (mSearchBarController != null) {
+            throw new RuntimeException("Expected search bar controller to only be set once");
+        }
+        mSearchBarController = searchController;
+        mSearchBarController.initialize(mApps, this);
+
+        // Add the new search view to the layout
+        View searchBarView = searchController.getView(mSearchBarContainerView);
+        mSearchBarContainerView.addView(searchBarView);
+        mSearchBarContainerView.setVisibility(View.VISIBLE);
+        mSearchBarView = searchBarView;
+        setHasSearchBar();
+
+        updateBackgroundAndPaddings();
+    }
+
+    /**
+     * Scrolls this list view to the top.
+     */
+    public void scrollToTop() {
+        mAppsRecyclerView.scrollToTop();
+    }
+
+    /**
+     * Returns the content view used for the launcher transitions.
+     */
+    public View getContentView() {
+        return mContainerView;
+    }
+
+    /**
+     * Returns the all apps search view.
+     */
+    public View getSearchBarView() {
+        return mSearchBarView;
+    }
+
+    /**
+     * Returns the reveal view used for the launcher transitions.
+     */
+    public View getRevealView() {
+        return mRevealView;
+    }
+
+    /**
+     * Returns an new instance of the default app search controller.
+     */
+    public AllAppsSearchBarController newDefaultAppSearchController() {
+        return new DefaultAppSearchController(getContext(), this, mAppsRecyclerView);
+    }
+
+    /**
+     * Focuses the search field and begins an app search.
+     */
+    public void startAppsSearch() {
+        if (mSearchBarController != null) {
+            mSearchBarController.focusSearchField();
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        boolean isRtl = Utilities.isRtl(getResources());
+        mAdapter.setRtl(isRtl);
+        mContent = findViewById(R.id.content);
+
+        // This is a focus listener that proxies focus from a view into the list view.  This is to
+        // work around the search box from getting first focus and showing the cursor.
+        View.OnFocusChangeListener focusProxyListener = new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (hasFocus) {
+                    mAppsRecyclerView.requestFocus();
+                }
+            }
+        };
+        mSearchBarContainerView = (ViewGroup) findViewById(R.id.search_box_container);
+        mSearchBarContainerView.setOnFocusChangeListener(focusProxyListener);
+        mContainerView = findViewById(R.id.all_apps_container);
+        mContainerView.setOnFocusChangeListener(focusProxyListener);
+        mRevealView = findViewById(R.id.all_apps_reveal);
+
+        // Load the all apps recycler view
+        mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view);
+        mAppsRecyclerView.setApps(mApps);
+        mAppsRecyclerView.setLayoutManager(mLayoutManager);
+        mAppsRecyclerView.setAdapter(mAdapter);
+        mAppsRecyclerView.setHasFixedSize(true);
+        if (mItemDecoration != null) {
+            mAppsRecyclerView.addItemDecoration(mItemDecoration);
+        }
+
+        updateBackgroundAndPaddings();
+    }
+
+    @Override
+    public void onBoundsChanged(Rect newBounds) {
+        mLauncher.updateOverlayBounds(newBounds);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Update the number of items in the grid before we measure the view
+        int availableWidth = !mContentBounds.isEmpty() ? mContentBounds.width() :
+                MeasureSpec.getSize(widthMeasureSpec);
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        grid.updateAppsViewNumCols(getResources(), availableWidth);
+        if (mNumAppsPerRow != grid.allAppsNumCols ||
+                mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
+            mNumAppsPerRow = grid.allAppsNumCols;
+            mNumPredictedAppsPerRow = grid.allAppsNumPredictiveCols;
+
+            // If there is a start margin to draw section names, determine how we are going to merge
+            // app sections
+            boolean mergeSectionsFully = mSectionNamesMargin == 0 || !grid.isPhone;
+            AlphabeticalAppsList.MergeAlgorithm mergeAlgorithm = mergeSectionsFully ?
+                    new FullMergeAlgorithm() :
+                    new SimpleSectionMergeAlgorithm((int) Math.ceil(mNumAppsPerRow / 2f),
+                            MIN_ROWS_IN_MERGED_SECTION_PHONE, MAX_NUM_MERGES_PHONE);
+
+            mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
+            mAdapter.setNumAppsPerRow(mNumAppsPerRow);
+            mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow, mergeAlgorithm);
+        }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    /**
+     * Update the background and padding of the Apps view and children.  Instead of insetting the
+     * container view, we inset the background and padding of the recycler view to allow for the
+     * recycler view to handle touch events (for fast scrolling) all the way to the edge.
+     */
+    @Override
+    protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
+        boolean isRtl = Utilities.isRtl(getResources());
+
+        // TODO: Use quantum_panel instead of quantum_panel_shape
+        InsetDrawable background = new InsetDrawable(
+                getResources().getDrawable(R.drawable.quantum_panel_shape), padding.left, 0,
+                padding.right, 0);
+        Rect bgPadding = new Rect();
+        background.getPadding(bgPadding);
+        mContainerView.setBackground(background);
+        mRevealView.setBackground(background.getConstantState().newDrawable());
+        mAppsRecyclerView.updateBackgroundPadding(bgPadding);
+        mAdapter.updateBackgroundPadding(bgPadding);
+
+        // Hack: We are going to let the recycler view take the full width, so reset the padding on
+        // the container to zero after setting the background and apply the top-bottom padding to
+        // the content view instead so that the launcher transition clips correctly.
+        mContent.setPadding(0, padding.top, 0, padding.bottom);
+        mContainerView.setPadding(0, 0, 0, 0);
+
+        // Pad the recycler view by the background padding plus the start margin (for the section
+        // names)
+        int startInset = Math.max(mSectionNamesMargin, mAppsRecyclerView.getMaxScrollbarWidth());
+        int topBottomPadding = mRecyclerViewTopBottomPadding;
+        if (isRtl) {
+            mAppsRecyclerView.setPadding(padding.left + mAppsRecyclerView.getMaxScrollbarWidth(),
+                    topBottomPadding, padding.right + startInset, topBottomPadding);
+        } else {
+            mAppsRecyclerView.setPadding(padding.left + startInset, topBottomPadding,
+                    padding.right + mAppsRecyclerView.getMaxScrollbarWidth(), topBottomPadding);
+        }
+
+        // Inset the search bar to fit its bounds above the container
+        if (mSearchBarView != null) {
+            Rect backgroundPadding = new Rect();
+            if (mSearchBarView.getBackground() != null) {
+                mSearchBarView.getBackground().getPadding(backgroundPadding);
+            }
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+                    mSearchBarContainerView.getLayoutParams();
+            lp.leftMargin = searchBarBounds.left - backgroundPadding.left;
+            lp.topMargin = searchBarBounds.top - backgroundPadding.top;
+            lp.rightMargin = (getMeasuredWidth() - searchBarBounds.right) - backgroundPadding.right;
+            mSearchBarContainerView.requestLayout();
+        }
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // Determine if the key event was actual text, if so, focus the search bar and then dispatch
+        // the key normally so that it can process this key event
+        if (!mSearchBarController.isSearchFieldFocused() &&
+                event.getAction() == KeyEvent.ACTION_DOWN) {
+            final int unicodeChar = event.getUnicodeChar();
+            final boolean isKeyNotWhitespace = unicodeChar > 0 &&
+                    !Character.isWhitespace(unicodeChar) && !Character.isSpaceChar(unicodeChar);
+            if (isKeyNotWhitespace) {
+                boolean gotKey = TextKeyListener.getInstance().onKeyDown(this, mSearchQueryBuilder,
+                        event.getKeyCode(), event);
+                if (gotKey && mSearchQueryBuilder.length() > 0) {
+                    mSearchBarController.focusSearchField();
+                }
+            }
+        }
+
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return handleTouchEvent(ev);
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return handleTouchEvent(ev);
+    }
+
+    @SuppressLint("ClickableViewAccessibility")
+    @Override
+    public boolean onTouch(View v, MotionEvent ev) {
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE:
+                mIconLastTouchPos.set((int) ev.getX(), (int) ev.getY());
+                break;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        // Return early if this is not initiated from a touch
+        if (!v.isInTouchMode()) return false;
+        // When we have exited all apps or are in transition, disregard long clicks
+        if (!mLauncher.isAppsViewVisible() ||
+                mLauncher.getWorkspace().isSwitchingState()) return false;
+        // Return if global dragging is not enabled
+        if (!mLauncher.isDraggingEnabled()) return false;
+
+        // Start the drag
+        mLauncher.getWorkspace().beginDragShared(v, mIconLastTouchPos, this, false);
+        // Enter spring loaded mode
+        mLauncher.enterSpringLoadedDragMode();
+
+        return false;
+    }
+
+    @Override
+    public boolean supportsFlingToDelete() {
+        return true;
+    }
+
+    @Override
+    public boolean supportsAppInfoDropTarget() {
+        return true;
+    }
+
+    @Override
+    public boolean supportsDeleteDropTarget() {
+        return false;
+    }
+
+    @Override
+    public float getIntrinsicIconScaleFactor() {
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        return (float) grid.allAppsIconSizePx / grid.iconSizePx;
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // We just dismiss the drag when we fling, so cleanup here
+        mLauncher.exitSpringLoadedDragModeDelayed(true,
+                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        mLauncher.unlockScreenOrientation(false);
+    }
+
+    @Override
+    public void onDropCompleted(View target, DropTarget.DragObject d, boolean isFlingToDelete,
+            boolean success) {
+        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragModeDelayed(true,
+                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        }
+        mLauncher.unlockScreenOrientation(false);
+
+        // Display an error message if the drag failed due to there not being enough space on the
+        // target layout we were dropping on.
+        if (!success) {
+            boolean showOutOfSpaceMessage = false;
+            if (target instanceof Workspace) {
+                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
+                Workspace workspace = (Workspace) target;
+                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
+                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
+                if (layout != null) {
+                    layout.calculateSpans(itemInfo);
+                    showOutOfSpaceMessage =
+                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+                }
+            }
+            if (showOutOfSpaceMessage) {
+                mLauncher.showOutOfSpaceMessage(false);
+            }
+
+            d.deferDragViewCleanupPostAnimation = false;
+        }
+    }
+
+    @Override
+    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
+        // Do nothing
+    }
+
+    @Override
+    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
+        // Do nothing
+    }
+
+    @Override
+    public void onLauncherTransitionStep(Launcher l, float t) {
+        // Do nothing
+    }
+
+    @Override
+    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
+        if (toWorkspace) {
+            // Reset the search bar after transitioning home
+            mSearchBarController.reset();
+        }
+    }
+
+    /**
+     * Handles the touch events to dismiss all apps when clicking outside the bounds of the
+     * recycler view.
+     */
+    private boolean handleTouchEvent(MotionEvent ev) {
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                if (!mContentBounds.isEmpty()) {
+                    // Outset the fixed bounds and check if the touch is outside all apps
+                    Rect tmpRect = new Rect(mContentBounds);
+                    tmpRect.inset(-grid.allAppsIconSizePx / 2, 0);
+                    if (ev.getX() < tmpRect.left || ev.getX() > tmpRect.right) {
+                        mBoundsCheckLastTouchDownPos.set(x, y);
+                        return true;
+                    }
+                } else {
+                    // Check if the touch is outside all apps
+                    if (ev.getX() < getPaddingLeft() ||
+                            ev.getX() > (getWidth() - getPaddingRight())) {
+                        mBoundsCheckLastTouchDownPos.set(x, y);
+                        return true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mBoundsCheckLastTouchDownPos.x > -1) {
+                    ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
+                    float dx = ev.getX() - mBoundsCheckLastTouchDownPos.x;
+                    float dy = ev.getY() - mBoundsCheckLastTouchDownPos.y;
+                    float distance = (float) Math.hypot(dx, dy);
+                    if (distance < viewConfig.getScaledTouchSlop()) {
+                        // The background was clicked, so just go home
+                        Launcher launcher = (Launcher) getContext();
+                        launcher.showWorkspace(true);
+                        return true;
+                    }
+                }
+                // Fall through
+            case MotionEvent.ACTION_CANCEL:
+                mBoundsCheckLastTouchDownPos.set(-1, -1);
+                break;
+        }
+        return false;
+    }
+
+    @Override
+    public void onSearchResult(String query, ArrayList<ComponentKey> apps) {
+        if (apps != null) {
+            if (apps.isEmpty()) {
+                String formatStr = getResources().getString(R.string.all_apps_no_search_results);
+                mAdapter.setEmptySearchText(String.format(formatStr, query));
+            } else {
+                mAppsRecyclerView.scrollToTop();
+            }
+            mApps.setOrderedFilter(apps);
+        }
+    }
+
+    @Override
+    public void clearSearchResult() {
+        mApps.setOrderedFilter(null);
+
+        // Clear the search query
+        mSearchQueryBuilder.clear();
+        mSearchQueryBuilder.clearSpans();
+        Selection.setSelection(mSearchQueryBuilder, 0);
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
new file mode 100644
index 0000000..057883c
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Thunk;
+
+import java.util.HashMap;
+import java.util.List;
+
+
+/**
+ * The grid view adapter of all the apps.
+ */
+class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
+
+    public static final String TAG = "AppsGridAdapter";
+    private static final boolean DEBUG = false;
+
+    // A section break in the grid
+    public static final int SECTION_BREAK_VIEW_TYPE = 0;
+    // A normal icon
+    public static final int ICON_VIEW_TYPE = 1;
+    // A prediction icon
+    public static final int PREDICTION_ICON_VIEW_TYPE = 2;
+    // The message shown when there are no filtered results
+    public static final int EMPTY_SEARCH_VIEW_TYPE = 3;
+
+    /**
+     * ViewHolder for each icon.
+     */
+    public static class ViewHolder extends RecyclerView.ViewHolder {
+        public View mContent;
+
+        public ViewHolder(View v) {
+            super(v);
+            mContent = v;
+        }
+    }
+
+    /**
+     * Helper class to size the grid items.
+     */
+    public class GridSpanSizer extends GridLayoutManager.SpanSizeLookup {
+
+        public GridSpanSizer() {
+            super();
+            setSpanIndexCacheEnabled(true);
+        }
+
+        @Override
+        public int getSpanSize(int position) {
+            if (mApps.hasNoFilteredResults()) {
+                // Empty view spans full width
+                return mAppsPerRow;
+            }
+
+            switch (mApps.getAdapterItems().get(position).viewType) {
+                case AllAppsGridAdapter.ICON_VIEW_TYPE:
+                case AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE:
+                    return 1;
+                default:
+                    // Section breaks span the full width
+                    return mAppsPerRow;
+            }
+        }
+    }
+
+    /**
+     * Helper class to draw the section headers
+     */
+    public class GridItemDecoration extends RecyclerView.ItemDecoration {
+
+        private static final boolean DEBUG_SECTION_MARGIN = false;
+        private static final boolean FADE_OUT_SECTIONS = false;
+
+        private HashMap<String, PointF> mCachedSectionBounds = new HashMap<>();
+        private Rect mTmpBounds = new Rect();
+
+        @Override
+        public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            if (mApps.hasFilter() || mAppsPerRow == 0) {
+                return;
+            }
+
+            if (DEBUG_SECTION_MARGIN) {
+                Paint p = new Paint();
+                p.setColor(0x33ff0000);
+                c.drawRect(mBackgroundPadding.left, 0, mBackgroundPadding.left + mSectionNamesMargin,
+                        parent.getMeasuredHeight(), p);
+            }
+
+            List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+            boolean hasDrawnPredictedAppsDivider = false;
+            boolean showSectionNames = mSectionNamesMargin > 0;
+            int childCount = parent.getChildCount();
+            int lastSectionTop = 0;
+            int lastSectionHeight = 0;
+            for (int i = 0; i < childCount; i++) {
+                View child = parent.getChildAt(i);
+                ViewHolder holder = (ViewHolder) parent.getChildViewHolder(child);
+                if (!isValidHolderAndChild(holder, child, items)) {
+                    continue;
+                }
+
+                if (shouldDrawItemDivider(holder, items) && !hasDrawnPredictedAppsDivider) {
+                    // Draw the divider under the predicted apps
+                    int top = child.getTop() + child.getHeight() + mPredictionBarDividerOffset;
+                    c.drawLine(mBackgroundPadding.left, top,
+                            parent.getWidth() - mBackgroundPadding.right, top,
+                            mPredictedAppsDividerPaint);
+                    hasDrawnPredictedAppsDivider = true;
+
+                } else if (showSectionNames && shouldDrawItemSection(holder, i, items)) {
+                    // At this point, we only draw sections for each section break;
+                    int viewTopOffset = (2 * child.getPaddingTop());
+                    int pos = holder.getPosition();
+                    AlphabeticalAppsList.AdapterItem item = items.get(pos);
+                    AlphabeticalAppsList.SectionInfo sectionInfo = item.sectionInfo;
+
+                    // Draw all the sections for this index
+                    String lastSectionName = item.sectionName;
+                    for (int j = item.sectionAppIndex; j < sectionInfo.numApps; j++, pos++) {
+                        AlphabeticalAppsList.AdapterItem nextItem = items.get(pos);
+                        String sectionName = nextItem.sectionName;
+                        if (nextItem.sectionInfo != sectionInfo) {
+                            break;
+                        }
+                        if (j > item.sectionAppIndex && sectionName.equals(lastSectionName)) {
+                            continue;
+                        }
+
+
+                        // Find the section name bounds
+                        PointF sectionBounds = getAndCacheSectionBounds(sectionName);
+
+                        // Calculate where to draw the section
+                        int sectionBaseline = (int) (viewTopOffset + sectionBounds.y);
+                        int x = mIsRtl ?
+                                parent.getWidth() - mBackgroundPadding.left - mSectionNamesMargin :
+                                        mBackgroundPadding.left;
+                        x += (int) ((mSectionNamesMargin - sectionBounds.x) / 2f);
+                        int y = child.getTop() + sectionBaseline;
+
+                        // Determine whether this is the last row with apps in that section, if
+                        // so, then fix the section to the row allowing it to scroll past the
+                        // baseline, otherwise, bound it to the baseline so it's in the viewport
+                        int appIndexInSection = items.get(pos).sectionAppIndex;
+                        int nextRowPos = Math.min(items.size() - 1,
+                                pos + mAppsPerRow - (appIndexInSection % mAppsPerRow));
+                        AlphabeticalAppsList.AdapterItem nextRowItem = items.get(nextRowPos);
+                        boolean fixedToRow = !sectionName.equals(nextRowItem.sectionName);
+                        if (!fixedToRow) {
+                            y = Math.max(sectionBaseline, y);
+                        }
+
+                        // In addition, if it overlaps with the last section that was drawn, then
+                        // offset it so that it does not overlap
+                        if (lastSectionHeight > 0 && y <= (lastSectionTop + lastSectionHeight)) {
+                            y += lastSectionTop - y + lastSectionHeight;
+                        }
+
+                        // Draw the section header
+                        if (FADE_OUT_SECTIONS) {
+                            int alpha = 255;
+                            if (fixedToRow) {
+                                alpha = Math.min(255,
+                                        (int) (255 * (Math.max(0, y) / (float) sectionBaseline)));
+                            }
+                            mSectionTextPaint.setAlpha(alpha);
+                        }
+                        c.drawText(sectionName, x, y, mSectionTextPaint);
+
+                        lastSectionTop = y;
+                        lastSectionHeight = (int) (sectionBounds.y + mSectionHeaderOffset);
+                        lastSectionName = sectionName;
+                    }
+                    i += (sectionInfo.numApps - item.sectionAppIndex);
+                }
+            }
+        }
+
+        @Override
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                RecyclerView.State state) {
+            // Do nothing
+        }
+
+        /**
+         * Given a section name, return the bounds of the given section name.
+         */
+        private PointF getAndCacheSectionBounds(String sectionName) {
+            PointF bounds = mCachedSectionBounds.get(sectionName);
+            if (bounds == null) {
+                mSectionTextPaint.getTextBounds(sectionName, 0, sectionName.length(), mTmpBounds);
+                bounds = new PointF(mSectionTextPaint.measureText(sectionName), mTmpBounds.height());
+                mCachedSectionBounds.put(sectionName, bounds);
+            }
+            return bounds;
+        }
+
+        /**
+         * Returns whether we consider this a valid view holder for us to draw a divider or section for.
+         */
+        private boolean isValidHolderAndChild(ViewHolder holder, View child,
+                List<AlphabeticalAppsList.AdapterItem> items) {
+            // Ensure item is not already removed
+            GridLayoutManager.LayoutParams lp = (GridLayoutManager.LayoutParams)
+                    child.getLayoutParams();
+            if (lp.isItemRemoved()) {
+                return false;
+            }
+            // Ensure we have a valid holder
+            if (holder == null) {
+                return false;
+            }
+            // Ensure we have a holder position
+            int pos = holder.getPosition();
+            if (pos < 0 || pos >= items.size()) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * Returns whether to draw the divider for a given child.
+         */
+        private boolean shouldDrawItemDivider(ViewHolder holder,
+                List<AlphabeticalAppsList.AdapterItem> items) {
+            int pos = holder.getPosition();
+            return items.get(pos).viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
+        }
+
+        /**
+         * Returns whether to draw the section for the given child.
+         */
+        private boolean shouldDrawItemSection(ViewHolder holder, int childIndex,
+                List<AlphabeticalAppsList.AdapterItem> items) {
+            int pos = holder.getPosition();
+            AlphabeticalAppsList.AdapterItem item = items.get(pos);
+
+            // Ensure it's an icon
+            if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE) {
+                return false;
+            }
+            // Draw the section header for the first item in each section
+            return (childIndex == 0) ||
+                    (items.get(pos - 1).viewType == AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE);
+        }
+    }
+
+    private LayoutInflater mLayoutInflater;
+    @Thunk AlphabeticalAppsList mApps;
+    private GridLayoutManager mGridLayoutMgr;
+    private GridSpanSizer mGridSizer;
+    private GridItemDecoration mItemDecoration;
+    private View.OnTouchListener mTouchListener;
+    private View.OnClickListener mIconClickListener;
+    private View.OnLongClickListener mIconLongClickListener;
+    @Thunk final Rect mBackgroundPadding = new Rect();
+    @Thunk int mPredictionBarDividerOffset;
+    @Thunk int mAppsPerRow;
+    @Thunk boolean mIsRtl;
+    private String mEmptySearchText;
+
+    // Section drawing
+    @Thunk int mSectionNamesMargin;
+    @Thunk int mSectionHeaderOffset;
+    @Thunk Paint mSectionTextPaint;
+    @Thunk Paint mPredictedAppsDividerPaint;
+
+    public AllAppsGridAdapter(Context context, AlphabeticalAppsList apps,
+            View.OnTouchListener touchListener, View.OnClickListener iconClickListener,
+            View.OnLongClickListener iconLongClickListener) {
+        Resources res = context.getResources();
+        mApps = apps;
+        mGridSizer = new GridSpanSizer();
+        mGridLayoutMgr = new GridLayoutManager(context, 1, GridLayoutManager.VERTICAL, false);
+        mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
+        mItemDecoration = new GridItemDecoration();
+        mLayoutInflater = LayoutInflater.from(context);
+        mTouchListener = touchListener;
+        mIconClickListener = iconClickListener;
+        mIconLongClickListener = iconLongClickListener;
+        mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin);
+        mSectionHeaderOffset = res.getDimensionPixelSize(R.dimen.all_apps_grid_section_y_offset);
+
+        mSectionTextPaint = new Paint();
+        mSectionTextPaint.setTextSize(res.getDimensionPixelSize(
+                R.dimen.all_apps_grid_section_text_size));
+        mSectionTextPaint.setColor(res.getColor(R.color.all_apps_grid_section_text_color));
+        mSectionTextPaint.setAntiAlias(true);
+
+        mPredictedAppsDividerPaint = new Paint();
+        mPredictedAppsDividerPaint.setStrokeWidth(Utilities.pxFromDp(1f, res.getDisplayMetrics()));
+        mPredictedAppsDividerPaint.setColor(0x1E000000);
+        mPredictedAppsDividerPaint.setAntiAlias(true);
+        mPredictionBarDividerOffset =
+                (-res.getDimensionPixelSize(R.dimen.all_apps_prediction_icon_bottom_padding) +
+                        res.getDimensionPixelSize(R.dimen.all_apps_icon_top_bottom_padding)) / 2;
+    }
+
+    /**
+     * Sets the number of apps per row.
+     */
+    public void setNumAppsPerRow(int appsPerRow) {
+        mAppsPerRow = appsPerRow;
+        mGridLayoutMgr.setSpanCount(appsPerRow);
+    }
+
+    /**
+     * Sets whether we are in RTL mode.
+     */
+    public void setRtl(boolean rtl) {
+        mIsRtl = rtl;
+    }
+
+    /**
+     * Sets the text to show when there are no apps.
+     */
+    public void setEmptySearchText(String query) {
+        mEmptySearchText = query;
+    }
+
+    /**
+     * Notifies the adapter of the background padding so that it can draw things correctly in the
+     * item decorator.
+     */
+    public void updateBackgroundPadding(Rect padding) {
+        mBackgroundPadding.set(padding);
+    }
+
+    /**
+     * Returns the grid layout manager.
+     */
+    public GridLayoutManager getLayoutManager() {
+        return mGridLayoutMgr;
+    }
+
+    /**
+     * Returns the item decoration for the recycler view.
+     */
+    public RecyclerView.ItemDecoration getItemDecoration() {
+        // We don't draw any headers when we are uncomfortably dense
+        return mItemDecoration;
+    }
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        switch (viewType) {
+            case EMPTY_SEARCH_VIEW_TYPE:
+                return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search, parent,
+                        false));
+            case SECTION_BREAK_VIEW_TYPE:
+                return new ViewHolder(new View(parent.getContext()));
+            case ICON_VIEW_TYPE: {
+                BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
+                        R.layout.all_apps_icon, parent, false);
+                icon.setOnTouchListener(mTouchListener);
+                icon.setOnClickListener(mIconClickListener);
+                icon.setOnLongClickListener(mIconLongClickListener);
+                icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
+                        .getLongPressTimeout());
+                icon.setFocusable(true);
+                return new ViewHolder(icon);
+            }
+            case PREDICTION_ICON_VIEW_TYPE: {
+                BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
+                        R.layout.all_apps_prediction_bar_icon, parent, false);
+                icon.setOnTouchListener(mTouchListener);
+                icon.setOnClickListener(mIconClickListener);
+                icon.setOnLongClickListener(mIconLongClickListener);
+                icon.setLongPressTimeout(ViewConfiguration.get(parent.getContext())
+                        .getLongPressTimeout());
+                icon.setFocusable(true);
+                return new ViewHolder(icon);
+            }
+            default:
+                throw new RuntimeException("Unexpected view type");
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        switch (holder.getItemViewType()) {
+            case ICON_VIEW_TYPE: {
+                AppInfo info = mApps.getAdapterItems().get(position).appInfo;
+                BubbleTextView icon = (BubbleTextView) holder.mContent;
+                icon.applyFromApplicationInfo(info);
+                break;
+            }
+            case PREDICTION_ICON_VIEW_TYPE: {
+                AppInfo info = mApps.getAdapterItems().get(position).appInfo;
+                BubbleTextView icon = (BubbleTextView) holder.mContent;
+                icon.applyFromApplicationInfo(info);
+                break;
+            }
+            case EMPTY_SEARCH_VIEW_TYPE:
+                TextView emptyViewText = (TextView) holder.mContent.findViewById(R.id.empty_text);
+                emptyViewText.setText(mEmptySearchText);
+                break;
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        if (mApps.hasNoFilteredResults()) {
+            // For the empty view
+            return 1;
+        }
+        return mApps.getAdapterItems().size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (mApps.hasNoFilteredResults()) {
+            return EMPTY_SEARCH_VIEW_TYPE;
+        }
+
+        AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
+        return item.viewType;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
new file mode 100644
index 0000000..730c8d1
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.BaseRecyclerViewFastScrollBar;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Stats;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Thunk;
+
+import java.util.List;
+
+/**
+ * A RecyclerView with custom fast scroll support for the all apps view.
+ */
+public class AllAppsRecyclerView extends BaseRecyclerView
+        implements Stats.LaunchSourceProvider {
+
+    private static final int FAST_SCROLL_MODE_JUMP_TO_FIRST_ICON = 0;
+    private static final int FAST_SCROLL_MODE_FREE_SCROLL = 1;
+
+    private static final int FAST_SCROLL_BAR_MODE_DISTRIBUTE_BY_ROW = 0;
+    private static final int FAST_SCROLL_BAR_MODE_DISTRIBUTE_BY_SECTIONS = 1;
+
+    private AlphabeticalAppsList mApps;
+    private int mNumAppsPerRow;
+
+    @Thunk BaseRecyclerViewFastScrollBar.FastScrollFocusableView mLastFastScrollFocusedView;
+    @Thunk int mPrevFastScrollFocusedPosition;
+    @Thunk int mFastScrollFrameIndex;
+    @Thunk final int[] mFastScrollFrames = new int[10];
+
+    private final int mFastScrollMode = FAST_SCROLL_MODE_JUMP_TO_FIRST_ICON;
+    private final int mScrollBarMode = FAST_SCROLL_BAR_MODE_DISTRIBUTE_BY_ROW;
+
+    private ScrollPositionState mScrollPosState = new ScrollPositionState();
+
+    public AllAppsRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsRecyclerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    /**
+     * Sets the list of apps in this view, used to determine the fastscroll position.
+     */
+    public void setApps(AlphabeticalAppsList apps) {
+        mApps = apps;
+    }
+
+    /**
+     * Sets the number of apps per row in this recycler view.
+     */
+    public void setNumAppsPerRow(DeviceProfile grid, int numAppsPerRow) {
+        mNumAppsPerRow = numAppsPerRow;
+
+        RecyclerView.RecycledViewPool pool = getRecycledViewPool();
+        int approxRows = (int) Math.ceil(grid.availableHeightPx / grid.allAppsIconSizePx);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.EMPTY_SEARCH_VIEW_TYPE, 1);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.ICON_VIEW_TYPE, approxRows * mNumAppsPerRow);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE, mNumAppsPerRow);
+        pool.setMaxRecycledViews(AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE, approxRows);
+    }
+
+    /**
+     * Scrolls this recycler view to the top.
+     */
+    public void scrollToTop() {
+        scrollToPosition(0);
+    }
+
+    /**
+     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
+     * background bounds.
+     */
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
+                getWidth() - mBackgroundPadding.right,
+                getHeight() - mBackgroundPadding.bottom);
+        super.dispatchDraw(canvas);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        // Bind event handlers
+        addOnItemTouchListener(this);
+    }
+
+    @Override
+    public void fillInLaunchSourceData(Bundle sourceData) {
+        sourceData.putString(Stats.SOURCE_EXTRA_CONTAINER, Stats.CONTAINER_ALL_APPS);
+        if (mApps.hasFilter()) {
+            sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+                    Stats.SUB_CONTAINER_ALL_APPS_SEARCH);
+        } else {
+            sourceData.putString(Stats.SOURCE_EXTRA_SUB_CONTAINER,
+                    Stats.SUB_CONTAINER_ALL_APPS_A_Z);
+        }
+    }
+
+    /**
+     * Maps the touch (from 0..1) to the adapter position that should be visible.
+     */
+    @Override
+    public String scrollToPositionAtProgress(float touchFraction) {
+        int rowCount = mApps.getNumAppRows();
+        if (rowCount == 0) {
+            return "";
+        }
+
+        // Stop the scroller if it is scrolling
+        stopScroll();
+
+        // Find the fastscroll section that maps to this touch fraction
+        List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections =
+                mApps.getFastScrollerSections();
+        AlphabeticalAppsList.FastScrollSectionInfo lastInfo = fastScrollSections.get(0);
+        if (mScrollBarMode == FAST_SCROLL_BAR_MODE_DISTRIBUTE_BY_ROW) {
+            for (int i = 1; i < fastScrollSections.size(); i++) {
+                AlphabeticalAppsList.FastScrollSectionInfo info = fastScrollSections.get(i);
+                if (info.touchFraction > touchFraction) {
+                    break;
+                }
+                lastInfo = info;
+            }
+        } else if (mScrollBarMode == FAST_SCROLL_BAR_MODE_DISTRIBUTE_BY_SECTIONS){
+            lastInfo = fastScrollSections.get((int) (touchFraction * (fastScrollSections.size() - 1)));
+        } else {
+            throw new RuntimeException("Unexpected scroll bar mode");
+        }
+
+        // Map the touch position back to the scroll of the recycler view
+        getCurScrollState(mScrollPosState, mApps.getAdapterItems());
+        int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0);
+        LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
+        if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) {
+            layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
+        }
+
+        if (mPrevFastScrollFocusedPosition != lastInfo.fastScrollToItem.position) {
+            mPrevFastScrollFocusedPosition = lastInfo.fastScrollToItem.position;
+
+            // Reset the last focused view
+            if (mLastFastScrollFocusedView != null) {
+                mLastFastScrollFocusedView.setFastScrollFocused(false, true);
+                mLastFastScrollFocusedView = null;
+            }
+
+            if (mFastScrollMode == FAST_SCROLL_MODE_JUMP_TO_FIRST_ICON) {
+                smoothSnapToPosition(mPrevFastScrollFocusedPosition, mScrollPosState);
+            } else if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) {
+                final ViewHolder vh = findViewHolderForPosition(mPrevFastScrollFocusedPosition);
+                if (vh != null &&
+                        vh.itemView instanceof BaseRecyclerViewFastScrollBar.FastScrollFocusableView) {
+                    mLastFastScrollFocusedView =
+                            (BaseRecyclerViewFastScrollBar.FastScrollFocusableView) vh.itemView;
+                    mLastFastScrollFocusedView.setFastScrollFocused(true, true);
+                }
+            } else {
+                throw new RuntimeException("Unexpected fast scroll mode");
+            }
+        }
+        return lastInfo.sectionName;
+    }
+
+    @Override
+    public void onFastScrollCompleted() {
+        super.onFastScrollCompleted();
+        // Reset and clean up the last focused view
+        if (mLastFastScrollFocusedView != null) {
+            mLastFastScrollFocusedView.setFastScrollFocused(false, true);
+            mLastFastScrollFocusedView = null;
+        }
+        mPrevFastScrollFocusedPosition = -1;
+    }
+
+    /**
+     * Updates the bounds for the scrollbar.
+     */
+    @Override
+    public void onUpdateScrollbar() {
+        List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+
+        // Skip early if there are no items or we haven't been measured
+        if (items.isEmpty() || mNumAppsPerRow == 0) {
+            mScrollbar.setScrollbarThumbOffset(-1, -1);
+            return;
+        }
+
+        // Find the index and height of the first visible row (all rows have the same height)
+        int rowCount = mApps.getNumAppRows();
+        getCurScrollState(mScrollPosState, items);
+        if (mScrollPosState.rowIndex < 0) {
+            mScrollbar.setScrollbarThumbOffset(-1, -1);
+            return;
+        }
+
+        synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0);
+    }
+
+    /**
+     * This runnable runs a single frame of the smooth scroll animation and posts the next frame
+     * if necessary.
+     */
+    @Thunk Runnable mSmoothSnapNextFrameRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mFastScrollFrameIndex < mFastScrollFrames.length) {
+                scrollBy(0, mFastScrollFrames[mFastScrollFrameIndex]);
+                mFastScrollFrameIndex++;
+                postOnAnimation(mSmoothSnapNextFrameRunnable);
+            } else {
+                // Animation completed, set the fast scroll state on the target view
+                final ViewHolder vh = findViewHolderForPosition(mPrevFastScrollFocusedPosition);
+                if (vh != null &&
+                        vh.itemView instanceof BaseRecyclerViewFastScrollBar.FastScrollFocusableView &&
+                        mLastFastScrollFocusedView != vh.itemView) {
+                    mLastFastScrollFocusedView =
+                            (BaseRecyclerViewFastScrollBar.FastScrollFocusableView) vh.itemView;
+                    mLastFastScrollFocusedView.setFastScrollFocused(true, true);
+                }
+            }
+        }
+    };
+
+    /**
+     * Smoothly snaps to a given position.  We do this manually by calculating the keyframes
+     * ourselves and animating the scroll on the recycler view.
+     */
+    private void smoothSnapToPosition(final int position, ScrollPositionState scrollPosState) {
+        removeCallbacks(mSmoothSnapNextFrameRunnable);
+
+        // Calculate the full animation from the current scroll position to the final scroll
+        // position, and then run the animation for the duration.
+        int curScrollY = getPaddingTop() +
+                (scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset;
+        int newScrollY = getScrollAtPosition(position, scrollPosState.rowHeight);
+        int numFrames = mFastScrollFrames.length;
+        for (int i = 0; i < numFrames; i++) {
+            // TODO(winsonc): We can interpolate this as well.
+            mFastScrollFrames[i] = (newScrollY - curScrollY) / numFrames;
+        }
+        mFastScrollFrameIndex = 0;
+        postOnAnimation(mSmoothSnapNextFrameRunnable);
+    }
+
+    /**
+     * Returns the current scroll state of the apps rows.
+     */
+    private void getCurScrollState(ScrollPositionState stateOut,
+            List<AlphabeticalAppsList.AdapterItem> items) {
+        stateOut.rowIndex = -1;
+        stateOut.rowTopOffset = -1;
+        stateOut.rowHeight = -1;
+
+        // Return early if there are no items or we haven't been measured
+        if (items.isEmpty() || mNumAppsPerRow == 0) {
+            return;
+        }
+
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            int position = getChildPosition(child);
+            if (position != NO_POSITION) {
+                AlphabeticalAppsList.AdapterItem item = items.get(position);
+                if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE ||
+                        item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                    stateOut.rowIndex = item.rowIndex;
+                    stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
+                    stateOut.rowHeight = child.getHeight();
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the scrollY for the given position in the adapter.
+     */
+    private int getScrollAtPosition(int position, int rowHeight) {
+        AlphabeticalAppsList.AdapterItem item = mApps.getAdapterItems().get(position);
+        if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE ||
+                item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+            int offset = item.rowIndex > 0 ? getPaddingTop() : 0;
+            return offset + item.rowIndex * rowHeight;
+        } else {
+            return 0;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
new file mode 100644
index 0000000..14e2a18
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerViewContainerView.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.BubbleTextView.BubbleTextShadowHandler;
+import com.android.launcher3.ClickShadowView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+
+/**
+ * A container for RecyclerView to allow for the click shadow view to be shown behind an icon that
+ * is launching.
+ */
+public class AllAppsRecyclerViewContainerView extends FrameLayout
+        implements BubbleTextShadowHandler {
+
+    private final ClickShadowView mTouchFeedbackView;
+
+    public AllAppsRecyclerViewContainerView(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsRecyclerViewContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsRecyclerViewContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        Launcher launcher = (Launcher) context;
+        DeviceProfile grid = launcher.getDeviceProfile();
+
+        mTouchFeedbackView = new ClickShadowView(context);
+
+        // Make the feedback view large enough to hold the blur bitmap.
+        int size = grid.allAppsIconSizePx + mTouchFeedbackView.getExtraSize();
+        addView(mTouchFeedbackView, size, size);
+    }
+
+    @Override
+    public void setPressedIcon(BubbleTextView icon, Bitmap background) {
+        if (icon == null || background == null) {
+            mTouchFeedbackView.setBitmap(null);
+            mTouchFeedbackView.animate().cancel();
+        } else if (mTouchFeedbackView.setBitmap(background)) {
+            mTouchFeedbackView.alignWithIconView(icon, (ViewGroup) icon.getParent());
+            mTouchFeedbackView.animateShadow();
+        }
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
new file mode 100644
index 0000000..2b363c0
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsSearchBarController.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.util.ComponentKey;
+
+import java.util.ArrayList;
+
+/**
+ * An interface to a search box that AllApps can command.
+ */
+public abstract class AllAppsSearchBarController {
+
+    protected AlphabeticalAppsList mApps;
+    protected Callbacks mCb;
+
+    /**
+     * Sets the references to the apps model and the search result callback.
+     */
+    public final void initialize(AlphabeticalAppsList apps, Callbacks cb) {
+        mApps = apps;
+        mCb = cb;
+        onInitialize();
+    }
+
+    /**
+     * To be overridden by subclasses.  This method will get called when the controller is set,
+     * before getView().
+     */
+    protected abstract void onInitialize();
+
+    /**
+     * Returns the search bar view.
+     * @param parent the parent to attach the search bar view to.
+     */
+    public abstract View getView(ViewGroup parent);
+
+    /**
+     * Focuses the search field to handle key events.
+     */
+    public abstract void focusSearchField();
+
+    /**
+     * Returns whether the search field is focused.
+     */
+    public abstract boolean isSearchFieldFocused();
+
+    /**
+     * Resets the search bar state.
+     */
+    public abstract void reset();
+
+    /**
+     * Returns whether the prediction bar should currently be visible depending on the state of
+     * the search bar.
+     */
+    @Deprecated
+    public abstract boolean shouldShowPredictionBar();
+
+    /**
+     * Callback for getting search results.
+     */
+    public interface Callbacks {
+
+        /**
+         * Called when the bounds of the search bar has changed.
+         */
+        void onBoundsChanged(Rect newBounds);
+
+        /**
+         * Called when the search is complete.
+         *
+         * @param apps sorted list of matching components or null if in case of failure.
+         */
+        void onSearchResult(String query, ArrayList<ComponentKey> apps);
+
+        /**
+         * Called when the search results should be cleared.
+         */
+        void clearSearchResult();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsSearchEditView.java b/src/com/android/launcher3/allapps/AllAppsSearchEditView.java
new file mode 100644
index 0000000..b7dcd66
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AllAppsSearchEditView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.EditText;
+
+
+/**
+ * The edit text for the search container
+ */
+public class AllAppsSearchEditView extends EditText {
+
+    /**
+     * Implemented by listeners of the back key.
+     */
+    public interface OnBackKeyListener {
+        public void onBackKey();
+    }
+
+    private OnBackKeyListener mBackKeyListener;
+
+    public AllAppsSearchEditView(Context context) {
+        this(context, null);
+    }
+
+    public AllAppsSearchEditView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AllAppsSearchEditView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public void setOnBackKeyListener(OnBackKeyListener listener) {
+        mBackKeyListener = listener;
+    }
+
+    @Override
+    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+        // If this is a back key, propagate the key back to the listener
+        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
+            if (mBackKeyListener != null) {
+                mBackKeyListener.onBackKey();
+            }
+            return false;
+        }
+        return super.onKeyPreIme(keyCode, event);
+    }
+}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
new file mode 100644
index 0000000..47241ce
--- /dev/null
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.model.AppNameComparator;
+import com.android.launcher3.util.ComponentKey;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * The alphabetically sorted list of applications.
+ */
+public class AlphabeticalAppsList {
+
+    public static final String TAG = "AlphabeticalAppsList";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_PREDICTIONS = false;
+
+    /**
+     * Info about a section in the alphabetic list
+     */
+    public static class SectionInfo {
+        // The number of applications in this section
+        public int numApps;
+        // The section break AdapterItem for this section
+        public AdapterItem sectionBreakItem;
+        // The first app AdapterItem for this section
+        public AdapterItem firstAppItem;
+    }
+
+    /**
+     * Info about a fast scroller section, depending if sections are merged, the fast scroller
+     * sections will not be the same set as the section headers.
+     */
+    public static class FastScrollSectionInfo {
+        // The section name
+        public String sectionName;
+        // The AdapterItem to scroll to for this section
+        public AdapterItem fastScrollToItem;
+        // The touch fraction that should map to this fast scroll section info
+        public float touchFraction;
+
+        public FastScrollSectionInfo(String sectionName) {
+            this.sectionName = sectionName;
+        }
+    }
+
+    /**
+     * Info about a particular adapter item (can be either section or app)
+     */
+    public static class AdapterItem {
+        /** Common properties */
+        // The index of this adapter item in the list
+        public int position;
+        // The type of this item
+        public int viewType;
+        // The row that this item shows up on
+        public int rowIndex;
+
+        /** Section & App properties */
+        // The section for this item
+        public SectionInfo sectionInfo;
+
+        /** App-only properties */
+        // The section name of this app.  Note that there can be multiple items with different
+        // sectionNames in the same section
+        public String sectionName = null;
+        // The index of this app in the section
+        public int sectionAppIndex = -1;
+        // The index of this app in the row
+        public int rowAppIndex;
+        // The associated AppInfo for the app
+        public AppInfo appInfo = null;
+        // The index of this app not including sections
+        public int appIndex = -1;
+
+        public static AdapterItem asSectionBreak(int pos, SectionInfo section) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE;
+            item.position = pos;
+            item.sectionInfo = section;
+            section.sectionBreakItem = item;
+            return item;
+        }
+
+        public static AdapterItem asPredictedApp(int pos, SectionInfo section, String sectionName,
+                                        int sectionAppIndex, AppInfo appInfo, int appIndex) {
+            AdapterItem item = asApp(pos, section, sectionName, sectionAppIndex, appInfo, appIndex);
+            item.viewType = AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE;
+            return item;
+        }
+
+        public static AdapterItem asApp(int pos, SectionInfo section, String sectionName,
+                                        int sectionAppIndex, AppInfo appInfo, int appIndex) {
+            AdapterItem item = new AdapterItem();
+            item.viewType = AllAppsGridAdapter.ICON_VIEW_TYPE;
+            item.position = pos;
+            item.sectionInfo = section;
+            item.sectionName = sectionName;
+            item.sectionAppIndex = sectionAppIndex;
+            item.appInfo = appInfo;
+            item.appIndex = appIndex;
+            return item;
+        }
+    }
+
+    /**
+     * Common interface for different merging strategies.
+     */
+    public interface MergeAlgorithm {
+        boolean continueMerging(SectionInfo section, SectionInfo withSection,
+                int sectionAppCount, int numAppsPerRow, int mergeCount);
+    }
+
+    private Launcher mLauncher;
+
+    // The set of apps from the system not including predictions
+    private final List<AppInfo> mApps = new ArrayList<>();
+    private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
+
+    // The set of filtered apps with the current filter
+    private List<AppInfo> mFilteredApps = new ArrayList<>();
+    // The current set of adapter items
+    private List<AdapterItem> mAdapterItems = new ArrayList<>();
+    // The set of sections for the apps with the current filter
+    private List<SectionInfo> mSections = new ArrayList<>();
+    // The set of sections that we allow fast-scrolling to (includes non-merged sections)
+    private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
+    // The set of predicted app component names
+    private List<ComponentKey> mPredictedAppComponents = new ArrayList<>();
+    // The set of predicted apps resolved from the component names and the current set of apps
+    private List<AppInfo> mPredictedApps = new ArrayList<>();
+    // The of ordered component names as a result of a search query
+    private ArrayList<ComponentKey> mSearchResults;
+    private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
+    private RecyclerView.Adapter mAdapter;
+    private AlphabeticIndexCompat mIndexer;
+    private AppNameComparator mAppNameComparator;
+    private MergeAlgorithm mMergeAlgorithm;
+    private int mNumAppsPerRow;
+    private int mNumPredictedAppsPerRow;
+    private int mNumAppRowsInAdapter;
+
+    public AlphabeticalAppsList(Context context) {
+        mLauncher = (Launcher) context;
+        mIndexer = new AlphabeticIndexCompat(context);
+        mAppNameComparator = new AppNameComparator(context);
+    }
+
+    /**
+     * Sets the number of apps per row.
+     */
+    public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow,
+            MergeAlgorithm mergeAlgorithm) {
+        mNumAppsPerRow = numAppsPerRow;
+        mNumPredictedAppsPerRow = numPredictedAppsPerRow;
+        mMergeAlgorithm = mergeAlgorithm;
+
+        updateAdapterItems();
+    }
+
+    /**
+     * Sets the adapter to notify when this dataset changes.
+     */
+    public void setAdapter(RecyclerView.Adapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Returns all the apps.
+     */
+    public List<AppInfo> getApps() {
+        return mApps;
+    }
+
+    /**
+     * Returns sections of all the current filtered applications.
+     */
+    public List<SectionInfo> getSections() {
+        return mSections;
+    }
+
+    /**
+     * Returns fast scroller sections of all the current filtered applications.
+     */
+    public List<FastScrollSectionInfo> getFastScrollerSections() {
+        return mFastScrollerSections;
+    }
+
+    /**
+     * Returns the current filtered list of applications broken down into their sections.
+     */
+    public List<AdapterItem> getAdapterItems() {
+        return mAdapterItems;
+    }
+
+    /**
+     * Returns the number of applications in this list.
+     */
+    public int getSize() {
+        return mFilteredApps.size();
+    }
+
+    /**
+     * Returns the number of rows of applications (not including predictions)
+     */
+    public int getNumAppRows() {
+        return mNumAppRowsInAdapter;
+    }
+
+    /**
+     * Returns whether there are is a filter set.
+     */
+    public boolean hasFilter() {
+        return (mSearchResults != null);
+    }
+
+    /**
+     * Returns whether there are no filtered results.
+     */
+    public boolean hasNoFilteredResults() {
+        return (mSearchResults != null) && mFilteredApps.isEmpty();
+    }
+
+    /**
+     * Sets the sorted list of filtered components.
+     */
+    public void setOrderedFilter(ArrayList<ComponentKey> f) {
+        if (mSearchResults != f) {
+            mSearchResults = f;
+            updateAdapterItems();
+        }
+    }
+
+    /**
+     * Sets the current set of predicted apps.  Since this can be called before we get the full set
+     * of applications, we should merge the results only in onAppsUpdated() which is idempotent.
+     */
+    public void setPredictedApps(List<ComponentKey> apps) {
+        mPredictedAppComponents.clear();
+        mPredictedAppComponents.addAll(apps);
+        onAppsUpdated();
+    }
+
+    /**
+     * Sets the current set of apps.
+     */
+    public void setApps(List<AppInfo> apps) {
+        mComponentToAppMap.clear();
+        addApps(apps);
+    }
+
+    /**
+     * Adds new apps to the list.
+     */
+    public void addApps(List<AppInfo> apps) {
+        updateApps(apps);
+    }
+
+    /**
+     * Updates existing apps in the list
+     */
+    public void updateApps(List<AppInfo> apps) {
+        for (AppInfo app : apps) {
+            mComponentToAppMap.put(app.toComponentKey(), app);
+        }
+        onAppsUpdated();
+    }
+
+    /**
+     * Removes some apps from the list.
+     */
+    public void removeApps(List<AppInfo> apps) {
+        for (AppInfo app : apps) {
+            mComponentToAppMap.remove(app.toComponentKey());
+        }
+        onAppsUpdated();
+    }
+
+    /**
+     * Updates internals when the set of apps are updated.
+     */
+    private void onAppsUpdated() {
+        // Sort the list of apps
+        mApps.clear();
+        mApps.addAll(mComponentToAppMap.values());
+        Collections.sort(mApps, mAppNameComparator.getAppInfoComparator());
+
+        // As a special case for some languages (currently only Simplified Chinese), we may need to
+        // coalesce sections
+        Locale curLocale = mLauncher.getResources().getConfiguration().locale;
+        TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
+        boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
+        if (localeRequiresSectionSorting) {
+            // Compute the section headers.  We use a TreeMap with the section name comparator to
+            // ensure that the sections are ordered when we iterate over it later
+            sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
+            for (AppInfo info : mApps) {
+                // Add the section to the cache
+                String sectionName = getAndUpdateCachedSectionName(info.title);
+
+                // Add it to the mapping
+                ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
+                if (sectionApps == null) {
+                    sectionApps = new ArrayList<>();
+                    sectionMap.put(sectionName, sectionApps);
+                }
+                sectionApps.add(info);
+            }
+
+            // Add each of the section apps to the list in order
+            List<AppInfo> allApps = new ArrayList<>(mApps.size());
+            for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
+                allApps.addAll(entry.getValue());
+            }
+
+            mApps.clear();
+            mApps.addAll(allApps);
+        } else {
+            // Just compute the section headers for use below
+            for (AppInfo info : mApps) {
+                // Add the section to the cache
+                getAndUpdateCachedSectionName(info.title);
+            }
+        }
+
+        // Recompose the set of adapter items from the current set of apps
+        updateAdapterItems();
+    }
+
+    /**
+     * Updates the set of filtered apps with the current filter.  At this point, we expect
+     * mCachedSectionNames to have been calculated for the set of all apps in mApps.
+     */
+    private void updateAdapterItems() {
+        SectionInfo lastSectionInfo = null;
+        String lastSectionName = null;
+        FastScrollSectionInfo lastFastScrollerSectionInfo = null;
+        int position = 0;
+        int appIndex = 0;
+
+        // Prepare to update the list of sections, filtered apps, etc.
+        mFilteredApps.clear();
+        mFastScrollerSections.clear();
+        mAdapterItems.clear();
+        mSections.clear();
+
+        if (DEBUG_PREDICTIONS) {
+            if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+                mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
+                        UserHandleCompat.myUserHandle()));
+            }
+        }
+
+        // Process the predicted app components
+        mPredictedApps.clear();
+        if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
+            for (ComponentKey ck : mPredictedAppComponents) {
+                AppInfo info = mComponentToAppMap.get(ck);
+                if (info != null) {
+                    mPredictedApps.add(info);
+                } else {
+                    if (LauncherAppState.isDogfoodBuild()) {
+                        Log.e(TAG, "Predicted app not found: " + ck.flattenToString(mLauncher));
+                    }
+                }
+                // Stop at the number of predicted apps
+                if (mPredictedApps.size() == mNumPredictedAppsPerRow) {
+                    break;
+                }
+            }
+
+            if (!mPredictedApps.isEmpty()) {
+                // Add a section for the predictions
+                lastSectionInfo = new SectionInfo();
+                lastFastScrollerSectionInfo = new FastScrollSectionInfo("");
+                AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
+                mSections.add(lastSectionInfo);
+                mFastScrollerSections.add(lastFastScrollerSectionInfo);
+                mAdapterItems.add(sectionItem);
+
+                // Add the predicted app items
+                for (AppInfo info : mPredictedApps) {
+                    AdapterItem appItem = AdapterItem.asPredictedApp(position++, lastSectionInfo,
+                            "", lastSectionInfo.numApps++, info, appIndex++);
+                    if (lastSectionInfo.firstAppItem == null) {
+                        lastSectionInfo.firstAppItem = appItem;
+                        lastFastScrollerSectionInfo.fastScrollToItem = appItem;
+                    }
+                    mAdapterItems.add(appItem);
+                    mFilteredApps.add(info);
+                }
+            }
+        }
+
+        // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
+        // ordered set of sections
+        for (AppInfo info : getFiltersAppInfos()) {
+            String sectionName = getAndUpdateCachedSectionName(info.title);
+
+            // Create a new section if the section names do not match
+            if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
+                lastSectionName = sectionName;
+                lastSectionInfo = new SectionInfo();
+                lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
+                mSections.add(lastSectionInfo);
+                mFastScrollerSections.add(lastFastScrollerSectionInfo);
+
+                // Create a new section item to break the flow of items in the list
+                if (!hasFilter()) {
+                    AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
+                    mAdapterItems.add(sectionItem);
+                }
+            }
+
+            // Create an app item
+            AdapterItem appItem = AdapterItem.asApp(position++, lastSectionInfo, sectionName,
+                    lastSectionInfo.numApps++, info, appIndex++);
+            if (lastSectionInfo.firstAppItem == null) {
+                lastSectionInfo.firstAppItem = appItem;
+                lastFastScrollerSectionInfo.fastScrollToItem = appItem;
+            }
+            mAdapterItems.add(appItem);
+            mFilteredApps.add(info);
+        }
+
+        // Merge multiple sections together as requested by the merge strategy for this device
+        mergeSections();
+
+        if (mNumAppsPerRow != 0) {
+            // Update the number of rows in the adapter after we do all the merging (otherwise, we
+            // would have to shift the values again)
+            int numAppsInSection = 0;
+            int numAppsInRow = 0;
+            int rowIndex = -1;
+            for (AdapterItem item : mAdapterItems) {
+                item.rowIndex = 0;
+                if (item.viewType == AllAppsGridAdapter.SECTION_BREAK_VIEW_TYPE) {
+                    numAppsInSection = 0;
+                } else if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE ||
+                        item.viewType == AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                    if (numAppsInSection % mNumAppsPerRow == 0) {
+                        numAppsInRow = 0;
+                        rowIndex++;
+                    }
+                    item.rowIndex = rowIndex;
+                    item.rowAppIndex = numAppsInRow;
+                    numAppsInSection++;
+                    numAppsInRow++;
+                }
+            }
+            mNumAppRowsInAdapter = rowIndex + 1;
+
+            // Pre-calculate all the fast scroller fractions based on the number of rows
+            float rowFraction = 1f / mNumAppRowsInAdapter;
+            for (FastScrollSectionInfo info : mFastScrollerSections) {
+                AdapterItem item = info.fastScrollToItem;
+                if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE &&
+                        item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) {
+                    info.touchFraction = 0f;
+                    continue;
+                }
+
+                float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow);
+                info.touchFraction = item.rowIndex * rowFraction + subRowFraction;
+            }
+        }
+
+        // Refresh the recycler view
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    private List<AppInfo> getFiltersAppInfos() {
+        if (mSearchResults == null) {
+            return mApps;
+        }
+
+        ArrayList<AppInfo> result = new ArrayList<>();
+        for (ComponentKey key : mSearchResults) {
+            AppInfo match = mComponentToAppMap.get(key);
+            if (match != null) {
+                result.add(match);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Merges multiple sections to reduce visual raggedness.
+     */
+    private void mergeSections() {
+        // Ignore merging until we have an algorithm and a valid row size
+        if (mMergeAlgorithm == null || mNumAppsPerRow == 0) {
+            return;
+        }
+
+        // Go through each section and try and merge some of the sections
+        if (!hasFilter()) {
+            int sectionAppCount = 0;
+            for (int i = 0; i < mSections.size() - 1; i++) {
+                SectionInfo section = mSections.get(i);
+                sectionAppCount = section.numApps;
+                int mergeCount = 1;
+
+                // Merge rows based on the current strategy
+                while (i < (mSections.size() - 1) &&
+                        mMergeAlgorithm.continueMerging(section, mSections.get(i + 1),
+                                sectionAppCount, mNumAppsPerRow, mergeCount)) {
+                    SectionInfo nextSection = mSections.remove(i + 1);
+
+                    // Remove the next section break
+                    mAdapterItems.remove(nextSection.sectionBreakItem);
+                    int pos = mAdapterItems.indexOf(section.firstAppItem);
+
+                    // Point the section for these new apps to the merged section
+                    int nextPos = pos + section.numApps;
+                    for (int j = nextPos; j < (nextPos + nextSection.numApps); j++) {
+                        AdapterItem item = mAdapterItems.get(j);
+                        item.sectionInfo = section;
+                        item.sectionAppIndex += section.numApps;
+                    }
+
+                    // Update the following adapter items of the removed section item
+                    pos = mAdapterItems.indexOf(nextSection.firstAppItem);
+                    for (int j = pos; j < mAdapterItems.size(); j++) {
+                        AdapterItem item = mAdapterItems.get(j);
+                        item.position--;
+                    }
+                    section.numApps += nextSection.numApps;
+                    sectionAppCount += nextSection.numApps;
+
+                    if (DEBUG) {
+                        Log.d(TAG, "Merging: " + nextSection.firstAppItem.sectionName +
+                                " to " + section.firstAppItem.sectionName +
+                                " mergedNumRows: " + (sectionAppCount / mNumAppsPerRow));
+                    }
+                    mergeCount++;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the cached section name for the given title, recomputing and updating the cache if
+     * the title has no cached section name.
+     */
+    private String getAndUpdateCachedSectionName(CharSequence title) {
+        String sectionName = mCachedSectionNames.get(title);
+        if (sectionName == null) {
+            sectionName = mIndexer.computeSectionName(title);
+            mCachedSectionNames.put(title, sectionName);
+        }
+        return sectionName;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java
new file mode 100644
index 0000000..10740ec
--- /dev/null
+++ b/src/com/android/launcher3/allapps/DefaultAppSearchAlgorithm.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.os.Handler;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.util.ComponentKey;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * The default search implementation.
+ */
+public class DefaultAppSearchAlgorithm {
+
+    private static final Pattern SPLIT_PATTERN = Pattern.compile("[\\s|\\p{javaSpaceChar}]+");
+
+    private final List<AppInfo> mApps;
+    protected final Handler mResultHandler;
+
+    public DefaultAppSearchAlgorithm(List<AppInfo> apps) {
+        mApps = apps;
+        mResultHandler = new Handler();
+    }
+
+    public void cancel(boolean interruptActiveRequests) {
+        if (interruptActiveRequests) {
+            mResultHandler.removeCallbacksAndMessages(null);
+        }
+    }
+
+    public void doSearch(final String query,
+            final AllAppsSearchBarController.Callbacks callback) {
+        final ArrayList<ComponentKey> result = getTitleMatchResult(query);
+        mResultHandler.post(new Runnable() {
+
+            @Override
+            public void run() {
+                callback.onSearchResult(query, result);
+            }
+        });
+    }
+
+    protected ArrayList<ComponentKey> getTitleMatchResult(String query) {
+        // Do an intersection of the words in the query and each title, and filter out all the
+        // apps that don't match all of the words in the query.
+        final String queryTextLower = query.toLowerCase();
+        final String[] queryWords = SPLIT_PATTERN.split(queryTextLower);
+
+        final ArrayList<ComponentKey> result = new ArrayList<>();
+        for (AppInfo info : mApps) {
+            if (matches(info, queryWords)) {
+                result.add(info.toComponentKey());
+            }
+        }
+        return result;
+    }
+
+    protected boolean matches(AppInfo info, String[] queryWords) {
+        String title = info.title.toString();
+        String[] words = SPLIT_PATTERN.split(title.toLowerCase());
+        for (int qi = 0; qi < queryWords.length; qi++) {
+            boolean foundMatch = false;
+            for (int i = 0; i < words.length; i++) {
+                if (words[i].startsWith(queryWords[qi])) {
+                    foundMatch = true;
+                    break;
+                }
+            }
+            if (!foundMatch) {
+                // If there is a word in the query that does not match any words in this
+                // title, so skip it.
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchController.java b/src/com/android/launcher3/allapps/DefaultAppSearchController.java
new file mode 100644
index 0000000..83b9205
--- /dev/null
+++ b/src/com/android/launcher3/allapps/DefaultAppSearchController.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.Thunk;
+
+import java.util.List;
+
+
+/**
+ * The default search controller.
+ */
+final class DefaultAppSearchController extends AllAppsSearchBarController
+        implements TextWatcher, TextView.OnEditorActionListener, View.OnClickListener {
+
+    private static final boolean ALLOW_SINGLE_APP_LAUNCH = true;
+
+    private static final int FADE_IN_DURATION = 175;
+    private static final int FADE_OUT_DURATION = 100;
+    private static final int SEARCH_TRANSLATION_X_DP = 18;
+
+    private final Context mContext;
+    @Thunk final InputMethodManager mInputMethodManager;
+
+    private DefaultAppSearchAlgorithm mSearchManager;
+
+    private ViewGroup mContainerView;
+    private View mSearchView;
+    @Thunk View mSearchBarContainerView;
+    private View mSearchButtonView;
+    private View mDismissSearchButtonView;
+    @Thunk AllAppsSearchEditView mSearchBarEditView;
+    @Thunk AllAppsRecyclerView mAppsRecyclerView;
+    @Thunk Runnable mFocusRecyclerViewRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mAppsRecyclerView.requestFocus();
+        }
+    };
+
+    public DefaultAppSearchController(Context context, ViewGroup containerView,
+            AllAppsRecyclerView appsRecyclerView) {
+        mContext = context;
+        mInputMethodManager = (InputMethodManager)
+                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mContainerView = containerView;
+        mAppsRecyclerView = appsRecyclerView;
+    }
+
+    @Override
+    public View getView(ViewGroup parent) {
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        mSearchView = inflater.inflate(R.layout.all_apps_search_bar, parent, false);
+        mSearchView.setOnClickListener(this);
+
+        mSearchButtonView = mSearchView.findViewById(R.id.search_button);
+        mSearchBarContainerView = mSearchView.findViewById(R.id.search_container);
+        mDismissSearchButtonView = mSearchBarContainerView.findViewById(R.id.dismiss_search_button);
+        mDismissSearchButtonView.setOnClickListener(this);
+        mSearchBarEditView = (AllAppsSearchEditView)
+                mSearchBarContainerView.findViewById(R.id.search_box_input);
+        mSearchBarEditView.addTextChangedListener(this);
+        mSearchBarEditView.setOnEditorActionListener(this);
+        mSearchBarEditView.setOnBackKeyListener(
+                new AllAppsSearchEditView.OnBackKeyListener() {
+                    @Override
+                    public void onBackKey() {
+                        // Only hide the search field if there is no query, or if there
+                        // are no filtered results
+                        String query = Utilities.trim(
+                                mSearchBarEditView.getEditableText().toString());
+                        if (query.isEmpty() || mApps.hasNoFilteredResults()) {
+                            hideSearchField(true, mFocusRecyclerViewRunnable);
+                        }
+                    }
+                });
+        return mSearchView;
+    }
+
+    @Override
+    public void focusSearchField() {
+        mSearchBarEditView.requestFocus();
+        showSearchField();
+    }
+
+    @Override
+    public boolean isSearchFieldFocused() {
+        return mSearchBarEditView.isFocused();
+    }
+
+    @Override
+    protected void onInitialize() {
+        mSearchManager = new DefaultAppSearchAlgorithm(mApps.getApps());
+    }
+
+    @Override
+    public void reset() {
+        hideSearchField(false, null);
+    }
+
+    @Override
+    public boolean shouldShowPredictionBar() {
+        return false;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mSearchView) {
+            showSearchField();
+        } else if (v == mDismissSearchButtonView) {
+            hideSearchField(true, mFocusRecyclerViewRunnable);
+        }
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        // Do nothing
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+        // Do nothing
+    }
+
+    @Override
+    public void afterTextChanged(final Editable s) {
+        String query = s.toString();
+        if (query.isEmpty()) {
+            mSearchManager.cancel(true);
+            mCb.clearSearchResult();
+        } else {
+            mSearchManager.cancel(false);
+            mSearchManager.doSearch(query, mCb);
+        }
+    }
+
+    @Override
+    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+        // Skip if we disallow app-launch-on-enter
+        if (!ALLOW_SINGLE_APP_LAUNCH) {
+            return false;
+        }
+        // Skip if it's not the right action
+        if (actionId != EditorInfo.IME_ACTION_DONE) {
+            return false;
+        }
+        // Skip if there isn't exactly one item
+        if (mApps.getSize() != 1) {
+            return false;
+        }
+        // If there is exactly one icon, then quick-launch it
+        List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
+        for (int i = 0; i < items.size(); i++) {
+            AlphabeticalAppsList.AdapterItem item = items.get(i);
+            if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE) {
+                mAppsRecyclerView.getChildAt(i).performClick();
+                mInputMethodManager.hideSoftInputFromWindow(
+                        mContainerView.getWindowToken(), 0);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Focuses the search field.
+     */
+    private void showSearchField() {
+        // Show the search bar and focus the search
+        final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
+                mContext.getResources().getDisplayMetrics());
+        mSearchBarContainerView.setVisibility(View.VISIBLE);
+        mSearchBarContainerView.setAlpha(0f);
+        mSearchBarContainerView.setTranslationX(translationX);
+        mSearchBarContainerView.animate()
+                .alpha(1f)
+                .translationX(0)
+                .setDuration(FADE_IN_DURATION)
+                .withLayer()
+                .withEndAction(new Runnable() {
+                    @Override
+                    public void run() {
+                        mSearchBarEditView.requestFocus();
+                        mInputMethodManager.showSoftInput(mSearchBarEditView,
+                                InputMethodManager.SHOW_IMPLICIT);
+                    }
+                });
+        mSearchButtonView.animate()
+                .alpha(0f)
+                .translationX(-translationX)
+                .setDuration(FADE_OUT_DURATION)
+                .withLayer();
+    }
+
+    /**
+     * Unfocuses the search field.
+     */
+    @Thunk void hideSearchField(boolean animated, final Runnable postAnimationRunnable) {
+        mSearchManager.cancel(true);
+
+        final boolean resetTextField = mSearchBarEditView.getText().toString().length() > 0;
+        final int translationX = Utilities.pxFromDp(SEARCH_TRANSLATION_X_DP,
+                mContext.getResources().getDisplayMetrics());
+        if (animated) {
+            // Hide the search bar and focus the recycler view
+            mSearchBarContainerView.animate()
+                    .alpha(0f)
+                    .translationX(0)
+                    .setDuration(FADE_IN_DURATION)
+                    .withLayer()
+                    .withEndAction(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSearchBarContainerView.setVisibility(View.INVISIBLE);
+                            if (resetTextField) {
+                                mSearchBarEditView.setText("");
+                            }
+                            mCb.clearSearchResult();
+                            if (postAnimationRunnable != null) {
+                                postAnimationRunnable.run();
+                            }
+                        }
+                    });
+            mSearchButtonView.setTranslationX(-translationX);
+            mSearchButtonView.animate()
+                    .alpha(1f)
+                    .translationX(0)
+                    .setDuration(FADE_OUT_DURATION)
+                    .withLayer();
+        } else {
+            mSearchBarContainerView.setVisibility(View.INVISIBLE);
+            if (resetTextField) {
+                mSearchBarEditView.setText("");
+            }
+            mCb.clearSearchResult();
+            mSearchButtonView.setAlpha(1f);
+            mSearchButtonView.setTranslationX(0f);
+            if (postAnimationRunnable != null) {
+                postAnimationRunnable.run();
+            }
+        }
+        mInputMethodManager.hideSoftInputFromWindow(mContainerView.getWindowToken(), 0);
+    }
+}
diff --git a/src/com/android/launcher3/compat/AlphabeticIndexCompat.java b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
new file mode 100644
index 0000000..ec1fb66
--- /dev/null
+++ b/src/com/android/launcher3/compat/AlphabeticIndexCompat.java
@@ -0,0 +1,170 @@
+package com.android.launcher3.compat;
+
+import android.content.Context;
+import com.android.launcher3.Utilities;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+/**
+ * Fallback class to support Alphabetic indexing if not supported by the framework.
+ * TODO(winsonc): disable for non-english locales
+ */
+class BaseAlphabeticIndex {
+
+    private static final String BUCKETS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-";
+    private static final int UNKNOWN_BUCKET_INDEX = BUCKETS.length() - 1;
+
+    public BaseAlphabeticIndex() {}
+
+    /**
+     * Sets the max number of the label buckets in this index.
+     */
+    public void setMaxLabelCount(int count) {
+        // Not currently supported
+    }
+
+    /**
+     * Returns the index of the bucket in which the given string should appear.
+     */
+    protected int getBucketIndex(String s) {
+        if (s.isEmpty()) {
+            return UNKNOWN_BUCKET_INDEX;
+        }
+        int index = BUCKETS.indexOf(s.substring(0, 1).toUpperCase());
+        if (index != -1) {
+            return index;
+        }
+        return UNKNOWN_BUCKET_INDEX;
+    }
+
+    /**
+     * Returns the label for the bucket at the given index (as returned by getBucketIndex).
+     */
+    protected String getBucketLabel(int index) {
+        return BUCKETS.substring(index, index + 1);
+    }
+}
+
+/**
+ * Reflected libcore.icu.AlphabeticIndex implementation, falls back to the base alphabetic index.
+ */
+public class AlphabeticIndexCompat extends BaseAlphabeticIndex {
+
+    private static final String MID_DOT = "\u2219";
+
+    private Object mAlphabeticIndex;
+    private Method mAddLabelsMethod;
+    private Method mSetMaxLabelCountMethod;
+    private Method mGetBucketIndexMethod;
+    private Method mGetBucketLabelMethod;
+    private boolean mHasValidAlphabeticIndex;
+    private String mDefaultMiscLabel;
+
+    public AlphabeticIndexCompat(Context context) {
+        super();
+        try {
+            Locale curLocale = context.getResources().getConfiguration().locale;
+            Class clazz = Class.forName("libcore.icu.AlphabeticIndex");
+            Constructor ctor = clazz.getConstructor(Locale.class);
+            mAddLabelsMethod = clazz.getDeclaredMethod("addLabels", Locale.class);
+            mSetMaxLabelCountMethod = clazz.getDeclaredMethod("setMaxLabelCount", int.class);
+            mGetBucketIndexMethod = clazz.getDeclaredMethod("getBucketIndex", String.class);
+            mGetBucketLabelMethod = clazz.getDeclaredMethod("getBucketLabel", int.class);
+            mAlphabeticIndex = ctor.newInstance(curLocale);
+            try {
+                // Ensure we always have some base English locale buckets
+                if (!curLocale.getLanguage().equals(Locale.ENGLISH.getLanguage())) {
+                    mAddLabelsMethod.invoke(mAlphabeticIndex, Locale.ENGLISH);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            if (curLocale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
+                // Japanese character 他 ("misc")
+                mDefaultMiscLabel = "\u4ed6";
+                // TODO(winsonc, omakoto): We need to handle Japanese sections better, especially the kanji
+            } else {
+                // Dot
+                mDefaultMiscLabel = MID_DOT;
+            }
+            mHasValidAlphabeticIndex = true;
+        } catch (Exception e) {
+            mHasValidAlphabeticIndex = false;
+        }
+    }
+
+    /**
+     * Sets the max number of the label buckets in this index.
+     * (ICU 51 default is 99)
+     */
+    public void setMaxLabelCount(int count) {
+        if (mHasValidAlphabeticIndex) {
+            try {
+                mSetMaxLabelCountMethod.invoke(mAlphabeticIndex, count);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        } else {
+            super.setMaxLabelCount(count);
+        }
+    }
+
+    /**
+     * Computes the section name for an given string {@param s}.
+     */
+    public String computeSectionName(CharSequence cs) {
+        String s = Utilities.trim(cs);
+        String sectionName = getBucketLabel(getBucketIndex(s));
+        if (Utilities.trim(sectionName).isEmpty() && s.length() > 0) {
+            int c = s.codePointAt(0);
+            boolean startsWithDigit = Character.isDigit(c);
+            if (startsWithDigit) {
+                // Digit section
+                return "#";
+            } else {
+                boolean startsWithLetter = Character.isLetter(c);
+                if (startsWithLetter) {
+                    return mDefaultMiscLabel;
+                } else {
+                    // In languages where these differ, this ensures that we differentiate
+                    // between the misc section in the native language and a misc section
+                    // for everything else.
+                    return MID_DOT;
+                }
+            }
+        }
+        return sectionName;
+    }
+
+    /**
+     * Returns the index of the bucket in which {@param s} should appear.
+     * Function is synchronized because underlying routine walks an iterator
+     * whose state is maintained inside the index object.
+     */
+    protected int getBucketIndex(String s) {
+        if (mHasValidAlphabeticIndex) {
+            try {
+                return (Integer) mGetBucketIndexMethod.invoke(mAlphabeticIndex, s);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return super.getBucketIndex(s);
+    }
+
+    /**
+     * Returns the label for the bucket at the given index (as returned by getBucketIndex).
+     */
+    protected String getBucketLabel(int index) {
+        if (mHasValidAlphabeticIndex) {
+            try {
+                return (String) mGetBucketLabelMethod.invoke(mAlphabeticIndex, index);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return super.getBucketLabel(index);
+    }
+}
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
index 6512d42..7aa36d4 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 
 import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.Utilities;
 
 import java.util.List;
@@ -63,20 +64,21 @@
 
     public abstract List<AppWidgetProviderInfo> getAllProviders();
 
-    public abstract String loadLabel(AppWidgetProviderInfo info);
+    public abstract String loadLabel(LauncherAppWidgetProviderInfo info);
 
     public abstract boolean bindAppWidgetIdIfAllowed(
             int appWidgetId, AppWidgetProviderInfo info, Bundle options);
 
-    public abstract UserHandleCompat getUser(AppWidgetProviderInfo info);
+    public abstract UserHandleCompat getUser(LauncherAppWidgetProviderInfo info);
 
     public abstract void startConfigActivity(AppWidgetProviderInfo info, int widgetId,
             Activity activity, AppWidgetHost host, int requestCode);
 
     public abstract Drawable loadPreview(AppWidgetProviderInfo info);
 
-    public abstract Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache);
+    public abstract Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache);
 
-    public abstract Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap);
+    public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
+            int imageHeight);
 
 }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
index f599f43..f7f4b7e 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
@@ -28,6 +29,7 @@
 import android.os.Bundle;
 
 import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.Utilities;
 
 import java.util.List;
@@ -44,10 +46,11 @@
     }
 
     @Override
-    public String loadLabel(AppWidgetProviderInfo info) {
-        return info.label.trim();
+    public String loadLabel(LauncherAppWidgetProviderInfo info) {
+        return Utilities.trim(info.label);
     }
 
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     @Override
     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
             Bundle options) {
@@ -59,7 +62,7 @@
     }
 
     @Override
-    public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+    public UserHandleCompat getUser(LauncherAppWidgetProviderInfo info) {
         return UserHandleCompat.myUserHandle();
     }
 
@@ -79,12 +82,13 @@
     }
 
     @Override
-    public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
+    public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) {
         return cache.getFullResIcon(info.provider.getPackageName(), info.icon);
     }
 
     @Override
-    public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
+    public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
+            int imageHeight) {
         return bitmap;
     }
 }
diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
index 03d43a6..13712d8 100644
--- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java
@@ -38,6 +38,7 @@
 import android.widget.Toast;
 
 import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.R;
 
 import java.util.ArrayList;
@@ -65,8 +66,8 @@
     }
 
     @Override
-    public String loadLabel(AppWidgetProviderInfo info) {
-        return info.loadLabel(mPm);
+    public String loadLabel(LauncherAppWidgetProviderInfo info) {
+        return info.getLabel(mPm);
     }
 
     @Override
@@ -77,7 +78,10 @@
     }
 
     @Override
-    public UserHandleCompat getUser(AppWidgetProviderInfo info) {
+    public UserHandleCompat getUser(LauncherAppWidgetProviderInfo info) {
+        if (info.isCustomWidget) {
+            return UserHandleCompat.myUserHandle();
+        }
         return UserHandleCompat.fromUser(info.getProfile());
     }
 
@@ -99,27 +103,28 @@
     }
 
     @Override
-    public Drawable loadIcon(AppWidgetProviderInfo info, IconCache cache) {
-        return info.loadIcon(mContext, cache.getFullResIconDpi());
+    public Drawable loadIcon(LauncherAppWidgetProviderInfo info, IconCache cache) {
+        return info.getIcon(mContext, cache);
     }
 
     @Override
-    public Bitmap getBadgeBitmap(AppWidgetProviderInfo info, Bitmap bitmap) {
-        if (info.getProfile().equals(android.os.Process.myUserHandle())) {
+    public Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap,
+            int imageHeight) {
+        if (info.isCustomWidget || info.getProfile().equals(android.os.Process.myUserHandle())) {
             return bitmap;
         }
 
         // Add a user badge in the bottom right of the image.
         final Resources res = mContext.getResources();
         final int badgeSize = res.getDimensionPixelSize(R.dimen.profile_badge_size);
-        final int badgeMargin = res.getDimensionPixelSize(R.dimen.profile_badge_margin);
+        final int badgeMinTop = res.getDimensionPixelSize(R.dimen.profile_badge_minimum_top);
         final Rect badgeLocation = new Rect(0, 0, badgeSize, badgeSize);
 
-        final int top = bitmap.getHeight() - badgeSize - badgeMargin;
+        final int top = Math.max(imageHeight - badgeSize, badgeMinTop);
         if (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-            badgeLocation.offset(badgeMargin, top);
+            badgeLocation.offset(0, top);
         } else {
-            badgeLocation.offset(bitmap.getWidth() - badgeSize - badgeMargin, top);
+            badgeLocation.offset(bitmap.getWidth() - badgeSize, top);
         }
 
         Drawable drawable = mPm.getUserBadgedDrawableForDensity(
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
index 90a4d1a..07ef0ef 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
@@ -17,7 +17,9 @@
 package com.android.launcher3.compat;
 
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 
 public abstract class LauncherActivityInfoCompat {
@@ -32,4 +34,11 @@
     public abstract ApplicationInfo getApplicationInfo();
     public abstract long getFirstInstallTime();
     public abstract Drawable getBadgedIcon(int density);
+
+    /**
+     * Creates a LauncherActivityInfoCompat for the primary user.
+     */
+    public static LauncherActivityInfoCompat fromResolveInfo(ResolveInfo info, Context context) {
+        return new LauncherActivityInfoCompatV16(context, info);
+    }
 }
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
index 1d41a6f..ea51aac 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatV16.java
@@ -29,13 +29,15 @@
 
 
 public class LauncherActivityInfoCompatV16 extends LauncherActivityInfoCompat {
-    private ActivityInfo mActivityInfo;
-    private ComponentName mComponentName;
-    private PackageManager mPm;
+    private final ResolveInfo mResolveInfo;
+    private final ActivityInfo mActivityInfo;
+    private final ComponentName mComponentName;
+    private final PackageManager mPm;
 
     LauncherActivityInfoCompatV16(Context context, ResolveInfo info) {
         super();
-        this.mActivityInfo = info.activityInfo;
+        mResolveInfo = info;
+        mActivityInfo = info.activityInfo;
         mComponentName = new ComponentName(mActivityInfo.packageName, mActivityInfo.name);
         mPm = context.getPackageManager();
     }
@@ -49,31 +51,30 @@
     }
 
     public CharSequence getLabel() {
-        return mActivityInfo.loadLabel(mPm);
+        return mResolveInfo.loadLabel(mPm);
     }
 
     public Drawable getIcon(int density) {
-        Drawable d = null;
-        if (mActivityInfo.getIconResource() != 0) {
-            Resources resources;
+        int iconRes = mResolveInfo.getIconResource();
+        Resources resources = null;
+        Drawable icon = null;
+        // Get the preferred density icon from the app's resources
+        if (density != 0 && iconRes != 0) {
             try {
-                resources = mPm.getResourcesForApplication(mActivityInfo.packageName);
-            } catch (PackageManager.NameNotFoundException e) {
-                resources = null;
-            }
-            if (resources != null) {
-                try {
-                    d = resources.getDrawableForDensity(mActivityInfo.getIconResource(), density);
-                } catch (Resources.NotFoundException e) {
-                    // Return default icon below.
-                }
+                resources = mPm.getResourcesForApplication(mActivityInfo.applicationInfo);
+                icon = resources.getDrawableForDensity(iconRes, density);
+            } catch (NameNotFoundException | Resources.NotFoundException exc) {
             }
         }
-        if (d == null) {
-            Resources resources = Resources.getSystem();
-            d = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+        // Get the default density icon
+        if (icon == null) {
+            icon = mResolveInfo.loadIcon(mPm);
         }
-        return d;
+        if (icon == null) {
+            resources = Resources.getSystem();
+            icon = resources.getDrawableForDensity(android.R.mipmap.sym_def_app_icon, density);
+        }
+        return icon;
     }
 
     public ApplicationInfo getApplicationInfo() {
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
index b52cf1d..4448758 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
@@ -16,12 +16,14 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
+import android.os.Build;
 
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat {
     private LauncherActivityInfo mLauncherActivityInfo;
 
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
index e47b9a5..ac3d252 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -31,6 +31,8 @@
 import android.os.Bundle;
 import android.provider.Settings;
 
+import com.android.launcher3.util.Thunk;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -139,11 +141,11 @@
         mContext.registerReceiver(mPackageMonitor, filter);
     }
 
-    private synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
+    @Thunk synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
         return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
     }
 
-    private class PackageMonitor extends BroadcastReceiver {
+    @Thunk class PackageMonitor extends BroadcastReceiver {
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             final UserHandleCompat user = UserHandleCompat.myUserHandle();
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index e0d28b5..fbf91b5 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -32,6 +33,7 @@
 import java.util.List;
 import java.util.Map;
 
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LauncherAppsCompatVL extends LauncherAppsCompat {
 
     private LauncherApps mLauncherApps;
@@ -49,7 +51,7 @@
         List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName,
                 user.getUser());
         if (list.size() == 0) {
-            return Collections.EMPTY_LIST;
+            return Collections.emptyList();
         }
         ArrayList<LauncherActivityInfoCompat> compatList =
                 new ArrayList<LauncherActivityInfoCompat>(list.size());
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 0eb8754..c499083 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -20,7 +20,7 @@
 
 import com.android.launcher3.Utilities;
 
-import java.util.HashSet;
+import java.util.HashMap;
 
 public abstract class PackageInstallerCompat {
 
@@ -37,25 +37,20 @@
                 if (Utilities.isLmpOrAbove()) {
                     sInstance = new PackageInstallerCompatVL(context);
                 } else {
-                    sInstance = new PackageInstallerCompatV16(context) { };
+                    sInstance = new PackageInstallerCompatV16();
                 }
             }
             return sInstance;
         }
     }
 
-    public abstract HashSet<String> updateAndGetActiveSessionCache();
-
-    public abstract void onPause();
-
-    public abstract void onResume();
-
-    public abstract void onFinishBind();
+    /**
+     * @return a map of active installs to their progress
+     */
+    public abstract HashMap<String, Integer> updateAndGetActiveSessionCache();
 
     public abstract void onStop();
 
-    public abstract void recordPackageUpdate(String packageName, int state, int progress);
-
     public static final class PackageInstallInfo {
         public final String packageName;
 
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
index 1910d22..654e349 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatV16.java
@@ -16,160 +16,17 @@
 
 package com.android.launcher3.compat;
 
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.launcher3.LauncherAppState;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONStringer;
-import org.json.JSONTokener;
-
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
 
 public class PackageInstallerCompatV16 extends PackageInstallerCompat {
 
-    private static final String TAG = "PackageInstallerCompatV16";
-    private static final boolean DEBUG = false;
-
-    private static final String KEY_PROGRESS = "progress";
-    private static final String KEY_STATE = "state";
-
-    private static final String PREFS =
-            "com.android.launcher3.compat.PackageInstallerCompatV16.queue";
-
-    protected final SharedPreferences mPrefs;
-
-    boolean mUseQueue;
-    boolean mFinishedBind;
-    boolean mReplayPending;
-
-    PackageInstallerCompatV16(Context context) {
-        mPrefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
-    }
-
-    @Override
-    public void onPause() {
-        mUseQueue = true;
-        if (DEBUG) Log.d(TAG, "updates paused");
-    }
-
-    @Override
-    public void onResume() {
-        mUseQueue = false;
-        if (mFinishedBind) {
-            replayUpdates();
-        }
-    }
-
-    @Override
-    public void onFinishBind() {
-        mFinishedBind = true;
-        if (!mUseQueue) {
-            replayUpdates();
-        }
-    }
+    PackageInstallerCompatV16() { }
 
     @Override
     public void onStop() { }
 
-    private void replayUpdates() {
-        if (DEBUG) Log.d(TAG, "updates resumed");
-        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app == null) {
-            mReplayPending = true; // try again later
-            if (DEBUG) Log.d(TAG, "app is null, delaying send");
-            return;
-        }
-        mReplayPending = false;
-        ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
-        for (String packageName: mPrefs.getAll().keySet()) {
-            final String json = mPrefs.getString(packageName, null);
-            if (!TextUtils.isEmpty(json)) {
-                updates.add(infoFromJson(packageName, json));
-            }
-        }
-        if (!updates.isEmpty()) {
-            sendUpdate(app, updates);
-        }
-    }
-
-    /**
-     * This should be called by the implementations to register a package update.
-     */
     @Override
-    public synchronized void recordPackageUpdate(String packageName, int state, int progress) {
-        SharedPreferences.Editor editor = mPrefs.edit();
-        PackageInstallInfo installInfo = new PackageInstallInfo(packageName);
-        installInfo.progress = progress;
-        installInfo.state = state;
-        if (state == STATUS_INSTALLED) {
-            // no longer necessary to track this package
-            editor.remove(packageName);
-            if (DEBUG) Log.d(TAG, "no longer tracking " + packageName);
-        } else {
-            editor.putString(packageName, infoToJson(installInfo));
-            if (DEBUG)
-                Log.d(TAG, "saved state: " + infoToJson(installInfo)
-                        + " for package: " + packageName);
-
-        }
-        editor.commit();
-
-        if (!mUseQueue) {
-            if (mReplayPending) {
-                replayUpdates();
-            } else if (state != STATUS_INSTALLED) {
-                LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-                ArrayList<PackageInstallInfo> update = new ArrayList<PackageInstallInfo>();
-                update.add(installInfo);
-                sendUpdate(app, update);
-            }
-        }
-    }
-
-    private void sendUpdate(LauncherAppState app, ArrayList<PackageInstallInfo> updates) {
-        if (app == null) {
-            mReplayPending = true; // try again later
-            if (DEBUG) Log.d(TAG, "app is null, delaying send");
-        } else {
-            app.setPackageState(updates);
-        }
-    }
-
-    private static PackageInstallInfo infoFromJson(String packageName, String json) {
-        PackageInstallInfo info = new PackageInstallInfo(packageName);
-        try {
-            JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
-            info.state = object.getInt(KEY_STATE);
-            info.progress = object.getInt(KEY_PROGRESS);
-        } catch (JSONException e) {
-            Log.e(TAG, "failed to deserialize app state update", e);
-        }
-        return info;
-    }
-
-    private static String infoToJson(PackageInstallInfo info) {
-        String value = null;
-        try {
-            JSONStringer json = new JSONStringer()
-                    .object()
-                    .key(KEY_STATE).value(info.state)
-                    .key(KEY_PROGRESS).value(info.progress)
-                    .endObject();
-            value = json.toString();
-        } catch (JSONException e) {
-            Log.e(TAG, "failed to serialize app state update", e);
-        }
-        return value;
-    }
-
-    @Override
-    public HashSet<String> updateAndGetActiveSessionCache() {
-        return new HashSet<String>();
+    public HashMap<String, Integer> updateAndGetActiveSessionCache() {
+        return new HashMap<>();
     }
 }
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 601f04c..3ad5101 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -16,73 +16,55 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionCallback;
 import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.Build;
 import android.os.Handler;
-import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.launcher3.IconCache;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.util.Thunk;
 
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.HashMap;
 
-public class PackageInstallerCompatVL extends PackageInstallerCompat implements Runnable {
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class PackageInstallerCompatVL extends PackageInstallerCompat {
 
-    private static final String TAG = "PackageInstallerCompatVL";
-    private static final boolean DEBUG = false;
+    @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
 
-    // All updates to these sets must happen on the {@link #mWorker} thread.
-    private final SparseArray<SessionInfo> mPendingReplays = new SparseArray<SessionInfo>();
-    private final HashSet<String> mPendingBadgeUpdates = new HashSet<String>();
-
-    private final PackageInstaller mInstaller;
+    @Thunk final PackageInstaller mInstaller;
     private final IconCache mCache;
     private final Handler mWorker;
 
-    private boolean mResumed;
-    private boolean mBound;
-
     PackageInstallerCompatVL(Context context) {
         mInstaller = context.getPackageManager().getPackageInstaller();
         LauncherAppState.setApplicationContext(context.getApplicationContext());
         mCache = LauncherAppState.getInstance().getIconCache();
-        mWorker = new Handler();
-
-        mResumed = false;
-        mBound = false;
+        mWorker = new Handler(LauncherModel.getWorkerLooper());
 
         mInstaller.registerSessionCallback(mCallback, mWorker);
-
-        // On start, send updates for all active sessions
-        mWorker.post(new Runnable() {
-
-            @Override
-            public void run() {
-                for (SessionInfo info : mInstaller.getAllSessions()) {
-                    mPendingReplays.append(info.getSessionId(), info);
-                }
-            }
-        });
     }
 
     @Override
-    public HashSet<String> updateAndGetActiveSessionCache() {
-        HashSet<String> activePackages = new HashSet<String>();
+    public HashMap<String, Integer> updateAndGetActiveSessionCache() {
+        HashMap<String, Integer> activePackages = new HashMap<>();
         UserHandleCompat user = UserHandleCompat.myUserHandle();
         for (SessionInfo info : mInstaller.getAllSessions()) {
             addSessionInfoToCahce(info, user);
             if (info.getAppPackageName() != null) {
-                activePackages.add(info.getAppPackageName());
+                activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
+                mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
             }
         }
         return activePackages;
     }
 
-    private void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
+    @Thunk void addSessionInfoToCahce(SessionInfo info, UserHandleCompat user) {
         String packageName = info.getAppPackageName();
         if (packageName != null) {
             mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(),
@@ -95,74 +77,10 @@
         mInstaller.unregisterSessionCallback(mCallback);
     }
 
-    @Override
-    public void onFinishBind() {
-        mBound = true;
-        mWorker.post(this);
-    }
-
-    @Override
-    public void onPause() {
-        mResumed = false;
-    }
-
-    @Override
-    public void onResume() {
-        mResumed = true;
-        mWorker.post(this);
-    }
-
-    @Override
-    public void recordPackageUpdate(String packageName, int state, int progress) {
-        // No op
-    }
-
-    @Override
-    public void run() {
-        // Called on mWorker thread.
-        replayUpdates(null);
-    }
-
-    private void replayUpdates(PackageInstallInfo newInfo) {
-        if (DEBUG) Log.d(TAG, "updates resumed");
-        if (!mResumed || !mBound) {
-            // Not yet ready
-            return;
-        }
-        if ((mPendingReplays.size() == 0) && (newInfo == null)) {
-            // Nothing to update
-            return;
-        }
-
+    @Thunk void sendUpdate(PackageInstallInfo info) {
         LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app == null) {
-            // Try again later
-            if (DEBUG) Log.d(TAG, "app is null, delaying send");
-            return;
-        }
-
-        ArrayList<PackageInstallInfo> updates = new ArrayList<PackageInstallInfo>();
-        if ((newInfo != null) && (newInfo.state != STATUS_INSTALLED)) {
-            updates.add(newInfo);
-        }
-        for (int i = mPendingReplays.size() - 1; i >= 0; i--) {
-            SessionInfo session = mPendingReplays.valueAt(i);
-            if (session.getAppPackageName() != null) {
-                updates.add(new PackageInstallInfo(session.getAppPackageName(),
-                        STATUS_INSTALLING,
-                        (int) (session.getProgress() * 100)));
-            }
-        }
-        mPendingReplays.clear();
-        if (!updates.isEmpty()) {
-            app.setPackageState(updates);
-        }
-
-        if (!mPendingBadgeUpdates.isEmpty()) {
-            for (String pkg : mPendingBadgeUpdates) {
-                app.updatePackageBadge(pkg);
-            }
-            mPendingBadgeUpdates.clear();
+        if (app != null) {
+            app.getModel().setPackageState(info);
         }
     }
 
@@ -170,19 +88,18 @@
 
         @Override
         public void onCreated(int sessionId) {
-            pushSessionBadgeToLauncher(sessionId);
+            pushSessionDisplayToLauncher(sessionId);
         }
 
         @Override
         public void onFinished(int sessionId, boolean success) {
-            mPendingReplays.remove(sessionId);
-            SessionInfo session = mInstaller.getSessionInfo(sessionId);
-            if ((session != null) && (session.getAppPackageName() != null)) {
-                mPendingBadgeUpdates.remove(session.getAppPackageName());
-                // Replay all updates with a one time update for this installed package. No
-                // need to store this record for future updates, as the app list will get
-                // refreshed on resume.
-                replayUpdates(new PackageInstallInfo(session.getAppPackageName(),
+            // For a finished session, we can't get the session info. So use the
+            // packageName from our local cache.
+            String packageName = mActiveSessions.get(sessionId);
+            mActiveSessions.remove(sessionId);
+
+            if (packageName != null) {
+                sendUpdate(new PackageInstallInfo(packageName,
                         success ? STATUS_INSTALLED : STATUS_FAILED, 0));
             }
         }
@@ -191,8 +108,9 @@
         public void onProgressChanged(int sessionId, float progress) {
             SessionInfo session = mInstaller.getSessionInfo(sessionId);
             if (session != null) {
-                mPendingReplays.put(sessionId, session);
-                replayUpdates(null);
+                sendUpdate(new PackageInstallInfo(session.getAppPackageName(),
+                        STATUS_INSTALLING,
+                        (int) (session.getProgress() * 100)));
             }
         }
 
@@ -201,18 +119,18 @@
 
         @Override
         public void onBadgingChanged(int sessionId) {
-            pushSessionBadgeToLauncher(sessionId);
+            pushSessionDisplayToLauncher(sessionId);
         }
 
-        private void pushSessionBadgeToLauncher(int sessionId) {
+        private void pushSessionDisplayToLauncher(int sessionId) {
             SessionInfo session = mInstaller.getSessionInfo(sessionId);
             if (session != null) {
                 addSessionInfoToCahce(session, UserHandleCompat.myUserHandle());
-                if (session.getAppPackageName() != null) {
-                    mPendingBadgeUpdates.add(session.getAppPackageName());
+                LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+
+                if (app != null) {
+                    app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
                 }
-                mPendingReplays.put(sessionId, session);
-                replayUpdates(null);
             }
         }
     };
diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java
index 2ae6731..ab4b721 100644
--- a/src/com/android/launcher3/compat/UserHandleCompat.java
+++ b/src/com/android/launcher3/compat/UserHandleCompat.java
@@ -16,10 +16,10 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.Intent;
 import android.os.Build;
 import android.os.UserHandle;
-
 import com.android.launcher3.Utilities;
 
 public class UserHandleCompat {
@@ -32,6 +32,7 @@
     private UserHandleCompat() {
     }
 
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
     public static UserHandleCompat myUserHandle() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
             return new UserHandleCompat(android.os.Process.myUserHandle());
@@ -40,7 +41,7 @@
         }
     }
 
-    static UserHandleCompat fromUser(UserHandle user) {
+    public static UserHandleCompat fromUser(UserHandle user) {
         if (user == null) {
             return null;
         } else {
diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java
index 1374b4e..a79d946 100644
--- a/src/com/android/launcher3/compat/UserManagerCompat.java
+++ b/src/com/android/launcher3/compat/UserManagerCompat.java
@@ -43,4 +43,5 @@
     public abstract UserHandleCompat getUserForSerialNumber(long serialNumber);
     public abstract Drawable getBadgedDrawableForUser(Drawable unbadged, UserHandleCompat user);
     public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user);
+    public abstract long getUserCreationTime(UserHandleCompat user);
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java
index 32f972e..ffe698c 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatV16.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java
@@ -48,4 +48,9 @@
     public CharSequence getBadgedLabelForUser(CharSequence label, UserHandleCompat user) {
         return label;
     }
+
+    @Override
+    public long getUserCreationTime(UserHandleCompat user) {
+        return 0;
+    }
 }
diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java
index 055359a..c42c00c 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatV17.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatV17.java
@@ -16,14 +16,12 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
+import android.os.Build;
 import android.os.UserManager;
 
-import java.util.ArrayList;
-import java.util.List;
-
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
 public class UserManagerCompatV17 extends UserManagerCompatV16 {
     protected UserManager mUserManager;
 
diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java
index 19eeabd..dd7a726 100644
--- a/src/com/android/launcher3/compat/UserManagerCompatVL.java
+++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java
@@ -17,29 +17,36 @@
 
 package com.android.launcher3.compat;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.UserHandle;
-import android.os.UserManager;
-
+import com.android.launcher3.LauncherAppState;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class UserManagerCompatVL extends UserManagerCompatV17 {
+    private static final String USER_CREATION_TIME_KEY = "user_creation_time_";
+
     private final PackageManager mPm;
+    private final Context mContext;
 
     UserManagerCompatVL(Context context) {
         super(context);
         mPm = context.getPackageManager();
+        mContext = context;
     }
 
     @Override
     public List<UserHandleCompat> getUserProfiles() {
         List<UserHandle> users = mUserManager.getUserProfiles();
         if (users == null) {
-            return Collections.EMPTY_LIST;
+            return Collections.emptyList();
         }
         ArrayList<UserHandleCompat> compatUsers = new ArrayList<UserHandleCompat>(
                 users.size());
@@ -61,5 +68,17 @@
         }
         return mPm.getUserBadgedLabel(label, user.getUser());
     }
+
+    @Override
+    public long getUserCreationTime(UserHandleCompat user) {
+        // TODO: Use system API once available.
+        SharedPreferences prefs = mContext.getSharedPreferences(
+                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
+        String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user);
+        if (!prefs.contains(key)) {
+            prefs.edit().putLong(key, System.currentTimeMillis()).apply();
+        }
+        return prefs.getLong(key, 0);
+    }
 }
 
diff --git a/src/com/android/launcher3/config/ProviderConfig.java b/src/com/android/launcher3/config/ProviderConfig.java
index db25076..e8930d0 100644
--- a/src/com/android/launcher3/config/ProviderConfig.java
+++ b/src/com/android/launcher3/config/ProviderConfig.java
@@ -18,5 +18,5 @@
 
 public class ProviderConfig {
 
-    public static final String AUTHORITY = "com.android.launcher3.settings";
+    public static final String AUTHORITY = "com.android.launcher3.settings".intern();
 }
diff --git a/src/com/android/launcher3/model/AbstractUserComparator.java b/src/com/android/launcher3/model/AbstractUserComparator.java
new file mode 100644
index 0000000..cf47ce6
--- /dev/null
+++ b/src/com/android/launcher3/model/AbstractUserComparator.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.Context;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * A comparator to arrange items based on user profiles.
+ */
+public abstract class AbstractUserComparator<T extends ItemInfo> implements Comparator<T> {
+
+    private HashMap<UserHandleCompat, Long> mUserSerialCache = new HashMap<>();
+    private final UserManagerCompat mUserManager;
+    private final UserHandleCompat mMyUser;
+
+    public AbstractUserComparator(Context context) {
+        mUserManager = UserManagerCompat.getInstance(context);
+        mMyUser = UserHandleCompat.myUserHandle();
+    }
+
+    @Override
+    public int compare(T lhs, T rhs) {
+        if (mMyUser.equals(lhs.user)) {
+            return -1;
+        } else {
+            Long aUserSerial = getAndCacheUserSerial(lhs.user);
+            Long bUserSerial = getAndCacheUserSerial(rhs.user);
+            return aUserSerial.compareTo(bUserSerial);
+        }
+    }
+
+    /**
+     * Returns the user serial for this user, using a cached serial if possible.
+     */
+    private Long getAndCacheUserSerial(UserHandleCompat user) {
+        Long userSerial = mUserSerialCache.get(user);
+        if (userSerial == null) {
+            userSerial = mUserManager.getSerialNumberForUser(user);
+            mUserSerialCache.put(user, userSerial);
+        }
+        return userSerial;
+    }
+
+    public void clearUserCache() {
+        mUserSerialCache.clear();
+    }
+}
diff --git a/src/com/android/launcher3/model/AppNameComparator.java b/src/com/android/launcher3/model/AppNameComparator.java
new file mode 100644
index 0000000..c4b74d4
--- /dev/null
+++ b/src/com/android/launcher3/model/AppNameComparator.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.Context;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.util.Thunk;
+
+import java.text.Collator;
+import java.util.Comparator;
+
+/**
+ * Class to manage access to an app name comparator.
+ * <p>
+ * Used to sort application name in all apps view and widget tray view.
+ */
+public class AppNameComparator {
+    private final Collator mCollator;
+    private final AbstractUserComparator<ItemInfo> mAppInfoComparator;
+    private final Comparator<String> mSectionNameComparator;
+
+    public AppNameComparator(Context context) {
+        mCollator = Collator.getInstance();
+        mAppInfoComparator = new AbstractUserComparator<ItemInfo>(context) {
+
+            @Override
+            public final int compare(ItemInfo a, ItemInfo b) {
+                // Order by the title in the current locale
+                int result = compareTitles(a.title.toString(), b.title.toString());
+                if (result == 0 && a instanceof AppInfo && b instanceof AppInfo) {
+                    AppInfo aAppInfo = (AppInfo) a;
+                    AppInfo bAppInfo = (AppInfo) b;
+                    // If two apps have the same title, then order by the component name
+                    result = aAppInfo.componentName.compareTo(bAppInfo.componentName);
+                    if (result == 0) {
+                        // If the two apps are the same component, then prioritize by the order that
+                        // the app user was created (prioritizing the main user's apps)
+                        return super.compare(a, b);
+                    }
+                }
+                return result;
+            }
+        };
+        mSectionNameComparator = new Comparator<String>() {
+            @Override
+            public int compare(String o1, String o2) {
+                return compareTitles(o1, o2);
+            }
+        };
+    }
+
+    /**
+     * Returns a locale-aware comparator that will alphabetically order a list of applications.
+     */
+    public Comparator<ItemInfo> getAppInfoComparator() {
+        // Clear the user serial cache so that we get serials as needed in the comparator
+        mAppInfoComparator.clearUserCache();
+        return mAppInfoComparator;
+    }
+
+    /**
+     * Returns a locale-aware comparator that will alphabetically order a list of section names.
+     */
+    public Comparator<String> getSectionNameComparator() {
+        return mSectionNameComparator;
+    }
+
+    /**
+     * Compares two titles with the same return value semantics as Comparator.
+     */
+    @Thunk int compareTitles(String titleA, String titleB) {
+        // Ensure that we de-prioritize any titles that don't start with a linguistic letter or digit
+        boolean aStartsWithLetter = (titleA.length() > 0) &&
+                Character.isLetterOrDigit(titleA.codePointAt(0));
+        boolean bStartsWithLetter = (titleB.length() > 0) &&
+                Character.isLetterOrDigit(titleB.codePointAt(0));
+        if (aStartsWithLetter && !bStartsWithLetter) {
+            return -1;
+        } else if (!aStartsWithLetter && bStartsWithLetter) {
+            return 1;
+        }
+
+        // Order by the title in the current locale
+        return mCollator.compare(titleA, titleB);
+    }
+}
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
new file mode 100644
index 0000000..30f228c
--- /dev/null
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import android.graphics.Bitmap;
+
+import com.android.launcher3.ItemInfo;
+
+import java.util.Arrays;
+
+/**
+ * Represents a {@link Package} in the widget tray section.
+ */
+public class PackageItemInfo extends ItemInfo {
+
+    /**
+     * A bitmap version of the application icon.
+     */
+    public Bitmap iconBitmap;
+
+    /**
+     * Indicates whether we're using a low res icon.
+     */
+    public boolean usingLowResIcon;
+
+    /**
+     * Package name of the {@link ItemInfo}.
+     */
+    public String packageName;
+
+    /**
+     * Character that is used as a section name for the {@link ItemInfo#title}.
+     * (e.g., "G" will be stored if title is "Google")
+     */
+    public String titleSectionName;
+
+    int flags = 0;
+
+    PackageItemInfo(String packageName) {
+        this.packageName = packageName;
+    }
+
+    @Override
+    public String toString() {
+        return "PackageItemInfo(title=" + title + " id=" + this.id
+                + " type=" + this.itemType + " container=" + this.container
+                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
+                + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
+                + " user=" + user + ")";
+    }
+}
diff --git a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
new file mode 100644
index 0000000..61e8952
--- /dev/null
+++ b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java
@@ -0,0 +1,68 @@
+package com.android.launcher3.model;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.text.Collator;
+import java.util.Comparator;
+import java.util.HashMap;
+
+public class WidgetsAndShortcutNameComparator implements Comparator<Object> {
+    private final AppWidgetManagerCompat mManager;
+    private final PackageManager mPackageManager;
+    private final HashMap<Object, String> mLabelCache;
+    private final Collator mCollator;
+    private final UserHandleCompat mMainHandle;
+
+    public WidgetsAndShortcutNameComparator(Context context) {
+        mManager = AppWidgetManagerCompat.getInstance(context);
+        mPackageManager = context.getPackageManager();
+        mLabelCache = new HashMap<Object, String>();
+        mCollator = Collator.getInstance();
+        mMainHandle = UserHandleCompat.myUserHandle();
+    }
+
+    @Override
+    public final int compare(Object a, Object b) {
+        String labelA, labelB;
+        if (mLabelCache.containsKey(a)) {
+            labelA = mLabelCache.get(a);
+        } else {
+            labelA = (a instanceof LauncherAppWidgetProviderInfo)
+                    ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a))
+                    : Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager));
+            mLabelCache.put(a, labelA);
+        }
+        if (mLabelCache.containsKey(b)) {
+            labelB = mLabelCache.get(b);
+        } else {
+            labelB = (b instanceof LauncherAppWidgetProviderInfo)
+                    ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b))
+                    : Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager));
+            mLabelCache.put(b, labelB);
+        }
+
+        // Currently, there is no work profile shortcuts, hence only considering the widget cases.
+
+        boolean aWorkProfile = (a instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) a));
+        boolean bWorkProfile = (b instanceof LauncherAppWidgetProviderInfo) &&
+                !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) b));
+
+        // Independent of how the labels compare, if only one of the two widget info belongs to
+        // work profile, put that one in the back.
+        if (aWorkProfile && !bWorkProfile) {
+            return 1;
+        }
+        if (!aWorkProfile && bWorkProfile) {
+            return -1;
+        }
+        return mCollator.compare(labelA, labelB);
+    }
+};
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
new file mode 100644
index 0000000..185dfca
--- /dev/null
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -0,0 +1,170 @@
+
+package com.android.launcher3.model;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.util.Log;
+
+import com.android.launcher3.AppFilter;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AlphabeticIndexCompat;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Widgets data model that is used by the adapters of the widget views and controllers.
+ *
+ * <p> The widgets and shortcuts are organized using package name as its index.
+ */
+public class WidgetsModel {
+
+    private static final String TAG = "WidgetsModel";
+    private static final boolean DEBUG = false;
+
+    /* List of packages that is tracked by this model. */
+    private ArrayList<PackageItemInfo> mPackageItemInfos = new ArrayList<>();
+
+    /* Map of widgets and shortcuts that are tracked per package. */
+    private HashMap<PackageItemInfo, ArrayList<Object>> mWidgetsList = new HashMap<>();
+
+    private ArrayList<Object> mRawList;
+
+    private final AppWidgetManagerCompat mAppWidgetMgr;
+    private final Comparator mWidgetAndShortcutNameComparator;
+    private final Comparator mAppNameComparator;
+    private final IconCache mIconCache;
+    private final AppFilter mAppFilter;
+    private AlphabeticIndexCompat mIndexer;
+
+    public WidgetsModel(Context context,  IconCache iconCache, AppFilter appFilter) {
+        mAppWidgetMgr = AppWidgetManagerCompat.getInstance(context);
+        mWidgetAndShortcutNameComparator = new WidgetsAndShortcutNameComparator(context);
+        mAppNameComparator = (new AppNameComparator(context)).getAppInfoComparator();
+        mIconCache = iconCache;
+        mAppFilter = appFilter;
+        mIndexer = new AlphabeticIndexCompat(context);
+    }
+
+    private WidgetsModel(WidgetsModel model) {
+        mAppWidgetMgr = model.mAppWidgetMgr;
+        mPackageItemInfos = (ArrayList<PackageItemInfo>) model.mPackageItemInfos.clone();
+        mWidgetsList = (HashMap<PackageItemInfo, ArrayList<Object>>) model.mWidgetsList.clone();
+        mRawList = (ArrayList<Object>) model.mRawList.clone();
+        mWidgetAndShortcutNameComparator = model.mWidgetAndShortcutNameComparator;
+        mAppNameComparator = model.mAppNameComparator;
+        mIconCache = model.mIconCache;
+        mAppFilter = model.mAppFilter;
+    }
+
+    // Access methods that may be deleted if the private fields are made package-private.
+    public int getPackageSize() {
+        if (mPackageItemInfos == null) {
+            return 0;
+        }
+        return mPackageItemInfos.size();
+    }
+
+    // Access methods that may be deleted if the private fields are made package-private.
+    public PackageItemInfo getPackageItemInfo(int pos) {
+        if (pos >= mPackageItemInfos.size() || pos < 0) {
+            return null;
+        }
+        return mPackageItemInfos.get(pos);
+    }
+
+    public List<Object> getSortedWidgets(int pos) {
+        return mWidgetsList.get(mPackageItemInfos.get(pos));
+    }
+
+    public ArrayList<Object> getRawList() {
+        return mRawList;
+    }
+
+    public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) {
+        Utilities.assertWorkerThread();
+        mRawList = rawWidgetsShortcuts;
+        if (DEBUG) {
+            Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
+        }
+
+        // Temporary list for {@link PackageItemInfos} to avoid having to go through
+        // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
+        HashMap<String, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+
+        // clear the lists.
+        mWidgetsList.clear();
+        mPackageItemInfos.clear();
+
+        // add and update.
+        for (Object o: rawWidgetsShortcuts) {
+            String packageName = "";
+            UserHandleCompat userHandle = null;
+            ComponentName componentName = null;
+            if (o instanceof LauncherAppWidgetProviderInfo) {
+                LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o;
+                componentName = widgetInfo.provider;
+                packageName = widgetInfo.provider.getPackageName();
+                userHandle = mAppWidgetMgr.getUser(widgetInfo);
+            } else if (o instanceof ResolveInfo) {
+                ResolveInfo resolveInfo = (ResolveInfo) o;
+                componentName = new ComponentName(resolveInfo.activityInfo.packageName,
+                        resolveInfo.activityInfo.name);
+                packageName = resolveInfo.activityInfo.packageName;
+                userHandle = UserHandleCompat.myUserHandle();
+            }
+
+            if (componentName == null || userHandle == null) {
+                Log.e(TAG, String.format("Widget cannot be set for %s.", o.getClass().toString()));
+                continue;
+            }
+            if (mAppFilter != null && !mAppFilter.shouldShowApp(componentName)) {
+                if (DEBUG) {
+                    Log.d(TAG, String.format("%s is filtered and not added to the widget tray.",
+                        packageName));
+                }
+                continue;
+            }
+
+            PackageItemInfo pInfo = tmpPackageItemInfos.get(packageName);
+            ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(pInfo);
+            if (widgetsShortcutsList != null) {
+                widgetsShortcutsList.add(o);
+            } else {
+                widgetsShortcutsList = new ArrayList<Object>();
+                widgetsShortcutsList.add(o);
+                pInfo = new PackageItemInfo(packageName);
+                mIconCache.getTitleAndIconForApp(packageName, userHandle,
+                        true /* userLowResIcon */, pInfo);
+                pInfo.titleSectionName = mIndexer.computeSectionName(pInfo.title);
+                mWidgetsList.put(pInfo, widgetsShortcutsList);
+                tmpPackageItemInfos.put(packageName,  pInfo);
+                mPackageItemInfos.add(pInfo);
+            }
+        }
+
+        // sort.
+        Collections.sort(mPackageItemInfos, mAppNameComparator);
+        for (PackageItemInfo p: mPackageItemInfos) {
+            Collections.sort(mWidgetsList.get(p), mWidgetAndShortcutNameComparator);
+        }
+    }
+
+    /**
+     * Create a snapshot of the widgets model.
+     * <p>
+     * Usage case: view binding without being modified from package updates.
+     */
+    @Override
+    public WidgetsModel clone(){
+        return new WidgetsModel(this);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
similarity index 89%
rename from src/com/android/launcher3/LauncherExtension.java
rename to src/com/android/launcher3/testing/LauncherExtension.java
index b264042..34492e4 100644
--- a/src/com/android/launcher3/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -1,7 +1,6 @@
-package com.android.launcher3;
+package com.android.launcher3.testing;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.ComponentName;
@@ -12,9 +11,19 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.InsettableFrameLayout;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.LauncherCallbacks;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsSearchBarController;
+import com.android.launcher3.util.ComponentKey;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class represents a very trivial LauncherExtension. It primarily serves as a simple
@@ -82,6 +91,11 @@
         }
 
         @Override
+        public void onRequestPermissionsResult(int requestCode, String[] permissions,
+                int[] grantResults) {
+        }
+
+        @Override
         public void onWindowFocusChanged(boolean hasFocus) {
         }
 
@@ -108,6 +122,10 @@
         }
 
         @Override
+        public void onTrimMemory(int level) {
+        }
+
+        @Override
         public void onLauncherProviderChange() {
         }
 
@@ -242,6 +260,16 @@
         }
 
         @Override
+        public AllAppsSearchBarController getAllAppsSearchBarController() {
+            return null;
+        }
+
+        @Override
+        public List<ComponentKey> getPredictedApps() {
+            return new ArrayList<>();
+        }
+
+        @Override
         public boolean isLauncherPreinstalled() {
             return false;
         }
@@ -261,6 +289,11 @@
             return mLauncherOverlay;
         }
 
+        @Override
+        public void setLauncherSearchCallback(Object callbacks) {
+            // Do nothing
+        }
+
         class LauncherExtensionOverlay implements LauncherOverlay {
             LauncherOverlayCallbacks mLauncherOverlayCallbacks;
             ViewGroup mOverlayView;
diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java
new file mode 100644
index 0000000..6a7df43
--- /dev/null
+++ b/src/com/android/launcher3/util/ComponentKey.java
@@ -0,0 +1,81 @@
+package com.android.launcher3.util;
+
+/**
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.content.ComponentName;
+import android.content.Context;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+import java.util.Arrays;
+
+public class ComponentKey {
+
+    public final ComponentName componentName;
+    public final UserHandleCompat user;
+
+    private final int mHashCode;
+
+    public ComponentKey(ComponentName componentName, UserHandleCompat user) {
+        assert (componentName != null);
+        assert (user != null);
+        this.componentName = componentName;
+        this.user = user;
+        mHashCode = Arrays.hashCode(new Object[] {componentName, user});
+
+    }
+
+    /**
+     * 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 = UserHandleCompat.myUserHandle();
+        }
+        mHashCode = Arrays.hashCode(new Object[] {componentName, user});
+    }
+
+    /**
+     * Encodes a component key as a string of the form [flattenedComponentString#userId].
+     */
+    public String flattenToString(Context context) {
+        return componentName.flattenToString() + "#" +
+                UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+    }
+
+    @Override
+    public int hashCode() {
+        return mHashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        ComponentKey other = (ComponentKey) o;
+        return other.componentName.equals(componentName) && other.user.equals(user);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/CursorIconInfo.java b/src/com/android/launcher3/util/CursorIconInfo.java
new file mode 100644
index 0000000..cdf9e3c
--- /dev/null
+++ b/src/com/android/launcher3/util/CursorIconInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.content.Context;
+import android.content.Intent.ShortcutIconResource;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+
+/**
+ * Utility class to load icon from a cursor.
+ */
+public class CursorIconInfo {
+    public final int iconTypeIndex;
+    public final int iconPackageIndex;
+    public final int iconResourceIndex;
+    public final int iconIndex;
+
+    public CursorIconInfo(Cursor c) {
+        iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
+        iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
+        iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
+        iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
+    }
+
+    public Bitmap loadIcon(Cursor c, ShortcutInfo info, Context context) {
+        Bitmap icon = null;
+        int iconType = c.getInt(iconTypeIndex);
+        switch (iconType) {
+        case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
+            String packageName = c.getString(iconPackageIndex);
+            String resourceName = c.getString(iconResourceIndex);
+            if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
+                info.iconResource = new ShortcutIconResource();
+                info.iconResource.packageName = packageName;
+                info.iconResource.resourceName = resourceName;
+                icon = Utilities.createIconBitmap(packageName, resourceName, context);
+            }
+            if (icon == null) {
+                // Failed to load from resource, try loading from DB.
+                icon = Utilities.createIconBitmap(c, iconIndex, context);
+            }
+            break;
+        case LauncherSettings.Favorites.ICON_TYPE_BITMAP:
+            icon = Utilities.createIconBitmap(c, iconIndex, context);
+            info.customIcon = icon != null;
+            break;
+        }
+        return icon;
+    }
+}
diff --git a/src/com/android/launcher3/util/FlingAnimation.java b/src/com/android/launcher3/util/FlingAnimation.java
new file mode 100644
index 0000000..55c5d7d
--- /dev/null
+++ b/src/com/android/launcher3/util/FlingAnimation.java
@@ -0,0 +1,104 @@
+package com.android.launcher3.util;
+
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.DragView;
+import com.android.launcher3.DropTarget.DragObject;
+
+public class FlingAnimation implements AnimatorUpdateListener {
+
+    /**
+     * Maximum acceleration in one dimension (pixels per milliseconds)
+     */
+    private static final float MAX_ACCELERATION = 0.5f;
+    private static final int DRAG_END_DELAY = 300;
+
+    protected final DragObject mDragObject;
+    protected final Rect mIconRect;
+    protected final DragLayer mDragLayer;
+    protected final Rect mFrom;
+    protected final int mDuration;
+    protected final float mUX, mUY;
+    protected final float mAnimationTimeFraction;
+    protected final TimeInterpolator mAlphaInterpolator = new DecelerateInterpolator(0.75f);
+
+    protected float mAX, mAY;
+
+    /**
+     * @param vel initial fling velocity in pixels per second.
+     */
+    public FlingAnimation(DragObject d, PointF vel, Rect iconRect, DragLayer dragLayer) {
+        mDragObject = d;
+        mUX = vel.x / 1000;
+        mUY = vel.y / 1000;
+        mIconRect = iconRect;
+
+        mDragLayer = dragLayer;
+        mFrom = new Rect();
+        dragLayer.getViewRectRelativeToSelf(d.dragView, mFrom);
+
+        float scale = d.dragView.getScaleX();
+        float xOffset = ((scale - 1f) * d.dragView.getMeasuredWidth()) / 2f;
+        float yOffset = ((scale - 1f) * d.dragView.getMeasuredHeight()) / 2f;
+        mFrom.left += xOffset;
+        mFrom.right -= xOffset;
+        mFrom.top += yOffset;
+        mFrom.bottom -= yOffset;
+
+        mDuration = initDuration();
+        mAnimationTimeFraction = ((float) mDuration) / (mDuration + DRAG_END_DELAY);
+    }
+
+    /**
+     * The fling animation is based on the following system
+     *   - Apply a constant force in the y direction to causing the fling to decelerate.
+     *   - The animation runs for the time taken by the object to go out of the screen.
+     *   - Calculate a constant acceleration in x direction such that the object reaches
+     *     {@link #mIconRect} in the given time.
+     */
+    protected int initDuration() {
+        float sY = -mFrom.bottom;
+
+        float d = mUY * mUY + 2 * sY * MAX_ACCELERATION;
+        if (d >= 0) {
+            // sY can be reached under the MAX_ACCELERATION. Use MAX_ACCELERATION for y direction.
+            mAY = MAX_ACCELERATION;
+        } else {
+            // sY is not reachable, decrease the acceleration so that sY is almost reached.
+            d = 0;
+            mAY = mUY * mUY / (2 * -sY);
+        }
+        double t = (-mUY - Math.sqrt(d)) / mAY;
+
+        float sX = -mFrom.exactCenterX() + mIconRect.exactCenterX();
+
+        // Find horizontal acceleration such that: u*t + a*t*t/2 = s
+        mAX = (float) ((sX - t * mUX) * 2 / (t * t));
+        return (int) Math.round(t);
+    }
+
+    public final int getDuration() {
+        return mDuration + DRAG_END_DELAY;
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        float t = animation.getAnimatedFraction();
+        if (t > mAnimationTimeFraction) {
+            t = 1;
+        } else {
+            t = t / mAnimationTimeFraction;
+        }
+        final DragView dragView = (DragView) mDragLayer.getAnimatedView();
+        final float time = t * mDuration;
+        dragView.setTranslationX(time * mUX + mFrom.left + mAX * time * time / 2);
+        dragView.setTranslationY(time * mUY + mFrom.top + mAY * time * time / 2);
+        dragView.setAlpha(1f - mAlphaInterpolator.getInterpolation(t));
+    }
+}
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
new file mode 100644
index 0000000..696eabe
--- /dev/null
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.ShortcutAndWidgetContainer;
+
+import java.util.Arrays;
+
+/**
+ * Calculates the next item that a {@link KeyEvent} should change the focus to.
+ *<p>
+ * Note, this utility class calculates everything regards to icon index and its (x,y) coordinates.
+ * Currently supports:
+ * <ul>
+ *  <li> full matrix of cells that are 1x1
+ *  <li> sparse matrix of cells that are 1x1
+ *     [ 1][  ][ 2][  ]
+ *     [  ][  ][ 3][  ]
+ *     [  ][ 4][  ][  ]
+ *     [  ][ 5][ 6][ 7]
+ * </ul>
+ * *<p>
+ * For testing, one can use a BT keyboard, or use following adb command.
+ * ex. $ adb shell input keyevent 20 // KEYCODE_DPAD_LEFT
+ */
+public class FocusLogic {
+
+    private static final String TAG = "FocusLogic";
+    private static final boolean DEBUG = false;
+
+    // Item and page index related constant used by {@link #handleKeyEvent}.
+    public static final int NOOP = -1;
+
+    public static final int PREVIOUS_PAGE_RIGHT_COLUMN  = -2;
+    public static final int PREVIOUS_PAGE_FIRST_ITEM    = -3;
+    public static final int PREVIOUS_PAGE_LAST_ITEM     = -4;
+    public static final int PREVIOUS_PAGE_LEFT_COLUMN   = -5;
+
+    public static final int CURRENT_PAGE_FIRST_ITEM     = -6;
+    public static final int CURRENT_PAGE_LAST_ITEM      = -7;
+
+    public static final int NEXT_PAGE_FIRST_ITEM        = -8;
+    public static final int NEXT_PAGE_LEFT_COLUMN       = -9;
+    public static final int NEXT_PAGE_RIGHT_COLUMN      = -10;
+
+    // Matrix related constant.
+    public static final int EMPTY = -1;
+    public static final int PIVOT = 100;
+
+    /**
+     * Returns true only if this utility class handles the key code.
+     */
+    public static boolean shouldConsume(int keyCode) {
+        return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
+                keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
+                keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END ||
+                keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN ||
+                keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL);
+    }
+
+    public static int handleKeyEvent(int keyCode, int cntX, int cntY,
+            int [][] map, int iconIdx, int pageIndex, int pageCount, boolean isRtl) {
+
+        if (DEBUG) {
+            Log.v(TAG, String.format(
+                    "handleKeyEvent START: cntX=%d, cntY=%d, iconIdx=%d, pageIdx=%d, pageCnt=%d",
+                    cntX, cntY, iconIdx, pageIndex, pageCount));
+        }
+
+        int newIndex = NOOP;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, -1 /*increment*/);
+                if (isRtl && newIndex == NOOP && pageIndex > 0) {
+                    newIndex = PREVIOUS_PAGE_RIGHT_COLUMN;
+                } else if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
+                    newIndex = NEXT_PAGE_RIGHT_COLUMN;
+                }
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                newIndex = handleDpadHorizontal(iconIdx, cntX, cntY, map, 1 /*increment*/);
+                if (isRtl && newIndex == NOOP && pageIndex < pageCount - 1) {
+                    newIndex = NEXT_PAGE_LEFT_COLUMN;
+                } else if (isRtl && newIndex == NOOP && pageIndex > 0) {
+                    newIndex = PREVIOUS_PAGE_LEFT_COLUMN;
+                }
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, 1  /*increment*/);
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                newIndex = handleDpadVertical(iconIdx, cntX, cntY, map, -1  /*increment*/);
+                break;
+            case KeyEvent.KEYCODE_MOVE_HOME:
+                newIndex = handleMoveHome();
+                break;
+            case KeyEvent.KEYCODE_MOVE_END:
+                newIndex = handleMoveEnd();
+                break;
+            case KeyEvent.KEYCODE_PAGE_DOWN:
+                newIndex = handlePageDown(pageIndex, pageCount);
+                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
+                newIndex = handlePageUp(pageIndex);
+                break;
+            default:
+                break;
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, String.format("handleKeyEvent FINISH: index [%d -> %s]",
+                    iconIdx, getStringIndex(newIndex)));
+        }
+        return newIndex;
+    }
+
+    /**
+     * Returns a matrix of size (m x n) that has been initialized with {@link #EMPTY}.
+     *
+     * @param m                 number of columns in the matrix
+     * @param n                 number of rows in the matrix
+     */
+    // TODO: get rid of dynamic matrix creation.
+    private static int[][] createFullMatrix(int m, int n) {
+        int[][] matrix = new int [m][n];
+
+        for (int i=0; i < m;i++) {
+            Arrays.fill(matrix[i], EMPTY);
+        }
+        return matrix;
+    }
+
+    /**
+     * Returns a matrix of size same as the {@link CellLayout} dimension that is initialized with the
+     * index of the child view.
+     */
+    // TODO: get rid of the dynamic matrix creation
+    public static int[][] createSparseMatrix(CellLayout layout) {
+        ShortcutAndWidgetContainer parent = layout.getShortcutsAndWidgets();
+        final int m = layout.getCountX();
+        final int n = layout.getCountY();
+        final boolean invert = parent.invertLayoutHorizontally();
+
+        int[][] matrix = createFullMatrix(m, n);
+
+        // Iterate thru the children.
+        for (int i = 0; i < parent.getChildCount(); i++ ) {
+            int cx = ((CellLayout.LayoutParams) parent.getChildAt(i).getLayoutParams()).cellX;
+            int cy = ((CellLayout.LayoutParams) parent.getChildAt(i).getLayoutParams()).cellY;
+            matrix[invert ? (m - cx - 1) : cx][cy] = i;
+        }
+        if (DEBUG) {
+            printMatrix(matrix);
+        }
+        return matrix;
+    }
+
+    /**
+     * Creates a sparse matrix that merges the icon and hotseat view group using the cell layout.
+     * The size of the returning matrix is [icon column count x (icon + hotseat row count)]
+     * in portrait orientation. In landscape, [(icon + hotseat) column count x (icon row count)]
+     */
+    // TODO: get rid of the dynamic matrix creation
+    public static int[][] createSparseMatrix(CellLayout iconLayout, CellLayout hotseatLayout,
+            boolean isHorizontal, int allappsiconRank, boolean includeAllappsicon) {
+
+        ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
+        ViewGroup hotseatParent = hotseatLayout.getShortcutsAndWidgets();
+
+        int m, n;
+        if (isHorizontal) {
+            m = iconLayout.getCountX();
+            n = iconLayout.getCountY() + hotseatLayout.getCountY();
+        } else {
+            m = iconLayout.getCountX() + hotseatLayout.getCountX();
+            n = iconLayout.getCountY();
+        }
+        int[][] matrix = createFullMatrix(m, n);
+
+        // Iterate thru the children of the top parent.
+        for (int i = 0; i < iconParent.getChildCount(); i++) {
+            int cx = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellX;
+            int cy = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellY;
+            matrix[cx][cy] = i;
+        }
+
+        // Iterate thru the children of the bottom parent
+        // The hotseat view group contains one more item than iconLayout column count.
+        // If {@param allappsiconRank} not negative, then the last icon in the hotseat
+        // is truncated. If it is negative, then all apps icon index is not inserted.
+        for(int i = hotseatParent.getChildCount() - 1; i >= (includeAllappsicon ? 0 : 1); i--) {
+            int delta = 0;
+            if (isHorizontal) {
+                int cx = ((CellLayout.LayoutParams)
+                        hotseatParent.getChildAt(i).getLayoutParams()).cellX;
+                if ((includeAllappsicon && cx >= allappsiconRank) ||
+                        (!includeAllappsicon && cx > allappsiconRank)) {
+                        delta = -1;
+                }
+                matrix[cx + delta][iconLayout.getCountY()] = iconParent.getChildCount() + i;
+            } else {
+                int cy = ((CellLayout.LayoutParams)
+                        hotseatParent.getChildAt(i).getLayoutParams()).cellY;
+                if ((includeAllappsicon && cy >= allappsiconRank) ||
+                        (!includeAllappsicon && cy > allappsiconRank)) {
+                        delta = -1;
+                }
+                matrix[iconLayout.getCountX()][cy + delta] = iconParent.getChildCount() + i;
+            }
+        }
+        if (DEBUG) {
+            printMatrix(matrix);
+        }
+        return matrix;
+    }
+
+    /**
+     * Creates a sparse matrix that merges the icon of previous/next page and last column of
+     * current page. When left key is triggered on the leftmost column, sparse matrix is created
+     * that combines previous page matrix and an extra column on the right. Likewise, when right
+     * key is triggered on the rightmost column, sparse matrix is created that combines this column
+     * on the 0th column and the next page matrix.
+     *
+     * @param pivotX    x coordinate of the focused item in the current page
+     * @param pivotY    y coordinate of the focused item in the current page
+     */
+    // TODO: get rid of the dynamic matrix creation
+    public static int[][] createSparseMatrix(CellLayout iconLayout, int pivotX, int pivotY) {
+
+        ViewGroup iconParent = iconLayout.getShortcutsAndWidgets();
+
+        int[][] matrix = createFullMatrix(iconLayout.getCountX() + 1, iconLayout.getCountY());
+
+        // Iterate thru the children of the top parent.
+        for (int i = 0; i < iconParent.getChildCount(); i++) {
+            int cx = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellX;
+            int cy = ((CellLayout.LayoutParams) iconParent.getChildAt(i).getLayoutParams()).cellY;
+            if (pivotX < 0) {
+                matrix[cx - pivotX][cy] = i;
+            } else {
+                matrix[cx][cy] = i;
+            }
+        }
+
+        if (pivotX < 0) {
+            matrix[0][pivotY] = PIVOT;
+        } else {
+            matrix[pivotX][pivotY] = PIVOT;
+        }
+        if (DEBUG) {
+            printMatrix(matrix);
+        }
+        return matrix;
+    }
+
+    //
+    // key event handling methods.
+    //
+
+    /**
+     * Calculates icon that has is closest to the horizontal axis in reference to the cur icon.
+     *
+     * Example of the check order for KEYCODE_DPAD_RIGHT:
+     * [  ][  ][13][14][15]
+     * [  ][ 6][ 8][10][12]
+     * [ X][ 1][ 2][ 3][ 4]
+     * [  ][ 5][ 7][ 9][11]
+     */
+    // TODO: add unit tests to verify all permutation.
+    private static int handleDpadHorizontal(int iconIdx, int cntX, int cntY,
+            int[][] matrix, int increment) {
+        if(matrix == null) {
+            throw new IllegalStateException("Dpad navigation requires a matrix.");
+        }
+        int newIconIndex = NOOP;
+
+        int xPos = -1;
+        int yPos = -1;
+        // Figure out the location of the icon.
+        for (int i = 0; i < cntX; i++) {
+            for (int j = 0; j < cntY; j++) {
+                if (matrix[i][j] == iconIdx) {
+                    xPos = i;
+                    yPos = j;
+                }
+            }
+        }
+        if (DEBUG) {
+            Log.v(TAG, String.format("\thandleDpadHorizontal: \t[x, y]=[%d, %d] iconIndex=%d",
+                    xPos, yPos, iconIdx));
+        }
+
+        // Rule1: check first in the horizontal direction
+        for (int i = xPos + increment; 0 <= i && i < cntX; i = i + increment) {
+            if ((newIconIndex = inspectMatrix(i, yPos, cntX, cntY, matrix)) != NOOP) {
+                return newIconIndex;
+            }
+        }
+
+        // Rule2: check (x1-n, yPos + increment),   (x1-n, yPos - increment)
+        //              (x2-n, yPos + 2*increment), (x2-n, yPos - 2*increment)
+        int nextYPos1;
+        int nextYPos2;
+        int i = -1;
+        for (int coeff = 1; coeff < cntY; coeff++) {
+            nextYPos1 = yPos + coeff * increment;
+            nextYPos2 = yPos - coeff * increment;
+            for (i = xPos + increment * coeff; 0 <= i && i < cntX; i = i + increment) {
+                if ((newIconIndex = inspectMatrix(i, nextYPos1, cntX, cntY, matrix)) != NOOP) {
+                    return newIconIndex;
+                }
+                if ((newIconIndex = inspectMatrix(i, nextYPos2, cntX, cntY, matrix)) != NOOP) {
+                    return newIconIndex;
+                }
+            }
+        }
+        return newIconIndex;
+    }
+
+    /**
+     * Calculates icon that is closest to the vertical axis in reference to the current icon.
+     *
+     * Example of the check order for KEYCODE_DPAD_DOWN:
+     * [  ][  ][  ][ X][  ][  ][  ]
+     * [  ][  ][ 5][ 1][ 4][  ][  ]
+     * [  ][10][ 7][ 2][ 6][ 9][  ]
+     * [14][12][ 9][ 3][ 8][11][13]
+     */
+    // TODO: add unit tests to verify all permutation.
+    private static int handleDpadVertical(int iconIndex, int cntX, int cntY,
+            int [][] matrix, int increment) {
+        int newIconIndex = NOOP;
+        if(matrix == null) {
+            throw new IllegalStateException("Dpad navigation requires a matrix.");
+        }
+
+        int xPos = -1;
+        int yPos = -1;
+        // Figure out the location of the icon.
+        for (int i = 0; i< cntX; i++) {
+            for (int j = 0; j < cntY; j++) {
+                if (matrix[i][j] == iconIndex) {
+                    xPos = i;
+                    yPos = j;
+                }
+            }
+        }
+
+        if (DEBUG) {
+            Log.v(TAG, String.format("\thandleDpadVertical: \t[x, y]=[%d, %d] iconIndex=%d",
+                    xPos, yPos, iconIndex));
+        }
+
+        // Rule1: check first in the dpad direction
+        for (int j = yPos + increment; 0 <= j && j <cntY && 0 <= j; j = j + increment) {
+            if ((newIconIndex = inspectMatrix(xPos, j, cntX, cntY, matrix)) != NOOP) {
+                return newIconIndex;
+            }
+        }
+
+        // Rule2: check (xPos + increment, y_(1-n)),   (xPos - increment, y_(1-n))
+        //              (xPos + 2*increment, y_(2-n))), (xPos - 2*increment, y_(2-n))
+        int nextXPos1;
+        int nextXPos2;
+        int j = -1;
+        for (int coeff = 1; coeff < cntX; coeff++) {
+            nextXPos1 = xPos + coeff * increment;
+            nextXPos2 = xPos - coeff * increment;
+            for (j = yPos + increment * coeff; 0 <= j && j < cntY; j = j + increment) {
+                if ((newIconIndex = inspectMatrix(nextXPos1, j, cntX, cntY, matrix)) != NOOP) {
+                    return newIconIndex;
+                }
+                if ((newIconIndex = inspectMatrix(nextXPos2, j, cntX, cntY, matrix)) != NOOP) {
+                    return newIconIndex;
+                }
+            }
+        }
+        return newIconIndex;
+    }
+
+    private static int handleMoveHome() {
+        return CURRENT_PAGE_FIRST_ITEM;
+    }
+
+    private static int handleMoveEnd() {
+        return CURRENT_PAGE_LAST_ITEM;
+    }
+
+    private static int handlePageDown(int pageIndex, int pageCount) {
+        if (pageIndex < pageCount -1) {
+            return NEXT_PAGE_FIRST_ITEM;
+        }
+        return CURRENT_PAGE_LAST_ITEM;
+    }
+
+    private static int handlePageUp(int pageIndex) {
+        if (pageIndex > 0) {
+            return PREVIOUS_PAGE_FIRST_ITEM;
+        } else {
+            return CURRENT_PAGE_FIRST_ITEM;
+        }
+    }
+
+    //
+    // Helper methods.
+    //
+
+    private static boolean isValid(int xPos, int yPos, int countX, int countY) {
+        return (0 <= xPos && xPos < countX && 0 <= yPos && yPos < countY);
+    }
+
+    private static int inspectMatrix(int x, int y, int cntX, int cntY, int[][] matrix) {
+        int newIconIndex = NOOP;
+        if (isValid(x, y, cntX, cntY)) {
+            if (matrix[x][y] != -1) {
+                newIconIndex = matrix[x][y];
+                if (DEBUG) {
+                    Log.v(TAG, String.format("\t\tinspect: \t[x, y]=[%d, %d] %d",
+                            x, y, matrix[x][y]));
+                }
+                return newIconIndex;
+            }
+        }
+        return newIconIndex;
+    }
+
+    /**
+     * Only used for debugging.
+     */
+    private static String getStringIndex(int index) {
+        switch(index) {
+            case NOOP: return "NOOP";
+            case PREVIOUS_PAGE_FIRST_ITEM:  return "PREVIOUS_PAGE_FIRST";
+            case PREVIOUS_PAGE_LAST_ITEM:   return "PREVIOUS_PAGE_LAST";
+            case PREVIOUS_PAGE_RIGHT_COLUMN:return "PREVIOUS_PAGE_RIGHT_COLUMN";
+            case CURRENT_PAGE_FIRST_ITEM:   return "CURRENT_PAGE_FIRST";
+            case CURRENT_PAGE_LAST_ITEM:    return "CURRENT_PAGE_LAST";
+            case NEXT_PAGE_FIRST_ITEM:      return "NEXT_PAGE_FIRST";
+            case NEXT_PAGE_LEFT_COLUMN:     return "NEXT_PAGE_LEFT_COLUMN";
+            default:
+                return Integer.toString(index);
+        }
+    }
+
+    /**
+     * Only used for debugging.
+     */
+    private static void printMatrix(int[][] matrix) {
+        Log.v(TAG, "\tprintMap:");
+        int m = matrix.length;
+        int n = matrix[0].length;
+
+        for (int j=0; j < n; j++) {
+            String colY = "\t\t";
+            for (int i=0; i < m; i++) {
+                colY +=  String.format("%3d",matrix[i][j]);
+            }
+            Log.v(TAG, colY);
+        }
+    }
+
+    /**
+     * @param edgeColumn the column of the new icon. either {@link #NEXT_PAGE_LEFT_COLUMN} or
+     * {@link #NEXT_PAGE_RIGHT_COLUMN}
+     * @return the view adjacent to {@param oldView} in the {@param nextPage}.
+     */
+    public static View getAdjacentChildInNextPage(
+            ShortcutAndWidgetContainer nextPage, View oldView, int edgeColumn) {
+        final int newRow = ((CellLayout.LayoutParams) oldView.getLayoutParams()).cellY;
+
+        int column = (edgeColumn == NEXT_PAGE_LEFT_COLUMN) ^ nextPage.invertLayoutHorizontally()
+                ? 0 : (((CellLayout) nextPage.getParent()).getCountX() - 1);
+
+        for (; column >= 0; column--) {
+            for (int row = newRow; row >= 0; row--) {
+                View newView = nextPage.getChildAt(column, row);
+                if (newView != null) {
+                    return newView;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/launcher3/util/LauncherEdgeEffect.java b/src/com/android/launcher3/util/LauncherEdgeEffect.java
new file mode 100644
index 0000000..3e3b255
--- /dev/null
+++ b/src/com/android/launcher3/util/LauncherEdgeEffect.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+/**
+ * This class differs from the framework {@link android.widget.EdgeEffect}:
+ *   1) It does not use PorterDuffXfermode
+ *   2) The width to radius factor is smaller (0.5 instead of 0.75)
+ */
+public class LauncherEdgeEffect {
+
+    // Time it will take the effect to fully recede in ms
+    private static final int RECEDE_TIME = 600;
+
+    // Time it will take before a pulled glow begins receding in ms
+    private static final int PULL_TIME = 167;
+
+    // Time it will take in ms for a pulled glow to decay to partial strength before release
+    private static final int PULL_DECAY_TIME = 2000;
+
+    private static final float MAX_ALPHA = 0.5f;
+
+    private static final float MAX_GLOW_SCALE = 2.f;
+
+    private static final float PULL_GLOW_BEGIN = 0.f;
+
+    // Minimum velocity that will be absorbed
+    private static final int MIN_VELOCITY = 100;
+    // Maximum velocity, clamps at this value
+    private static final int MAX_VELOCITY = 10000;
+
+    private static final float EPSILON = 0.001f;
+
+    private static final double ANGLE = Math.PI / 6;
+    private static final float SIN = (float) Math.sin(ANGLE);
+    private static final float COS = (float) Math.cos(ANGLE);
+
+    private float mGlowAlpha;
+    private float mGlowScaleY;
+
+    private float mGlowAlphaStart;
+    private float mGlowAlphaFinish;
+    private float mGlowScaleYStart;
+    private float mGlowScaleYFinish;
+
+    private long mStartTime;
+    private float mDuration;
+
+    private final Interpolator mInterpolator;
+
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_PULL = 1;
+    private static final int STATE_ABSORB = 2;
+    private static final int STATE_RECEDE = 3;
+    private static final int STATE_PULL_DECAY = 4;
+
+    private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
+
+    private static final int VELOCITY_GLOW_FACTOR = 6;
+
+    private int mState = STATE_IDLE;
+
+    private float mPullDistance;
+
+    private final Rect mBounds = new Rect();
+    private final Paint mPaint = new Paint();
+    private float mRadius;
+    private float mBaseGlowScale;
+    private float mDisplacement = 0.5f;
+    private float mTargetDisplacement = 0.5f;
+
+    /**
+     * Construct a new EdgeEffect with a theme appropriate for the provided context.
+     */
+    public LauncherEdgeEffect() {
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.FILL);
+        mInterpolator = new DecelerateInterpolator();
+    }
+
+    /**
+     * Set the size of this edge effect in pixels.
+     *
+     * @param width Effect width in pixels
+     * @param height Effect height in pixels
+     */
+    public void setSize(int width, int height) {
+        final float r = width * 0.5f / SIN;
+        final float y = COS * r;
+        final float h = r - y;
+        final float or = height * 0.75f / SIN;
+        final float oy = COS * or;
+        final float oh = or - oy;
+
+        mRadius = r;
+        mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
+
+        mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
+    }
+
+    /**
+     * Reports if this EdgeEffect's animation is finished. If this method returns false
+     * after a call to {@link #draw(Canvas)} the host widget should schedule another
+     * drawing pass to continue the animation.
+     *
+     * @return true if animation is finished, false if drawing should continue on the next frame.
+     */
+    public boolean isFinished() {
+        return mState == STATE_IDLE;
+    }
+
+    /**
+     * Immediately finish the current animation.
+     * After this call {@link #isFinished()} will return true.
+     */
+    public void finish() {
+        mState = STATE_IDLE;
+    }
+
+    /**
+     * A view should call this when content is pulled away from an edge by the user.
+     * This will update the state of the current visual effect and its associated animation.
+     * The host view should always {@link android.view.View#invalidate()} after this
+     * and draw the results accordingly.
+     *
+     * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
+     * of the pull point is known.</p>
+     *
+     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+     *                      1.f (full length of the view) or negative values to express change
+     *                      back toward the edge reached to initiate the effect.
+     */
+    public void onPull(float deltaDistance) {
+        onPull(deltaDistance, 0.5f);
+    }
+
+    /**
+     * A view should call this when content is pulled away from an edge by the user.
+     * This will update the state of the current visual effect and its associated animation.
+     * The host view should always {@link android.view.View#invalidate()} after this
+     * and draw the results accordingly.
+     *
+     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+     *                      1.f (full length of the view) or negative values to express change
+     *                      back toward the edge reached to initiate the effect.
+     * @param displacement The displacement from the starting side of the effect of the point
+     *                     initiating the pull. In the case of touch this is the finger position.
+     *                     Values may be from 0-1.
+     */
+    public void onPull(float deltaDistance, float displacement) {
+        final long now = AnimationUtils.currentAnimationTimeMillis();
+        mTargetDisplacement = displacement;
+        if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
+            return;
+        }
+        if (mState != STATE_PULL) {
+            mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
+        }
+        mState = STATE_PULL;
+
+        mStartTime = now;
+        mDuration = PULL_TIME;
+
+        mPullDistance += deltaDistance;
+
+        final float absdd = Math.abs(deltaDistance);
+        mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
+                mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
+
+        if (mPullDistance == 0) {
+            mGlowScaleY = mGlowScaleYStart = 0;
+        } else {
+            final float scale = (float) (Math.max(0, 1 - 1 /
+                    Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
+
+            mGlowScaleY = mGlowScaleYStart = scale;
+        }
+
+        mGlowAlphaFinish = mGlowAlpha;
+        mGlowScaleYFinish = mGlowScaleY;
+    }
+
+    /**
+     * Call when the object is released after being pulled.
+     * This will begin the "decay" phase of the effect. After calling this method
+     * the host view should {@link android.view.View#invalidate()} and thereby
+     * draw the results accordingly.
+     */
+    public void onRelease() {
+        mPullDistance = 0;
+
+        if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {
+            return;
+        }
+
+        mState = STATE_RECEDE;
+        mGlowAlphaStart = mGlowAlpha;
+        mGlowScaleYStart = mGlowScaleY;
+
+        mGlowAlphaFinish = 0.f;
+        mGlowScaleYFinish = 0.f;
+
+        mStartTime = AnimationUtils.currentAnimationTimeMillis();
+        mDuration = RECEDE_TIME;
+    }
+
+    /**
+     * Call when the effect absorbs an impact at the given velocity.
+     * Used when a fling reaches the scroll boundary.
+     *
+     * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
+     * the method <code>getCurrVelocity</code> will provide a reasonable approximation
+     * to use here.</p>
+     *
+     * @param velocity Velocity at impact in pixels per second.
+     */
+    public void onAbsorb(int velocity) {
+        mState = STATE_ABSORB;
+        velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
+
+        mStartTime = AnimationUtils.currentAnimationTimeMillis();
+        mDuration = 0.15f + (velocity * 0.02f);
+
+        // The glow depends more on the velocity, and therefore starts out
+        // nearly invisible.
+        mGlowAlphaStart = 0.3f;
+        mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
+
+
+        // Growth for the size of the glow should be quadratic to properly
+        // respond
+        // to a user's scrolling speed. The faster the scrolling speed, the more
+        // intense the effect should be for both the size and the saturation.
+        mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
+        // Alpha should change for the glow as well as size.
+        mGlowAlphaFinish = Math.max(
+                mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
+        mTargetDisplacement = 0.5f;
+    }
+
+    /**
+     * Set the color of this edge effect in argb.
+     *
+     * @param color Color in argb
+     */
+    public void setColor(int color) {
+        mPaint.setColor(color);
+    }
+
+    /**
+     * Return the color of this edge effect in argb.
+     * @return The color of this edge effect in argb
+     */
+    public int getColor() {
+        return mPaint.getColor();
+    }
+
+    /**
+     * Draw into the provided canvas. Assumes that the canvas has been rotated
+     * accordingly and the size has been set. The effect will be drawn the full
+     * width of X=0 to X=width, beginning from Y=0 and extending to some factor <
+     * 1.f of height.
+     *
+     * @param canvas Canvas to draw into
+     * @return true if drawing should continue beyond this frame to continue the
+     *         animation
+     */
+    public boolean draw(Canvas canvas) {
+        update();
+
+        final float centerX = mBounds.centerX();
+        final float centerY = mBounds.height() - mRadius;
+
+        canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0);
+
+        final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
+        float translateX = mBounds.width() * displacement / 2;
+        mPaint.setAlpha((int) (0xff * mGlowAlpha));
+        canvas.drawCircle(centerX + translateX, centerY, mRadius, mPaint);
+
+        boolean oneLastFrame = false;
+        if (mState == STATE_RECEDE && mGlowScaleY == 0) {
+            mState = STATE_IDLE;
+            oneLastFrame = true;
+        }
+
+        return mState != STATE_IDLE || oneLastFrame;
+    }
+
+    /**
+     * Return the maximum height that the edge effect will be drawn at given the original
+     * {@link #setSize(int, int) input size}.
+     * @return The maximum height of the edge effect
+     */
+    public int getMaxHeight() {
+        return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
+    }
+
+    private void update() {
+        final long time = AnimationUtils.currentAnimationTimeMillis();
+        final float t = Math.min((time - mStartTime) / mDuration, 1.f);
+
+        final float interp = mInterpolator.getInterpolation(t);
+
+        mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
+        mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
+        mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
+
+        if (t >= 1.f - EPSILON) {
+            switch (mState) {
+                case STATE_ABSORB:
+                    mState = STATE_RECEDE;
+                    mStartTime = AnimationUtils.currentAnimationTimeMillis();
+                    mDuration = RECEDE_TIME;
+
+                    mGlowAlphaStart = mGlowAlpha;
+                    mGlowScaleYStart = mGlowScaleY;
+
+                    // After absorb, the glow should fade to nothing.
+                    mGlowAlphaFinish = 0.f;
+                    mGlowScaleYFinish = 0.f;
+                    break;
+                case STATE_PULL:
+                    mState = STATE_PULL_DECAY;
+                    mStartTime = AnimationUtils.currentAnimationTimeMillis();
+                    mDuration = PULL_DECAY_TIME;
+
+                    mGlowAlphaStart = mGlowAlpha;
+                    mGlowScaleYStart = mGlowScaleY;
+
+                    // After pull, the glow should fade to nothing.
+                    mGlowAlphaFinish = 0.f;
+                    mGlowScaleYFinish = 0.f;
+                    break;
+                case STATE_PULL_DECAY:
+                    mState = STATE_RECEDE;
+                    break;
+                case STATE_RECEDE:
+                    mState = STATE_IDLE;
+                    break;
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/LongArrayMap.java
new file mode 100644
index 0000000..a337e85
--- /dev/null
+++ b/src/com/android/launcher3/util/LongArrayMap.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.util.LongSparseArray;
+
+import java.util.Iterator;
+
+/**
+ * Extension of {@link LongSparseArray} with some utility methods.
+ */
+public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
+
+    public boolean containsKey(long key) {
+        return indexOfKey(key) >= 0;
+    }
+
+    public boolean isEmpty() {
+        return size() <= 0;
+    }
+
+    @Override
+    public LongArrayMap<E> clone() {
+        return (LongArrayMap<E>) super.clone();
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return new ValueIterator();
+    }
+
+    @Thunk class ValueIterator implements Iterator<E> {
+
+        private int mNextIndex = 0;
+
+        @Override
+        public boolean hasNext() {
+            return mNextIndex < size();
+        }
+
+        @Override
+        public E next() {
+            return valueAt(mNextIndex ++);
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
new file mode 100644
index 0000000..b37f447
--- /dev/null
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.util.Log;
+
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.LauncherModel;
+import com.android.launcher3.MainThreadExecutor;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.LauncherActivityInfoCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Handles addition of app shortcuts for managed profiles.
+ * Methods of class should only be called on {@link LauncherModel#sWorkerThread}.
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class ManagedProfileHeuristic {
+
+    private static final String TAG = "ManagedProfileHeuristic";
+
+    /**
+     * Maintain a set of packages installed per user.
+     */
+    private static final String INSTALLED_PACKAGES_PREFIX = "installed_packages_for_user_";
+
+    private static final String USER_FOLDER_ID_PREFIX = "user_folder_";
+
+    /**
+     * Duration (in milliseconds) for which app shortcuts will be added to work folder.
+     */
+    private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000;
+
+    public static ManagedProfileHeuristic get(Context context, UserHandleCompat user) {
+        if (Utilities.isLmpOrAbove() && !UserHandleCompat.myUserHandle().equals(user)) {
+            return new ManagedProfileHeuristic(context, user);
+        }
+        return null;
+    }
+
+    private final Context mContext;
+    private final UserHandleCompat mUser;
+    private final LauncherModel mModel;
+
+    private final SharedPreferences mPrefs;
+    private final long mUserSerial;
+    private final long mUserCreationTime;
+    private final String mPackageSetKey;
+
+    private ArrayList<ShortcutInfo> mHomescreenApps;
+    private ArrayList<ShortcutInfo> mWorkFolderApps;
+
+    private ManagedProfileHeuristic(Context context, UserHandleCompat user) {
+        mContext = context;
+        mUser = user;
+        mModel = LauncherAppState.getInstance().getModel();
+
+        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
+        mUserSerial = userManager.getSerialNumberForUser(user);
+        mUserCreationTime = userManager.getUserCreationTime(user);
+        mPackageSetKey = INSTALLED_PACKAGES_PREFIX + mUserSerial;
+
+        mPrefs = mContext.getSharedPreferences(LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
+                Context.MODE_PRIVATE);
+    }
+
+    /**
+     * Checks the list of user apps and adds icons for newly installed apps on the homescreen or
+     * workfolder.
+     */
+    public void processUserApps(List<LauncherActivityInfoCompat> apps) {
+        mHomescreenApps = new ArrayList<>();
+        mWorkFolderApps = new ArrayList<>();
+
+        HashSet<String> packageSet = new HashSet<>();
+        final boolean userAppsExisted = getUserApps(packageSet);
+
+        boolean newPackageAdded = false;
+
+        for (LauncherActivityInfoCompat info : apps) {
+            String packageName = info.getComponentName().getPackageName();
+            if (!packageSet.contains(packageName)) {
+                packageSet.add(packageName);
+                newPackageAdded = true;
+
+                try {
+                    PackageInfo pkgInfo = mContext.getPackageManager()
+                            .getPackageInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+                    markForAddition(info, pkgInfo.firstInstallTime);
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Unknown package " + packageName, e);
+                }
+            }
+        }
+
+        if (newPackageAdded) {
+            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
+            // Do not add shortcuts on the homescreen for the first time. This prevents the launcher
+            // getting filled with the managed user apps, when it start with a fresh DB (or after
+            // a very long time).
+            finalizeAdditions(userAppsExisted);
+        }
+    }
+
+    private void markForAddition(LauncherActivityInfoCompat info, long installTime) {
+        ArrayList<ShortcutInfo> targetList =
+                (installTime <= mUserCreationTime + AUTO_ADD_TO_FOLDER_DURATION) ?
+                        mWorkFolderApps : mHomescreenApps;
+        targetList.add(ShortcutInfo.fromActivityInfo(info, mContext));
+    }
+
+    /**
+     * Adds and binds shortcuts marked to be added to the work folder.
+     */
+    private void finalizeWorkFolder() {
+        if (mWorkFolderApps.isEmpty()) {
+            return;
+        }
+        Collections.sort(mWorkFolderApps, new Comparator<ShortcutInfo>() {
+
+            @Override
+            public int compare(ShortcutInfo lhs, ShortcutInfo rhs) {
+                return Long.compare(lhs.firstInstallTime, rhs.firstInstallTime);
+            }
+        });
+
+        // Try to get a work folder.
+        String folderIdKey = USER_FOLDER_ID_PREFIX + mUserSerial;
+        if (mPrefs.contains(folderIdKey)) {
+            long folderId = mPrefs.getLong(folderIdKey, 0);
+            final FolderInfo workFolder = mModel.findFolderById(folderId);
+
+            if (workFolder == null || !workFolder.hasOption(FolderInfo.FLAG_WORK_FOLDER)) {
+                // Could not get a work folder. Add all the icons to homescreen.
+                mHomescreenApps.addAll(mWorkFolderApps);
+                return;
+            }
+            saveWorkFolderShortcuts(folderId, workFolder.contents.size());
+
+            final ArrayList<ShortcutInfo> shortcuts = mWorkFolderApps;
+            // FolderInfo could already be bound. We need to add shortcuts on the UI thread.
+            new MainThreadExecutor().execute(new Runnable() {
+
+                @Override
+                public void run() {
+                    for (ShortcutInfo info : shortcuts) {
+                        workFolder.add(info);
+                    }
+                }
+            });
+        } else {
+            // Create a new folder.
+            final FolderInfo workFolder = new FolderInfo();
+            workFolder.title = mContext.getText(R.string.work_folder_name);
+            workFolder.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null);
+
+            // Add all shortcuts before adding it to the UI, as an empty folder might get deleted.
+            for (ShortcutInfo info : mWorkFolderApps) {
+                workFolder.add(info);
+            }
+
+            // Add the item to home screen and DB. This also generates an item id synchronously.
+            ArrayList<ItemInfo> itemList = new ArrayList<ItemInfo>(1);
+            itemList.add(workFolder);
+            mModel.addAndBindAddedWorkspaceItems(mContext, itemList);
+            mPrefs.edit().putLong(USER_FOLDER_ID_PREFIX + mUserSerial, workFolder.id).apply();
+
+            saveWorkFolderShortcuts(workFolder.id, 0);
+        }
+    }
+
+    /**
+     * Add work folder shortcuts to the DB.
+     */
+    private void saveWorkFolderShortcuts(long workFolderId, int startingRank) {
+        for (ItemInfo info : mWorkFolderApps) {
+            info.rank = startingRank++;
+            LauncherModel.addItemToDatabase(mContext, info, workFolderId, 0, 0, 0);
+        }
+    }
+
+    /**
+     * Adds and binds all shortcuts marked for addition.
+     */
+    private void finalizeAdditions(boolean addHomeScreenShortcuts) {
+        finalizeWorkFolder();
+
+        if (addHomeScreenShortcuts && !mHomescreenApps.isEmpty()) {
+            mModel.addAndBindAddedWorkspaceItems(mContext, mHomescreenApps);
+        }
+    }
+
+    /**
+     * Updates the list of installed apps and adds any new icons on homescreen or work folder.
+     */
+    public void processPackageAdd(String[] packages) {
+        mHomescreenApps = new ArrayList<>();
+        mWorkFolderApps = new ArrayList<>();
+
+        HashSet<String> packageSet = new HashSet<>();
+        final boolean userAppsExisted = getUserApps(packageSet);
+
+        boolean newPackageAdded = false;
+        long installTime = System.currentTimeMillis();
+        LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
+
+        for (String packageName : packages) {
+            if (!packageSet.contains(packageName)) {
+                packageSet.add(packageName);
+                newPackageAdded = true;
+
+                List<LauncherActivityInfoCompat> activities =
+                        launcherApps.getActivityList(packageName, mUser);
+                if (!activities.isEmpty()) {
+                    markForAddition(activities.get(0), installTime);
+                }
+            }
+        }
+
+        if (newPackageAdded) {
+            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
+            finalizeAdditions(userAppsExisted);
+        }
+    }
+
+    /**
+     * Updates the list of installed packages for the user.
+     */
+    public void processPackageRemoved(String[] packages) {
+        HashSet<String> packageSet = new HashSet<String>();
+        getUserApps(packageSet);
+        boolean packageRemoved = false;
+
+        for (String packageName : packages) {
+            if (packageSet.remove(packageName)) {
+                packageRemoved = true;
+            }
+        }
+
+        if (packageRemoved) {
+            mPrefs.edit().putStringSet(mPackageSetKey, packageSet).apply();
+        }
+    }
+
+    /**
+     * Reads the list of user apps which have already been processed.
+     * @return false if the list didn't exist, true otherwise
+     */
+    private boolean getUserApps(HashSet<String> outExistingApps) {
+        Set<String> userApps = mPrefs.getStringSet(mPackageSetKey, null);
+        if (userApps == null) {
+            return false;
+        } else {
+            outExistingApps.addAll(userApps);
+            return true;
+        }
+    }
+
+    /**
+     * Verifies that entries corresponding to {@param users} exist and removes all invalid entries.
+     */
+    public static void processAllUsers(List<UserHandleCompat> users, Context context) {
+        if (!Utilities.isLmpOrAbove()) {
+            return;
+        }
+        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
+        HashSet<String> validKeys = new HashSet<String>();
+        for (UserHandleCompat user : users) {
+            addAllUserKeys(userManager.getSerialNumberForUser(user), validKeys);
+        }
+
+        SharedPreferences prefs = context.getSharedPreferences(
+                LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
+                Context.MODE_PRIVATE);
+        SharedPreferences.Editor editor = prefs.edit();
+        for (String key : prefs.getAll().keySet()) {
+            if (!validKeys.contains(key)) {
+                editor.remove(key);
+            }
+        }
+        editor.apply();
+    }
+
+    private static void addAllUserKeys(long userSerial, HashSet<String> keysOut) {
+        keysOut.add(INSTALLED_PACKAGES_PREFIX + userSerial);
+        keysOut.add(USER_FOLDER_ID_PREFIX + userSerial);
+    }
+
+    /**
+     * For each user, if a work folder has not been created, mark it such that the folder will
+     * never get created.
+     */
+    public static void markExistingUsersForNoFolderCreation(Context context) {
+        UserManagerCompat userManager = UserManagerCompat.getInstance(context);
+        UserHandleCompat myUser = UserHandleCompat.myUserHandle();
+
+        SharedPreferences prefs = null;
+        for (UserHandleCompat user : userManager.getUserProfiles()) {
+            if (myUser.equals(user)) {
+                continue;
+            }
+
+            if (prefs == null) {
+                prefs = context.getSharedPreferences(
+                        LauncherFiles.MANAGED_USER_PREFERENCES_KEY,
+                        Context.MODE_PRIVATE);
+            }
+            String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user);
+            if (!prefs.contains(folderIdKey)) {
+                prefs.edit().putLong(folderIdKey, ItemInfo.NO_ID).apply();
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/RevealOutlineProvider.java b/src/com/android/launcher3/util/RevealOutlineProvider.java
new file mode 100644
index 0000000..0db3984
--- /dev/null
+++ b/src/com/android/launcher3/util/RevealOutlineProvider.java
@@ -0,0 +1,49 @@
+package com.android.launcher3.util;
+
+import android.annotation.TargetApi;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class RevealOutlineProvider extends ViewOutlineProvider {
+
+    private int mCenterX;
+    private int mCenterY;
+    private float mRadius0;
+    private float mRadius1;
+    private int mCurrentRadius;
+
+    private final Rect mOval;
+
+    /**
+     * @param x reveal center x
+     * @param y reveal center y
+     * @param r0 initial radius
+     * @param r1 final radius
+     */
+    public RevealOutlineProvider(int x, int y, float r0, float r1) {
+        mCenterX = x;
+        mCenterY = y;
+        mRadius0 = r0;
+        mRadius1 = r1;
+
+        mOval = new Rect();
+    }
+
+    public void setProgress(float progress) {
+        mCurrentRadius = (int) ((1 - progress) * mRadius0 + progress * mRadius1);
+
+        mOval.left = mCenterX - mCurrentRadius;
+        mOval.top = mCenterY - mCurrentRadius;
+        mOval.right = mCenterX + mCurrentRadius;
+        mOval.bottom = mCenterY + mCurrentRadius;
+    }
+
+    @Override
+    public void getOutline(View v, Outline outline) {
+        outline.setRoundRect(mOval, mCurrentRadius);
+    }
+}
diff --git a/src/com/android/launcher3/util/Thunk.java b/src/com/android/launcher3/util/Thunk.java
new file mode 100644
index 0000000..de350b0
--- /dev/null
+++ b/src/com/android/launcher3/util/Thunk.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates that the given field or method has package visibility solely to prevent the creation
+ * of a synthetic method. In practice, you should treat this field/method as if it were private.
+ * <p>
+ *
+ * When a private method is called from an inner class, the Java compiler generates a simple
+ * package private shim method that the class generated from the inner class can call. This results
+ * in unnecessary bloat and runtime method call overhead. It also gets us closer to the dex method
+ * count limit.
+ * <p>
+ *
+ * If you'd like to see warnings for these synthetic methods in eclipse, turn on:
+ * Window > Preferences > Java > Compiler > Errors/Warnings > "Access to a non-accessible member
+ * of an enclosing type".
+ * <p>
+ *
+ */
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE})
+public @interface Thunk { }
\ No newline at end of file
diff --git a/src/com/android/launcher3/util/UiThreadCircularReveal.java b/src/com/android/launcher3/util/UiThreadCircularReveal.java
new file mode 100644
index 0000000..3ca3aee
--- /dev/null
+++ b/src/com/android/launcher3/util/UiThreadCircularReveal.java
@@ -0,0 +1,57 @@
+package com.android.launcher3.util;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import com.android.launcher3.Utilities;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class UiThreadCircularReveal {
+
+    public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1) {
+        return createCircularReveal(v, x, y, r0, r1, ViewOutlineProvider.BACKGROUND);
+    }
+
+    public static ValueAnimator createCircularReveal(View v, int x, int y, float r0, float r1,
+            final ViewOutlineProvider originalProvider) {
+        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+
+        final View revealView = v;
+        final RevealOutlineProvider outlineProvider = new RevealOutlineProvider(x, y, r0, r1);
+        final float elevation = v.getElevation();
+
+        va.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationStart(Animator animation) {
+                revealView.setOutlineProvider(outlineProvider);
+                revealView.setClipToOutline(true);
+                revealView.setTranslationZ(-elevation);
+            }
+
+            public void onAnimationEnd(Animator animation) {
+                revealView.setOutlineProvider(originalProvider);
+                revealView.setClipToOutline(false);
+                revealView.setTranslationZ(0);
+            }
+
+        });
+
+        va.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                float progress = arg0.getAnimatedFraction();
+                outlineProvider.setProgress(progress);
+                revealView.invalidateOutline();
+                if (!Utilities.isLmpMR1OrAbove()) {
+                    revealView.invalidate();
+                }
+            }
+        });
+        return va;
+    }
+}
diff --git a/src/com/android/launcher3/util/WallpaperUtils.java b/src/com/android/launcher3/util/WallpaperUtils.java
new file mode 100644
index 0000000..53b2acd
--- /dev/null
+++ b/src/com/android/launcher3/util/WallpaperUtils.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.annotation.TargetApi;
+import android.app.WallpaperManager;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.os.Build;
+import android.view.WindowManager;
+
+/**
+ * Utility methods for wallpaper management.
+ */
+public final class WallpaperUtils {
+
+    public static final String WALLPAPER_WIDTH_KEY = "wallpaper.width";
+    public static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height";
+    public static final float WALLPAPER_SCREENS_SPAN = 2f;
+
+    public static void suggestWallpaperDimension(Resources res,
+            final SharedPreferences sharedPrefs,
+            WindowManager windowManager,
+            final WallpaperManager wallpaperManager, boolean fallBackToDefaults) {
+        final Point defaultWallpaperSize = WallpaperUtils.getDefaultWallpaperSize(res, windowManager);
+        // If we have saved a wallpaper width/height, use that instead
+
+        int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, -1);
+        int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, -1);
+
+        if (savedWidth == -1 || savedHeight == -1) {
+            if (!fallBackToDefaults) {
+                return;
+            } else {
+                savedWidth = defaultWallpaperSize.x;
+                savedHeight = defaultWallpaperSize.y;
+            }
+        }
+
+        if (savedWidth != wallpaperManager.getDesiredMinimumWidth() ||
+                savedHeight != wallpaperManager.getDesiredMinimumHeight()) {
+            wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight);
+        }
+    }
+
+    /**
+     * As a ratio of screen height, the total distance we want the parallax effect to span
+     * horizontally
+     */
+    public static float wallpaperTravelToScreenWidthRatio(int width, int height) {
+        float aspectRatio = width / (float) height;
+
+        // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width
+        // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width
+        // We will use these two data points to extrapolate how much the wallpaper parallax effect
+        // to span (ie travel) at any aspect ratio:
+
+        final float ASPECT_RATIO_LANDSCAPE = 16/10f;
+        final float ASPECT_RATIO_PORTRAIT = 10/16f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f;
+        final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f;
+
+        // To find out the desired width at different aspect ratios, we use the following two
+        // formulas, where the coefficient on x is the aspect ratio (width/height):
+        //   (16/10)x + y = 1.5
+        //   (10/16)x + y = 1.2
+        // We solve for x and y and end up with a final formula:
+        final float x =
+            (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) /
+            (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT);
+        final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT;
+        return x * aspectRatio + y;
+    }
+
+    private static Point sDefaultWallpaperSize;
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    public static Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+        if (sDefaultWallpaperSize == null) {
+            Point minDims = new Point();
+            Point maxDims = new Point();
+            windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+
+            int maxDim = Math.max(maxDims.x, maxDims.y);
+            int minDim = Math.max(minDims.x, minDims.y);
+
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+                Point realSize = new Point();
+                windowManager.getDefaultDisplay().getRealSize(realSize);
+                maxDim = Math.max(realSize.x, realSize.y);
+                minDim = Math.min(realSize.x, realSize.y);
+            }
+
+            // We need to ensure that there is enough extra space in the wallpaper
+            // for the intended parallax effects
+            final int defaultWidth, defaultHeight;
+            if (res.getConfiguration().smallestScreenWidthDp >= 720) {
+                defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim));
+                defaultHeight = maxDim;
+            } else {
+                defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim);
+                defaultHeight = maxDim;
+            }
+            sDefaultWallpaperSize = new Point(defaultWidth, defaultHeight);
+        }
+        return sDefaultWallpaperSize;
+    }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
new file mode 100644
index 0000000..a569850
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+
+/**
+ * Meta data used for late binding of the short cuts.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddShortcutInfo extends PendingAddItemInfo {
+
+    ActivityInfo activityInfo;
+
+    public PendingAddShortcutInfo(ActivityInfo activityInfo) {
+        this.activityInfo = activityInfo;
+        componentName = new ComponentName(activityInfo.packageName, activityInfo.name);
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PendingAddShortcutInfo package=%s, name=%s",
+                activityInfo.packageName, activityInfo.name);
+    }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
new file mode 100644
index 0000000..758287a
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+/**
+ * Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddWidgetInfo extends PendingAddItemInfo {
+    public int minWidth;
+    public int minHeight;
+    public int minResizeWidth;
+    public int minResizeHeight;
+    public int previewImage;
+    public int icon;
+    public LauncherAppWidgetProviderInfo info;
+    public AppWidgetHostView boundWidget;
+    public Bundle bindOptions = null;
+
+    public PendingAddWidgetInfo(Launcher launcher, LauncherAppWidgetProviderInfo i, Parcelable data) {
+        if (i.isCustomWidget) {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+        } else {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+        }
+        this.info = i;
+        user = AppWidgetManagerCompat.getInstance(launcher).getUser(i);
+        componentName = i.provider;
+        minWidth = i.minWidth;
+        minHeight = i.minHeight;
+        minResizeWidth = i.minResizeWidth;
+        minResizeHeight = i.minResizeHeight;
+        previewImage = i.previewImage;
+        icon = i.icon;
+
+        spanX = i.getSpanX(launcher);
+        spanY = i.getSpanY(launcher);
+        minSpanX = i.getMinSpanX(launcher);
+        minSpanY = i.getMinSpanY(launcher);
+    }
+
+    public boolean isCustomWidget() {
+        return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PendingAddWidgetInfo package=%s, name=%s",
+                componentName.getPackageName(), componentName.getShortClassName());
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
new file mode 100644
index 0000000..7496ea2
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.ViewPropertyAnimator;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.StylusEventHelper;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+/**
+ * Represents the individual cell of the widget inside the widget tray. The preview is drawn
+ * horizontally centered, and scaled down if needed.
+ *
+ * This view does not support padding. Since the image is scaled down to fit the view, padding will
+ * further decrease the scaling factor. Drag-n-drop uses the view bounds for showing a smooth
+ * transition from the view to drag view, so when adding padding support, DnD would need to
+ * consider the appropriate scaling factor.
+ */
+public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
+
+    private static final String TAG = "WidgetCell";
+    private static final boolean DEBUG = false;
+
+    private static final int FADE_IN_DURATION_MS = 90;
+
+    /** Widget cell width is calculated by multiplying this factor to grid cell width. */
+    private static final float WIDTH_SCALE = 2.6f;
+
+    /** Widget preview width is calculated by multiplying this factor to the widget cell width. */
+    private static final float PREVIEW_SCALE = 0.8f;
+
+    private int mPresetPreviewSize;
+    int cellSize;
+
+    private WidgetImageView mWidgetImage;
+    private TextView mWidgetName;
+    private TextView mWidgetDims;
+
+    private String mDimensionsFormatString;
+    private Object mInfo;
+
+    private WidgetPreviewLoader mWidgetPreviewLoader;
+    private PreviewLoadRequest mActiveRequest;
+    private StylusEventHelper mStylusEventHelper;
+
+    private Launcher mLauncher;
+
+    public WidgetCell(Context context) {
+        this(context, null);
+    }
+
+    public WidgetCell(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        final Resources r = context.getResources();
+        mLauncher = (Launcher) context;
+        mStylusEventHelper = new StylusEventHelper(this);
+
+        mDimensionsFormatString = r.getString(R.string.widget_dims_format);
+        setContainerWidth();
+        setWillNotDraw(false);
+        setClipToPadding(false);
+        setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+    }
+
+    private void setContainerWidth() {
+        DeviceProfile profile = mLauncher.getDeviceProfile();
+        cellSize = (int) (profile.cellWidthPx * WIDTH_SCALE);
+        mPresetPreviewSize = (int) (cellSize * PREVIEW_SCALE);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mWidgetImage = (WidgetImageView) findViewById(R.id.widget_preview);
+        mWidgetName = ((TextView) findViewById(R.id.widget_name));
+        mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
+    }
+
+    /**
+     * Called to clear the view and free attached resources. (e.g., {@link Bitmap}
+     */
+    public void clear() {
+        if (DEBUG) {
+            Log.d(TAG, "reset called on:" + mWidgetName.getText());
+        }
+        mWidgetImage.animate().cancel();
+        mWidgetImage.setBitmap(null);
+        mWidgetName.setText(null);
+        mWidgetDims.setText(null);
+
+        if (mActiveRequest != null) {
+            mActiveRequest.cleanup();
+            mActiveRequest = null;
+        }
+    }
+
+    /**
+     * Apply the widget provider info to the view.
+     */
+    public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info,
+            WidgetPreviewLoader loader) {
+
+        InvariantDeviceProfile profile =
+                LauncherAppState.getInstance().getInvariantDeviceProfile();
+        mInfo = info;
+        // TODO(hyunyoungs): setup a cache for these labels.
+        mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
+        int hSpan = Math.min(info.getSpanX(mLauncher), profile.numColumns);
+        int vSpan = Math.min(info.getSpanY(mLauncher), profile.numRows);
+        mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
+        mWidgetPreviewLoader = loader;
+    }
+
+    /**
+     * Apply the resolve info to the view.
+     */
+    public void applyFromResolveInfo(
+            PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
+        mInfo = info;
+        CharSequence label = info.loadLabel(pm);
+        mWidgetName.setText(label);
+        mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1));
+        mWidgetPreviewLoader = loader;
+    }
+
+    public int[] getPreviewSize() {
+        int[] maxSize = new int[2];
+
+        maxSize[0] = mPresetPreviewSize;
+        maxSize[1] = mPresetPreviewSize;
+        return maxSize;
+    }
+
+    public void applyPreview(Bitmap bitmap) {
+        if (bitmap != null) {
+            mWidgetImage.setBitmap(bitmap);
+            mWidgetImage.setAlpha(0f);
+            ViewPropertyAnimator anim = mWidgetImage.animate();
+            anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+        }
+    }
+
+    public void ensurePreview() {
+        if (mActiveRequest != null) {
+            return;
+        }
+        int[] size = getPreviewSize();
+        if (DEBUG) {
+            Log.d(TAG, String.format("[tag=%s] ensurePreview (%d, %d):",
+                    getTagToString(), size[0], size[1]));
+        }
+        mActiveRequest = mWidgetPreviewLoader.getPreview(mInfo, size[0], size[1], this);
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        removeOnLayoutChangeListener(this);
+        ensurePreview();
+    }
+
+    public int getActualItemWidth() {
+        ItemInfo info = (ItemInfo) getTag();
+        int[] size = getPreviewSize();
+        int cellWidth = mLauncher.getDeviceProfile().cellWidthPx;
+
+        return Math.min(size[0], info.spanX * cellWidth);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = super.onTouchEvent(ev);
+        if (mStylusEventHelper.checkAndPerformStylusEvent(ev)) {
+            return true;
+        }
+        return handled;
+    }
+
+    /**
+     * Helper method to get the string info of the tag.
+     */
+    private String getTagToString() {
+        if (getTag() instanceof PendingAddWidgetInfo ||
+                getTag() instanceof PendingAddShortcutInfo) {
+            return getTag().toString();
+        }
+        return "";
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
new file mode 100644
index 0000000..30b3d58
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -0,0 +1,155 @@
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.DragController.DragListener;
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.util.Thunk;
+
+public class WidgetHostViewLoader implements DragListener {
+
+    /* Runnables to handle inflation and binding. */
+    @Thunk Runnable mInflateWidgetRunnable = null;
+    private Runnable mBindWidgetRunnable = null;
+
+    // TODO: technically, this class should not have to know the existence of the launcher.
+    @Thunk Launcher mLauncher;
+    @Thunk Handler mHandler;
+    @Thunk final View mView;
+    @Thunk final PendingAddWidgetInfo mInfo;
+
+    // Widget id generated for binding a widget host view or -1 for invalid id. The id is
+    // not is use as long as it is stored here and can be deleted safely. Once its used, this value
+    // to be set back to -1.
+    @Thunk int mWidgetLoadingId = -1;
+
+    public WidgetHostViewLoader(Launcher launcher, View view) {
+        mLauncher = launcher;
+        mHandler = new Handler();
+        mView = view;
+        mInfo = (PendingAddWidgetInfo) view.getTag();
+    }
+
+    @Override
+    public void onDragStart(DragSource source, Object info, int dragAction) { }
+
+    @Override
+    public void onDragEnd() {
+        // Cleanup up preloading state.
+        mLauncher.getDragController().removeDragListener(this);
+
+        mHandler.removeCallbacks(mBindWidgetRunnable);
+        mHandler.removeCallbacks(mInflateWidgetRunnable);
+
+        // Cleanup widget id
+        if (mWidgetLoadingId != -1) {
+            mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+            mWidgetLoadingId = -1;
+        }
+
+        // The widget was inflated and added to the DragLayer -- remove it.
+        if (mInfo.boundWidget != null) {
+            mLauncher.getDragLayer().removeView(mInfo.boundWidget);
+            mLauncher.getAppWidgetHost().deleteAppWidgetId(mInfo.boundWidget.getAppWidgetId());
+            mInfo.boundWidget = null;
+        }
+    }
+
+    /**
+     * Start preloading the widget.
+     */
+    public boolean preloadWidget() {
+        final LauncherAppWidgetProviderInfo pInfo = mInfo.info;
+
+        if (pInfo.isCustomWidget) {
+            return false;
+        }
+        final Bundle options = getDefaultOptionsForWidget(mLauncher, mInfo);
+
+        // If there is a configuration activity, do not follow thru bound and inflate.
+        if (pInfo.configure != null) {
+            mInfo.bindOptions = options;
+            return false;
+        }
+
+        mBindWidgetRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+                if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
+                        mWidgetLoadingId, pInfo, options)) {
+
+                    // Widget id bound. Inflate the widget.
+                    mHandler.post(mInflateWidgetRunnable);
+                }
+            }
+        };
+
+        mInflateWidgetRunnable = new Runnable() {
+            @Override
+            public void run() {
+                if (mWidgetLoadingId == -1) {
+                    return;
+                }
+                AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+                        (Context) mLauncher, mWidgetLoadingId, pInfo);
+                mInfo.boundWidget = hostView;
+
+                // We used up the widget Id in binding the above view.
+                mWidgetLoadingId = -1;
+
+                hostView.setVisibility(View.INVISIBLE);
+                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(mInfo, false);
+                // We want the first widget layout to be the correct size. This will be important
+                // for width size reporting to the AppWidgetManager.
+                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
+                        unScaledSize[1]);
+                lp.x = lp.y = 0;
+                lp.customPosition = true;
+                hostView.setLayoutParams(lp);
+                mLauncher.getDragLayer().addView(hostView);
+                mView.setTag(mInfo);
+            }
+        };
+
+        mHandler.post(mBindWidgetRunnable);
+        return true;
+    }
+
+    public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
+        Bundle options = null;
+        Rect rect = new Rect();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
+            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
+                    info.componentName, null);
+
+            float density = launcher.getResources().getDisplayMetrics().density;
+            int xPaddingDips = (int) ((padding.left + padding.right) / density);
+            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+
+            options = new Bundle();
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+                    rect.left - xPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+                    rect.top - yPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+                    rect.right - xPaddingDips);
+            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+                    rect.bottom - yPaddingDips);
+        }
+        return options;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
new file mode 100644
index 0000000..b0fbe1e
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * View that draws a bitmap horizontally centered. If the image width is greater than the view
+ * width, the image is scaled down appropriately.
+ */
+public class WidgetImageView extends View {
+
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    private final RectF mDstRectF = new RectF();
+    private Bitmap mBitmap;
+
+    public WidgetImageView(Context context) {
+        super(context);
+    }
+
+    public WidgetImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public WidgetImageView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setBitmap(Bitmap bitmap) {
+        mBitmap = bitmap;
+        invalidate();
+    }
+
+    public Bitmap getBitmap() {
+        return mBitmap;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mBitmap != null) {
+            updateDstRectF();
+            canvas.drawBitmap(mBitmap, null, mDstRectF, mPaint);
+        }
+    }
+
+    /**
+     * Prevents the inefficient alpha view rendering.
+     */
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
+    private void updateDstRectF() {
+        if (mBitmap.getWidth() > getWidth()) {
+            float scale = ((float) getWidth()) / mBitmap.getWidth();
+            mDstRectF.set(0, 0, getWidth(), scale * mBitmap.getHeight());
+        } else {
+            mDstRectF.set(
+                    (getWidth() - mBitmap.getWidth()) * 0.5f,
+                    0,
+                    (getWidth() + mBitmap.getWidth()) * 0.5f,
+                    mBitmap.getHeight());
+        }
+    }
+
+    /**
+     * @return the bounds where the image was drawn.
+     */
+    public Rect getBitmapBounds() {
+        updateDstRectF();
+        Rect rect = new Rect();
+        mDstRectF.round(rect);
+        return rect;
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
new file mode 100644
index 0000000..5afd7c4
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView.State;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.launcher3.BaseContainerView;
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DragController;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Folder;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.Thunk;
+
+/**
+ * The widgets list view container.
+ */
+public class WidgetsContainerView extends BaseContainerView
+        implements View.OnLongClickListener, View.OnClickListener, DragSource{
+
+    private static final String TAG = "WidgetsContainerView";
+    private static final boolean DEBUG = false;
+
+    /* Coefficient multiplied to the screen height for preloading widgets. */
+    private static final int PRELOAD_SCREEN_HEIGHT_MULTIPLE = 1;
+
+    /* Global instances that are used inside this container. */
+    @Thunk Launcher mLauncher;
+    private DragController mDragController;
+    private IconCache mIconCache;
+
+    /* Recycler view related member variables */
+    private View mContent;
+    private WidgetsRecyclerView mView;
+    private WidgetsListAdapter mAdapter;
+
+    /* Touch handling related member variables. */
+    private Toast mWidgetInstructionToast;
+
+    /* Rendering related. */
+    private WidgetPreviewLoader mWidgetPreviewLoader;
+
+    private Rect mPadding = new Rect();
+
+    public WidgetsContainerView(Context context) {
+        this(context, null);
+    }
+
+    public WidgetsContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = (Launcher) context;
+        mDragController = mLauncher.getDragController();
+        mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
+        mIconCache = (LauncherAppState.getInstance()).getIconCache();
+        if (DEBUG) {
+            Log.d(TAG, "WidgetsContainerView constructor");
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        mContent = findViewById(R.id.content);
+        mView = (WidgetsRecyclerView) findViewById(R.id.widgets_list_view);
+        mView.setAdapter(mAdapter);
+
+        // This extends the layout space so that preloading happen for the {@link RecyclerView}
+        mView.setLayoutManager(new LinearLayoutManager(getContext()) {
+            @Override
+            protected int getExtraLayoutSpace(State state) {
+                DeviceProfile grid = mLauncher.getDeviceProfile();
+                return super.getExtraLayoutSpace(state)
+                        + grid.availableHeightPx * PRELOAD_SCREEN_HEIGHT_MULTIPLE;
+            }
+        });
+        mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+                getPaddingBottom());
+    }
+
+    //
+    // Returns views used for launcher transitions.
+    //
+
+    public View getContentView() {
+        return mView;
+    }
+
+    public View getRevealView() {
+        // TODO(hyunyoungs): temporarily use apps view transition.
+        return findViewById(R.id.widgets_reveal_view);
+    }
+
+    public void scrollToTop() {
+        mView.scrollToPosition(0);
+    }
+
+    //
+    // Touch related handling.
+    //
+
+    @Override
+    public void onClick(View v) {
+        // When we have exited widget tray or are in transition, disregard clicks
+        if (!mLauncher.isWidgetsViewVisible()
+                || mLauncher.getWorkspace().isSwitchingState()
+                || !(v instanceof WidgetCell)) return;
+
+        // Let the user know that they have to long press to add a widget
+        if (mWidgetInstructionToast != null) {
+            mWidgetInstructionToast.cancel();
+        }
+        mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
+                Toast.LENGTH_SHORT);
+        mWidgetInstructionToast.show();
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("onLonglick [v=%s]", v));
+        }
+        // Return early if this is not initiated from a touch
+        if (!v.isInTouchMode()) return false;
+        // When we have exited all apps or are in transition, disregard long clicks
+        if (!mLauncher.isWidgetsViewVisible() ||
+                mLauncher.getWorkspace().isSwitchingState()) return false;
+        // Return if global dragging is not enabled
+        Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
+        if (!mLauncher.isDraggingEnabled()) return false;
+
+        boolean status = beginDragging(v);
+        if (status && v.getTag() instanceof PendingAddWidgetInfo) {
+            WidgetHostViewLoader hostLoader = new WidgetHostViewLoader(mLauncher, v);
+            boolean preloadStatus = hostLoader.preloadWidget();
+            if (DEBUG) {
+                Log.d(TAG, String.format("preloading widget [status=%s]", preloadStatus));
+            }
+            mLauncher.getDragController().addDragListener(hostLoader);
+        }
+        return status;
+    }
+
+    private boolean beginDragging(View v) {
+        if (v instanceof WidgetCell) {
+            if (!beginDraggingWidget((WidgetCell) v)) {
+                return false;
+            }
+        } else {
+            Log.e(TAG, "Unexpected dragging view: " + v);
+        }
+
+        // We don't enter spring-loaded mode if the drag has been cancelled
+        if (mLauncher.getDragController().isDragging()) {
+            // Go into spring loaded mode (must happen before we startDrag())
+            mLauncher.enterSpringLoadedDragMode();
+        }
+
+        return true;
+    }
+
+    private boolean beginDraggingWidget(WidgetCell v) {
+        // Get the widget preview as the drag representation
+        WidgetImageView image = (WidgetImageView) v.findViewById(R.id.widget_preview);
+        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
+        // we abort the drag.
+        if (image.getBitmap() == null) {
+            return false;
+        }
+
+        // Compose the drag image
+        Bitmap preview;
+        float scale = 1f;
+        final Rect bounds = image.getBitmapBounds();
+
+        if (createItemInfo instanceof PendingAddWidgetInfo) {
+            // This can happen in some weird cases involving multi-touch. We can't start dragging
+            // the widget if this is null, so we break out.
+
+            PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
+            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
+
+            Bitmap icon = image.getBitmap();
+            float minScale = 1.25f;
+            int maxWidth = Math.min((int) (icon.getWidth() * minScale), size[0]);
+
+            int[] previewSizeBeforeScale = new int[1];
+            preview = getWidgetPreviewLoader().generateWidgetPreview(mLauncher,
+                    createWidgetInfo.info, maxWidth, null, previewSizeBeforeScale);
+
+            if (previewSizeBeforeScale[0] < icon.getWidth()) {
+                // The icon has extra padding around it.
+                int padding = (icon.getWidth() - previewSizeBeforeScale[0]) / 2;
+                if (icon.getWidth() > image.getWidth()) {
+                    padding = padding * image.getWidth() / icon.getWidth();
+                }
+
+                bounds.left += padding;
+                bounds.right -= padding;
+            }
+            scale = bounds.width() / (float) preview.getWidth();
+        } else {
+            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
+            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
+            preview = Utilities.createIconBitmap(icon, mLauncher);
+            createItemInfo.spanX = createItemInfo.spanY = 1;
+            scale = ((float) mLauncher.getDeviceProfile().iconSizePx) / preview.getWidth();
+        }
+
+        // Don't clip alpha values for the drag outline if we're using the default widget preview
+        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
+                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
+
+        // Start the drag
+        mLauncher.lockScreenOrientation();
+        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, preview, clipAlpha);
+        mDragController.startDrag(image, preview, this, createItemInfo,
+                bounds, DragController.DRAG_ACTION_COPY, scale);
+
+        preview.recycle();
+        return true;
+    }
+
+    //
+    // Drag related handling methods that implement {@link DragSource} interface.
+    //
+
+    @Override
+    public boolean supportsFlingToDelete() {
+        return false;
+    }
+
+    @Override
+    public boolean supportsAppInfoDropTarget() {
+        return true;
+    }
+
+    /*
+     * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
+     * {@link DeleteDropTarget} to be invisible.)
+     */
+    @Override
+    public boolean supportsDeleteDropTarget() {
+        return false;
+    }
+
+    @Override
+    public float getIntrinsicIconScaleFactor() {
+        return 0;
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // We just dismiss the drag when we fling, so cleanup here
+        mLauncher.exitSpringLoadedDragModeDelayed(true,
+                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        mLauncher.unlockScreenOrientation(false);
+    }
+
+    @Override
+    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+            boolean success) {
+        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragModeDelayed(true,
+                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        }
+        mLauncher.unlockScreenOrientation(false);
+
+        // Display an error message if the drag failed due to there not being enough space on the
+        // target layout we were dropping on.
+        if (!success) {
+            boolean showOutOfSpaceMessage = false;
+            if (target instanceof Workspace) {
+                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
+                Workspace workspace = (Workspace) target;
+                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
+                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
+                if (layout != null) {
+                    layout.calculateSpans(itemInfo);
+                    showOutOfSpaceMessage =
+                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+                }
+            }
+            if (showOutOfSpaceMessage) {
+                mLauncher.showOutOfSpaceMessage(false);
+            }
+            d.deferDragViewCleanupPostAnimation = false;
+        }
+    }
+
+    //
+    // Container rendering related.
+    //
+
+    @Override
+    protected void onUpdateBackgroundAndPaddings(Rect searchBarBounds, Rect padding) {
+        // Apply the top-bottom padding to the content itself so that the launcher transition is
+        // clipped correctly
+        mContent.setPadding(0, padding.top, 0, padding.bottom);
+
+        // TODO: Use quantum_panel_dark instead of quantum_panel_shape_dark.
+        InsetDrawable background = new InsetDrawable(
+                getResources().getDrawable(R.drawable.quantum_panel_shape_dark), padding.left, 0,
+                padding.right, 0);
+        Rect bgPadding = new Rect();
+        background.getPadding(bgPadding);
+        mView.setBackground(background);
+        getRevealView().setBackground(background.getConstantState().newDrawable());
+        mView.updateBackgroundPadding(bgPadding);
+    }
+
+    /**
+     * Initialize the widget data model.
+     */
+    public void addWidgets(WidgetsModel model) {
+        mView.setWidgets(model);
+        mAdapter.setWidgetsModel(model);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    private WidgetPreviewLoader getWidgetPreviewLoader() {
+        if (mWidgetPreviewLoader == null) {
+            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+        }
+        return mWidgetPreviewLoader;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
new file mode 100644
index 0000000..d2ea252
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Build;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.LinearLayout;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.model.WidgetsModel;
+
+import java.util.List;
+
+/**
+ * List view adapter for the widget tray.
+ *
+ * <p>Memory vs. Performance:
+ * The less number of types of views are inserted into a {@link RecyclerView}, the more recycling
+ * happens and less memory is consumed. {@link #getItemViewType} was not overridden as there is
+ * only a single type of view.
+ */
+public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
+
+    private static final String TAG = "WidgetsListAdapter";
+    private static final boolean DEBUG = false;
+
+    private Launcher mLauncher;
+    private LayoutInflater mLayoutInflater;
+
+    private WidgetsModel mWidgetsModel;
+    private WidgetPreviewLoader mWidgetPreviewLoader;
+
+    private View.OnClickListener mIconClickListener;
+    private View.OnLongClickListener mIconLongClickListener;
+
+    private static final int PRESET_INDENT_SIZE_TABLET = 56;
+    private int mIndent = 0;
+
+    public WidgetsListAdapter(Context context,
+            View.OnClickListener iconClickListener,
+            View.OnLongClickListener iconLongClickListener,
+            Launcher launcher) {
+        mLayoutInflater = LayoutInflater.from(context);
+
+        mIconClickListener = iconClickListener;
+        mIconLongClickListener = iconLongClickListener;
+        mLauncher = launcher;
+
+        setContainerHeight();
+    }
+
+    public void setWidgetsModel(WidgetsModel w) {
+        mWidgetsModel = w;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mWidgetsModel.getPackageSize();
+    }
+
+    @Override
+    public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) {
+        List<Object> infoList = mWidgetsModel.getSortedWidgets(pos);
+
+        ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+        if (DEBUG) {
+            Log.d(TAG, String.format(
+                    "onBindViewHolder [pos=%d, widget#=%d, row.getChildCount=%d]",
+                    pos, infoList.size(), row.getChildCount()));
+        }
+
+        // Add more views.
+        // if there are too many, hide them.
+        int diff = infoList.size() - row.getChildCount();
+
+        if (diff > 0) {
+            for (int i = 0; i < diff; i++) {
+                WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
+                        R.layout.widget_cell, row, false);
+
+                // set up touch.
+                widget.setOnClickListener(mIconClickListener);
+                widget.setOnLongClickListener(mIconLongClickListener);
+                LayoutParams lp = widget.getLayoutParams();
+                lp.height = widget.cellSize;
+                lp.width = widget.cellSize;
+                widget.setLayoutParams(lp);
+
+                row.addView(widget);
+            }
+        } else if (diff < 0) {
+            for (int i=infoList.size() ; i < row.getChildCount(); i++) {
+                row.getChildAt(i).setVisibility(View.GONE);
+            }
+        }
+
+        // Bind the views in the application info section.
+        PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(pos);
+        BubbleTextView tv = ((BubbleTextView) holder.getContent().findViewById(R.id.section));
+        tv.applyFromPackageItemInfo(infoOut);
+
+        // Bind the view in the widget horizontal tray region.
+        if (getWidgetPreviewLoader() == null) {
+            return;
+        }
+        for (int i=0; i < infoList.size(); i++) {
+            WidgetCell widget = (WidgetCell) row.getChildAt(i);
+            if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) {
+                LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i);
+                PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(mLauncher, info, null);
+                widget.setTag(pawi);
+                widget.applyFromAppWidgetProviderInfo(info, mWidgetPreviewLoader);
+            } else if (infoList.get(i) instanceof ResolveInfo) {
+                ResolveInfo info = (ResolveInfo) infoList.get(i);
+                PendingAddShortcutInfo pasi = new PendingAddShortcutInfo(info.activityInfo);
+                widget.setTag(pasi);
+                widget.applyFromResolveInfo(mLauncher.getPackageManager(), info, mWidgetPreviewLoader);
+            }
+            widget.ensurePreview();
+            widget.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    @Override
+    public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (DEBUG) {
+            Log.v(TAG, "\nonCreateViewHolder");
+        }
+
+        ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
+                R.layout.widgets_list_row_view, parent, false);
+        LinearLayout cellList = (LinearLayout) container.findViewById(R.id.widgets_cell_list);
+
+        // if the end padding is 0, then container view (horizontal scroll view) doesn't respect
+        // the end of the linear layout width + the start padding and doesn't allow scrolling.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            cellList.setPaddingRelative(mIndent, 0, 1, 0);
+        } else {
+            cellList.setPadding(mIndent, 0, 1, 0);
+        }
+
+        return new WidgetsRowViewHolder(container);
+    }
+
+    @Override
+    public void onViewRecycled(WidgetsRowViewHolder holder) {
+        ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+
+        for (int i = 0; i < row.getChildCount(); i++) {
+            WidgetCell widget = (WidgetCell) row.getChildAt(i);
+            widget.clear();
+        }
+    }
+
+    public boolean onFailedToRecycleView(WidgetsRowViewHolder holder) {
+        // If child views are animating, then the RecyclerView may choose not to recycle the view,
+        // causing extraneous onCreateViewHolder() calls.  It is safe in this case to continue
+        // recycling this view, and take care in onViewRecycled() to cancel any existing
+        // animations.
+        return true;
+    }
+
+    @Override
+    public long getItemId(int pos) {
+        return pos;
+    }
+
+    private WidgetPreviewLoader getWidgetPreviewLoader() {
+        if (mWidgetPreviewLoader == null) {
+            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+        }
+        return mWidgetPreviewLoader;
+    }
+
+    private void setContainerHeight() {
+        Resources r = mLauncher.getResources();
+        DeviceProfile profile = mLauncher.getDeviceProfile();
+        if (profile.isLargeTablet || profile.isTablet) {
+            mIndent = Utilities.pxFromDp(PRESET_INDENT_SIZE_TABLET, r.getDisplayMetrics());
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
new file mode 100644
index 0000000..61e63cd
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.support.v7.widget.LinearLayoutManager;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.launcher3.BaseRecyclerView;
+import com.android.launcher3.R;
+import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.model.WidgetsModel;
+
+/**
+ * The widgets recycler view.
+ */
+public class WidgetsRecyclerView extends BaseRecyclerView {
+
+    private static final String TAG = "WidgetsRecyclerView";
+    private WidgetsModel mWidgets;
+    private ScrollPositionState mScrollPosState = new ScrollPositionState();
+
+    public WidgetsRecyclerView(Context context) {
+        this(context, null);
+    }
+
+    public WidgetsRecyclerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        // API 21 and below only support 3 parameter ctor.
+        super(context, attrs, defStyleAttr);
+    }
+
+    public WidgetsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        this(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        addOnItemTouchListener(this);
+    }
+
+    public int getFastScrollerTrackColor(int defaultTrackColor) {
+        return Color.WHITE;
+    }
+
+    public int getFastScrollerThumbInactiveColor(int defaultInactiveThumbColor) {
+        return getResources().getColor(R.color.widgets_view_fastscroll_thumb_inactive_color);
+    }
+
+    /**
+     * Sets the widget model in this view, used to determine the fast scroll position.
+     */
+    public void setWidgets(WidgetsModel widgets) {
+        mWidgets = widgets;
+    }
+    
+    /**
+     * We need to override the draw to ensure that we don't draw the overscroll effect beyond the
+     * background bounds.
+     */
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.clipRect(mBackgroundPadding.left, mBackgroundPadding.top,
+                getWidth() - mBackgroundPadding.right,
+                getHeight() - mBackgroundPadding.bottom);
+        super.dispatchDraw(canvas);
+    }
+
+    /**
+     * Maps the touch (from 0..1) to the adapter position that should be visible.
+     */
+    @Override
+    public String scrollToPositionAtProgress(float touchFraction) {
+        int rowCount = mWidgets.getPackageSize();
+        if (rowCount == 0) {
+            return "";
+        }
+
+        // Stop the scroller if it is scrolling
+        stopScroll();
+
+        getCurScrollState(mScrollPosState);
+        float pos = rowCount * touchFraction;
+        int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0);
+        LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());
+        layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction));
+
+        int posInt = (int) ((touchFraction == 1)? pos -1 : pos);
+        PackageItemInfo p = mWidgets.getPackageItemInfo(posInt);
+        return p.titleSectionName;
+    }
+
+    /**
+     * Updates the bounds for the scrollbar.
+     */
+    @Override
+    public void onUpdateScrollbar() {
+        int rowCount = mWidgets.getPackageSize();
+
+        // Skip early if, there are no items.
+        if (rowCount == 0) {
+            mScrollbar.setScrollbarThumbOffset(-1, -1);
+            return;
+        }
+
+        // Skip early if, there no child laid out in the container.
+        getCurScrollState(mScrollPosState);
+        if (mScrollPosState.rowIndex < 0) {
+            mScrollbar.setScrollbarThumbOffset(-1, -1);
+            return;
+        }
+
+        synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0);
+    }
+
+    /**
+     * Returns the current scroll state.
+     */
+    private void getCurScrollState(ScrollPositionState stateOut) {
+        stateOut.rowIndex = -1;
+        stateOut.rowTopOffset = -1;
+        stateOut.rowHeight = -1;
+
+        int rowCount = mWidgets.getPackageSize();
+
+        // Return early if there are no items
+        if (rowCount == 0) {
+            return;
+        }
+        View child = getChildAt(0);
+        int position = getChildPosition(child);
+
+        stateOut.rowIndex = position;
+        stateOut.rowTopOffset = getLayoutManager().getDecoratedTop(child);
+        stateOut.rowHeight = child.getHeight();
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
new file mode 100644
index 0000000..249559a
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class WidgetsRowViewHolder extends ViewHolder {
+
+    ViewGroup mContent;
+
+    public WidgetsRowViewHolder(ViewGroup v) {
+        super(v);
+        mContent = v;
+    }
+
+    ViewGroup getContent() {
+        return mContent;
+    }
+}
diff --git a/tests/Android.mk b/tests/Android.mk
index 762a52b..eba4ade 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 The Android Open Source Project
+# Copyright (C) 2015 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,5 +12,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-#LOCAL_PATH := $(call my-dir)
-#include $(call all-makefiles-under,$(LOCAL_PATH))
+
+LOCAL_PATH := $(call my-dir)
+
+src_dirs := src
+res_dirs := res
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
+LOCAL_AAPT_FLAGS := --auto-add-overlay
+
+LOCAL_SDK_VERSION := 21
+
+LOCAL_PACKAGE_NAME := Launcher3Tests
+
+LOCAL_INSTRUMENTATION_FOR := Launcher3
+
+include $(BUILD_PACKAGE)
diff --git a/tests/stress/AndroidManifest.xml b/tests/AndroidManifest.xml
similarity index 83%
rename from tests/stress/AndroidManifest.xml
rename to tests/AndroidManifest.xml
index bcca1ff..42ae5a3 100644
--- a/tests/stress/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="2.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.launcher3.stress.launcherrotation">
+    package="com.android.launcher3.tests">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -24,6 +24,6 @@
     <instrumentation
         android:name="android.test.InstrumentationTestRunner"
         android:targetPackage="com.android.launcher3"
-        android:label="Rotation stress test using Launcher2">
+        android:label="Unit tests for Launcher3">
     </instrumentation>
 </manifest>
diff --git a/res/values-sw340dp-port/config.xml b/tests/res/values/string.xml
similarity index 70%
copy from res/values-sw340dp-port/config.xml
copy to tests/res/values/string.xml
index 5f71077..3c1ec5c 100644
--- a/res/values-sw340dp-port/config.xml
+++ b/tests/res/values/string.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,5 +13,9 @@
      limitations under the License.
 -->
 
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Dummy string for tests. [DO NOT TRANSLATE] -->
+    <string name="dummy" >Dummy string for tests.</string>
+
 </resources>
diff --git a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
new file mode 100644
index 0000000..1bc7c11
--- /dev/null
+++ b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.android.launcher3;
+
+import android.graphics.PointF;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.util.FocusLogic;
+
+import java.util.ArrayList;
+
+/**
+ * Tests the {@link DeviceProfile} and {@link InvariantDeviceProfile}.
+ */
+@SmallTest
+public class InvariantDeviceProfileTest extends AndroidTestCase {
+
+    private static final String TAG = "DeviceProfileTest";
+    private static final boolean DEBUG = false;
+
+    private InvariantDeviceProfile mInvariantProfile;
+    private ArrayList<InvariantDeviceProfile> mPredefinedDeviceProfiles;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInvariantProfile = new InvariantDeviceProfile(getContext());
+        mPredefinedDeviceProfiles = mInvariantProfile.getPredefinedDeviceProfiles();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Nothing to tear down as this class only tests static methods.
+    }
+
+    public void testFindClosestDeviceProfile2() {
+        for (InvariantDeviceProfile idf: mPredefinedDeviceProfiles) {
+            ArrayList<InvariantDeviceProfile> closestProfiles =
+                    mInvariantProfile.findClosestDeviceProfiles(
+                            idf.minWidthDps, idf.minHeightDps, mPredefinedDeviceProfiles);
+            assertTrue(closestProfiles.get(0).equals(idf));
+        }
+    }
+
+    /**
+     * Used to print out how the invDistWeightedInterpolate works between device profiles to
+     * tweak the two constants that control how the interpolation curve is shaped.
+     */
+    public void testInvInterpolation() {
+
+        InvariantDeviceProfile p1 = mPredefinedDeviceProfiles.get(7); // e.g., Large Phone
+        InvariantDeviceProfile p2 = mPredefinedDeviceProfiles.get(8); // e.g., Nexus 7
+
+        ArrayList<PointF> pts = createInterpolatedPoints(
+                new PointF(p1.minWidthDps, p1.minHeightDps),
+                new PointF(p2.minWidthDps, p2.minHeightDps),
+                20f);
+
+        for (int i = 0; i < pts.size(); i++) {
+            ArrayList<InvariantDeviceProfile> closestProfiles =
+                    mInvariantProfile.findClosestDeviceProfiles(
+                            pts.get(i).x, pts.get(i).y, mPredefinedDeviceProfiles);
+            InvariantDeviceProfile result =
+                    mInvariantProfile.invDistWeightedInterpolate(
+                            pts.get(i).x, pts.get(i).y, closestProfiles);
+            if (DEBUG) {
+                Log.d(TAG, String.format("width x height = (%f, %f)] iconSize = %f",
+                        pts.get(i).x, pts.get(i).y, result.iconSize));
+            }
+        }
+    }
+
+    private ArrayList<PointF> createInterpolatedPoints(PointF a, PointF b, float numPts) {
+        ArrayList<PointF> result = new ArrayList<PointF>();
+        result.add(a);
+        for (float i = 1; i < numPts; i = i + 1.0f) {
+            result.add(new PointF((b.x * i +  a.x * (numPts - i)) / numPts,
+                    (b.y * i + a.y * (numPts - i)) / numPts));
+        }
+        result.add(b);
+        return result;
+    }
+
+    /**
+     * Ensures that system calls (e.g., WindowManager, DisplayMetrics) that require contexts are
+     * properly working to generate minimum width and height of the display.
+     */
+    public void test_hammerhead() {
+        if (!android.os.Build.DEVICE.equals("hammerhead")) {
+            return;
+        }
+        assertEquals(mInvariantProfile.numRows, 4);
+        assertEquals(mInvariantProfile.numColumns, 4);
+        assertEquals((int) mInvariantProfile.numHotseatIcons, 5);
+
+        DeviceProfile landscapeProfile = mInvariantProfile.landscapeProfile;
+        DeviceProfile portraitProfile = mInvariantProfile.portraitProfile;
+
+        assertEquals(portraitProfile.allAppsNumCols, 3);
+        assertEquals(landscapeProfile.allAppsNumCols, 5); // not used
+    }
+
+    // Add more tests for other devices, however, running them once on a single device is enough
+    // for verifying that for a platform version, the WindowManager and DisplayMetrics is
+    // working as intended.
+}
diff --git a/tests/src/com/android/launcher3/util/FocusLogicTest.java b/tests/src/com/android/launcher3/util/FocusLogicTest.java
new file mode 100644
index 0000000..ea87014
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/FocusLogicTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.launcher3;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
+
+import com.android.launcher3.util.FocusLogic;
+
+/**
+ * Tests the {@link FocusLogic} class that handles key event based focus handling.
+ */
+@SmallTest
+public final class FocusLogicTest extends AndroidTestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // Nothing to set up as this class only tests static methods.
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Nothing to tear down as this class only tests static methods.
+    }
+
+    public void testShouldConsume() {
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_LEFT));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_RIGHT));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_UP));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DPAD_DOWN));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_MOVE_HOME));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_MOVE_END));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_UP));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_DOWN));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DEL));
+         assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_FORWARD_DEL));
+    }
+
+    public void testCreateSparseMatrix() {
+         // Either, 1) create a helper method to generate/instantiate all possible cell layout that
+         // may get created in real world to test this method. OR 2) Move all the matrix
+         // management routine to celllayout and write tests for them.
+    }
+}
diff --git a/tests/stress/Android.mk b/tests/stress/Android.mk
deleted file mode 100644
index 68289bd..0000000
--- a/tests/stress/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := LauncherRotationStressTest
-
-LOCAL_CERTIFICATE := shared
-
-LOCAL_INSTRUMENTATION_FOR := Launcher2
-
-include $(BUILD_PACKAGE)
diff --git a/tests/stress/src/com/android/launcher3/stress/LauncherRotationStressTest.java b/tests/stress/src/com/android/launcher3/stress/LauncherRotationStressTest.java
deleted file mode 100644
index a5b85eb..0000000
--- a/tests/stress/src/com/android/launcher3/stress/LauncherRotationStressTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.stress;
-
-
-import com.android.launcher3.Launcher;
-
-import android.content.pm.ActivityInfo;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.RepetitiveTest;
-import android.util.Log;
-
-/**
- * Run rotation stress test using Launcher2 for 50 iterations.
- */
-public class LauncherRotationStressTest extends ActivityInstrumentationTestCase2<Launcher> {
-
-    private static final int NUM_ITERATIONS = 50;
-    private static final int WAIT_TIME_MS = 500;
-    private static final String LOG_TAG = "LauncherRotationStressTest";
-
-    public LauncherRotationStressTest() {
-        super(Launcher.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    @RepetitiveTest(numIterations=NUM_ITERATIONS)
-    public void testLauncherRotationStress() throws Exception {
-        Launcher launcher = getActivity();
-        getInstrumentation().waitForIdleSync();
-        SystemClock.sleep(WAIT_TIME_MS);
-        launcher.setRequestedOrientation(
-                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        getInstrumentation().waitForIdleSync();
-        SystemClock.sleep(WAIT_TIME_MS);
-        launcher.setRequestedOrientation(
-                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
-    }
-}
diff --git a/util/com/android/launcher3/DecoderRing.java b/util/com/android/launcher3/DecoderRing.java
index 86431d9..0732fe8 100644
--- a/util/com/android/launcher3/DecoderRing.java
+++ b/util/com/android/launcher3/DecoderRing.java
@@ -220,9 +220,6 @@
                     if (widget.icon != null) {
                         writeImageData(widget.icon.data, prefix + "_icon.png");
                     }
-                    if (widget.preview != null) {
-                        writeImageData(widget.preview.data, prefix + "_preview.png");
-                    }
                 }
             }
         }