resolved conflicts for merge of 13ef17a3 to mnc-dr-dev
b/22609402
Change-Id: I140cf972d57e14737a6f91c0b4a8ec6c7ff1af2b
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/WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
new file mode 100644
index 0000000..091c054
--- /dev/null
+++ b/WallpaperPicker/src/com/android/launcher3/LauncherWallpaperPickerActivity.java
@@ -0,0 +1,21 @@
+/*
+ * 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;
+
+// TODO: Remove this class
+public class LauncherWallpaperPickerActivity extends WallpaperPickerActivity {
+}
\ 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;