am 1f9fb1d1: (-s ours) am 2b06c5b5: am 12ac0d60: Setting tab bar widths automatically

* commit '1f9fb1d1d98b2837bbaf21a8cb50014e60369f45':
  Setting tab bar widths automatically
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 444dbd8..f78a1b2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -45,7 +45,9 @@
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/Launcher2_intermediates)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
\ No newline at end of file
+# ************************************************
diff --git a/proguard.flags b/proguard.flags
index 19c8fd5..c2b2c65 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -20,6 +20,17 @@
   public void setHoverAlpha(float);
 }
 
+-keep class com.android.launcher2.DragLayer$LayoutParams {
+  public void setWidth(int);
+  public int getWidth();
+  public void setHeight(int);
+  public int getHeight();
+  public void setX(int);
+  public int getX();
+  public void setY(int);
+  public int getY();
+}
+
 -keep class com.android.launcher2.CellLayout$LayoutParams {
   public void setWidth(int);
   public int getWidth();
diff --git a/res/anim/all_apps_2d_fade_in.xml b/res/anim/all_apps_2d_fade_in.xml
index 0f1e4f4..9d2171a 100644
--- a/res/anim/all_apps_2d_fade_in.xml
+++ b/res/anim/all_apps_2d_fade_in.xml
@@ -20,4 +20,4 @@
     android:fromAlpha="0.0"
     android:toAlpha="1.0"
 
-    android:duration="@integer/config_allAppsFadeInTime" />
+    android:duration="@integer/config_appsCustomizeFadeInTime" />
diff --git a/res/anim/all_apps_2d_fade_out.xml b/res/anim/all_apps_2d_fade_out.xml
index cc47691..90520c7 100644
--- a/res/anim/all_apps_2d_fade_out.xml
+++ b/res/anim/all_apps_2d_fade_out.xml
@@ -20,4 +20,4 @@
     android:fromAlpha="1.0"
     android:toAlpha="0.0"
 
-    android:duration="@integer/config_allAppsFadeOutTime" />
+    android:duration="@integer/config_appsCustomizeFadeOutTime" />
diff --git a/res/anim/fade_in_slow.xml b/res/anim/fade_in_slow.xml
index 0f1e4f4..9d2171a 100644
--- a/res/anim/fade_in_slow.xml
+++ b/res/anim/fade_in_slow.xml
@@ -20,4 +20,4 @@
     android:fromAlpha="0.0"
     android:toAlpha="1.0"
 
-    android:duration="@integer/config_allAppsFadeInTime" />
+    android:duration="@integer/config_appsCustomizeFadeInTime" />
diff --git a/res/anim/fade_out_slow.xml b/res/anim/fade_out_slow.xml
index cc47691..90520c7 100644
--- a/res/anim/fade_out_slow.xml
+++ b/res/anim/fade_out_slow.xml
@@ -20,4 +20,4 @@
     android:fromAlpha="1.0"
     android:toAlpha="0.0"
 
-    android:duration="@integer/config_allAppsFadeOutTime" />
+    android:duration="@integer/config_appsCustomizeFadeOutTime" />
diff --git a/res/drawable-hdpi/box_launcher_top_normal.9.png b/res/drawable-hdpi/box_launcher_top_normal.9.png
index 98997ad..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_normal.9.png
+++ b/res/drawable-hdpi/box_launcher_top_normal.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_launcher_top_pressed.9.png b/res/drawable-hdpi/box_launcher_top_pressed.9.png
index f52fd48..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_pressed.9.png
+++ b/res/drawable-hdpi/box_launcher_top_pressed.9.png
Binary files differ
diff --git a/res/drawable-hdpi/box_launcher_top_selected.9.png b/res/drawable-hdpi/box_launcher_top_selected.9.png
index 8cacf0e..af04b07 100644
--- a/res/drawable-hdpi/box_launcher_top_selected.9.png
+++ b/res/drawable-hdpi/box_launcher_top_selected.9.png
Binary files differ
diff --git a/res/drawable-hdpi/focused_bg.9.png b/res/drawable-hdpi/focused_bg.9.png
new file mode 100644
index 0000000..1b0d3fa
--- /dev/null
+++ b/res/drawable-hdpi/focused_bg.9.png
Binary files differ
diff --git a/res/drawable-hdpi/folder_bg.9.png b/res/drawable-hdpi/folder_bg.9.png
new file mode 100644
index 0000000..6f1bbe5
--- /dev/null
+++ b/res/drawable-hdpi/folder_bg.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/home_press.9.png b/res/drawable-hdpi/home_press.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/home_press.9.png
rename to res/drawable-hdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_delete_holo_dark.png b/res/drawable-hdpi/ic_home_delete_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_home_delete_holo_dark.png
rename to res/drawable-hdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-hdpi/ic_home_delete_hover_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_home_delete_hover_holo_dark.png
rename to res/drawable-hdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png b/res/drawable-hdpi/ic_home_info_holo_dark.png
similarity index 100%
copy from res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png
copy to res/drawable-hdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/wallpaper_divider.png b/res/drawable-hdpi/wallpaper_divider.png
new file mode 100644
index 0000000..2f92d60
--- /dev/null
+++ b/res/drawable-hdpi/wallpaper_divider.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/app_market_generic.png b/res/drawable-large-hdpi/app_market_generic.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/app_market_generic.png
rename to res/drawable-large-hdpi/app_market_generic.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/divider_launcher_holo.9.png b/res/drawable-large-hdpi/divider_launcher_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/divider_launcher_holo.9.png
rename to res/drawable-large-hdpi/divider_launcher_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_blue.9.png b/res/drawable-large-hdpi/homescreen_large_blue.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_large_blue.9.png
rename to res/drawable-large-hdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_blue_strong.9.png b/res/drawable-large-hdpi/homescreen_large_blue_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_large_blue_strong.9.png
rename to res/drawable-large-hdpi/homescreen_large_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_green.9.png b/res/drawable-large-hdpi/homescreen_large_green.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_large_green.9.png
rename to res/drawable-large-hdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_large_green_strong.9.png b/res/drawable-large-hdpi/homescreen_large_green_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_large_green_strong.9.png
rename to res/drawable-large-hdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_blue.9.png b/res/drawable-large-hdpi/homescreen_small_blue.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_small_blue.9.png
rename to res/drawable-large-hdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_blue_strong.9.png b/res/drawable-large-hdpi/homescreen_small_blue_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_small_blue_strong.9.png
rename to res/drawable-large-hdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_green.9.png b/res/drawable-large-hdpi/homescreen_small_green.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_small_green.9.png
rename to res/drawable-large-hdpi/homescreen_small_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/homescreen_small_green_strong.9.png b/res/drawable-large-hdpi/homescreen_small_green_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/homescreen_small_green_strong.9.png
rename to res/drawable-large-hdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_generic_search.png b/res/drawable-large-hdpi/ic_generic_search.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_generic_search.png
rename to res/drawable-large-hdpi/ic_generic_search.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_all_apps_holo_dark.png b/res/drawable-large-hdpi/ic_home_all_apps_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_home_all_apps_holo_dark.png
rename to res/drawable-large-hdpi/ic_home_all_apps_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png b/res/drawable-large-hdpi/ic_home_info_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_home_info_holo_dark.png
rename to res/drawable-large-hdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_no_applications.png b/res/drawable-large-hdpi/ic_no_applications.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_no_applications.png
rename to res/drawable-large-hdpi/ic_no_applications.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/ic_voice_search.png b/res/drawable-large-hdpi/ic_voice_search.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/ic_voice_search.png
rename to res/drawable-large-hdpi/ic_voice_search.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_focused_holo.9.png b/res/drawable-large-hdpi/tab_selected_focused_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/tab_selected_focused_holo.9.png
rename to res/drawable-large-hdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_holo.9.png b/res/drawable-large-hdpi/tab_selected_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/tab_selected_holo.9.png
rename to res/drawable-large-hdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-large-hdpi/tab_selected_pressed_focused_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/tab_selected_pressed_focused_holo.9.png
rename to res/drawable-large-hdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/tab_selected_pressed_holo.9.png b/res/drawable-large-hdpi/tab_selected_pressed_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/tab_selected_pressed_holo.9.png
rename to res/drawable-large-hdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_frame_holo.9.png b/res/drawable-large-hdpi/widget_resize_frame_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/widget_resize_frame_holo.9.png
rename to res/drawable-large-hdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_bottom.png b/res/drawable-large-hdpi/widget_resize_handle_bottom.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/widget_resize_handle_bottom.png
rename to res/drawable-large-hdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_left.png b/res/drawable-large-hdpi/widget_resize_handle_left.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/widget_resize_handle_left.png
rename to res/drawable-large-hdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_right.png b/res/drawable-large-hdpi/widget_resize_handle_right.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/widget_resize_handle_right.png
rename to res/drawable-large-hdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-xlarge-hdpi/widget_resize_handle_top.png b/res/drawable-large-hdpi/widget_resize_handle_top.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/widget_resize_handle_top.png
rename to res/drawable-large-hdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/app_market_generic.png b/res/drawable-large-mdpi/app_market_generic.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/app_market_generic.png
rename to res/drawable-large-mdpi/app_market_generic.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/divider_launcher_holo.9.png b/res/drawable-large-mdpi/divider_launcher_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/divider_launcher_holo.9.png
rename to res/drawable-large-mdpi/divider_launcher_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_blue.9.png b/res/drawable-large-mdpi/homescreen_large_blue.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_large_blue.9.png
rename to res/drawable-large-mdpi/homescreen_large_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_green.9.png b/res/drawable-large-mdpi/homescreen_large_green.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_large_green.9.png
rename to res/drawable-large-mdpi/homescreen_large_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_large_green_strong.9.png b/res/drawable-large-mdpi/homescreen_large_green_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_large_green_strong.9.png
rename to res/drawable-large-mdpi/homescreen_large_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_blue.9.png b/res/drawable-large-mdpi/homescreen_small_blue.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_small_blue.9.png
rename to res/drawable-large-mdpi/homescreen_small_blue.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_blue_strong.9.png b/res/drawable-large-mdpi/homescreen_small_blue_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_small_blue_strong.9.png
rename to res/drawable-large-mdpi/homescreen_small_blue_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_green.9.png b/res/drawable-large-mdpi/homescreen_small_green.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_small_green.9.png
rename to res/drawable-large-mdpi/homescreen_small_green.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/homescreen_small_green_strong.9.png b/res/drawable-large-mdpi/homescreen_small_green_strong.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/homescreen_small_green_strong.9.png
rename to res/drawable-large-mdpi/homescreen_small_green_strong.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_generic_search.png b/res/drawable-large-mdpi/ic_generic_search.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_generic_search.png
rename to res/drawable-large-mdpi/ic_generic_search.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_add_holo_dark.png b/res/drawable-large-mdpi/ic_home_add_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_home_add_holo_dark.png
rename to res/drawable-large-mdpi/ic_home_add_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_all_apps_holo_dark.png b/res/drawable-large-mdpi/ic_home_all_apps_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_home_all_apps_holo_dark.png
rename to res/drawable-large-mdpi/ic_home_all_apps_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_no_applications.png b/res/drawable-large-mdpi/ic_no_applications.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_no_applications.png
rename to res/drawable-large-mdpi/ic_no_applications.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_voice_search.png b/res/drawable-large-mdpi/ic_voice_search.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_voice_search.png
rename to res/drawable-large-mdpi/ic_voice_search.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_focused_holo.9.png b/res/drawable-large-mdpi/tab_selected_focused_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/tab_selected_focused_holo.9.png
rename to res/drawable-large-mdpi/tab_selected_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_holo.9.png b/res/drawable-large-mdpi/tab_selected_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/tab_selected_holo.9.png
rename to res/drawable-large-mdpi/tab_selected_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_pressed_focused_holo.9.png b/res/drawable-large-mdpi/tab_selected_pressed_focused_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/tab_selected_pressed_focused_holo.9.png
rename to res/drawable-large-mdpi/tab_selected_pressed_focused_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/tab_selected_pressed_holo.9.png b/res/drawable-large-mdpi/tab_selected_pressed_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/tab_selected_pressed_holo.9.png
rename to res/drawable-large-mdpi/tab_selected_pressed_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_frame_holo.9.png b/res/drawable-large-mdpi/widget_resize_frame_holo.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/widget_resize_frame_holo.9.png
rename to res/drawable-large-mdpi/widget_resize_frame_holo.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_bottom.png b/res/drawable-large-mdpi/widget_resize_handle_bottom.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/widget_resize_handle_bottom.png
rename to res/drawable-large-mdpi/widget_resize_handle_bottom.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_left.png b/res/drawable-large-mdpi/widget_resize_handle_left.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/widget_resize_handle_left.png
rename to res/drawable-large-mdpi/widget_resize_handle_left.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_right.png b/res/drawable-large-mdpi/widget_resize_handle_right.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/widget_resize_handle_right.png
rename to res/drawable-large-mdpi/widget_resize_handle_right.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/widget_resize_handle_top.png b/res/drawable-large-mdpi/widget_resize_handle_top.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/widget_resize_handle_top.png
rename to res/drawable-large-mdpi/widget_resize_handle_top.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/all_apps_bg_gradient.9.png b/res/drawable-large-nodpi/all_apps_bg_gradient.9.png
similarity index 100%
rename from res/drawable-xlarge-nodpi/all_apps_bg_gradient.9.png
rename to res/drawable-large-nodpi/all_apps_bg_gradient.9.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bluecrystal.jpg b/res/drawable-large-nodpi/bluecrystal.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bluecrystal.jpg
rename to res/drawable-large-nodpi/bluecrystal.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bluecrystal_small.jpg b/res/drawable-large-nodpi/bluecrystal_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bluecrystal_small.jpg
rename to res/drawable-large-nodpi/bluecrystal_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bluelinebots.jpg b/res/drawable-large-nodpi/bluelinebots.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bluelinebots.jpg
rename to res/drawable-large-nodpi/bluelinebots.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bluelinebots_small.jpg b/res/drawable-large-nodpi/bluelinebots_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bluelinebots_small.jpg
rename to res/drawable-large-nodpi/bluelinebots_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bots.jpg b/res/drawable-large-nodpi/bots.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bots.jpg
rename to res/drawable-large-nodpi/bots.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bots_small.jpg b/res/drawable-large-nodpi/bots_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bots_small.jpg
rename to res/drawable-large-nodpi/bots_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bucky.jpg b/res/drawable-large-nodpi/bucky.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bucky.jpg
rename to res/drawable-large-nodpi/bucky.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/bucky_small.jpg b/res/drawable-large-nodpi/bucky_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/bucky_small.jpg
rename to res/drawable-large-nodpi/bucky_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/city.jpg b/res/drawable-large-nodpi/city.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/city.jpg
rename to res/drawable-large-nodpi/city.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/city_small.jpg b/res/drawable-large-nodpi/city_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/city_small.jpg
rename to res/drawable-large-nodpi/city_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/customize_bg_gradient.png b/res/drawable-large-nodpi/customize_bg_gradient.png
similarity index 100%
rename from res/drawable-xlarge-nodpi/customize_bg_gradient.png
rename to res/drawable-large-nodpi/customize_bg_gradient.png
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/flowerbot.jpg b/res/drawable-large-nodpi/flowerbot.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/flowerbot.jpg
rename to res/drawable-large-nodpi/flowerbot.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/flowerbot_small.jpg b/res/drawable-large-nodpi/flowerbot_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/flowerbot_small.jpg
rename to res/drawable-large-nodpi/flowerbot_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/glowy_hex.jpg b/res/drawable-large-nodpi/glowy_hex.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/glowy_hex.jpg
rename to res/drawable-large-nodpi/glowy_hex.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/glowy_hex_small.jpg b/res/drawable-large-nodpi/glowy_hex_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/glowy_hex_small.jpg
rename to res/drawable-large-nodpi/glowy_hex_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/lotus.jpg b/res/drawable-large-nodpi/lotus.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/lotus.jpg
rename to res/drawable-large-nodpi/lotus.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/lotus_small.jpg b/res/drawable-large-nodpi/lotus_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/lotus_small.jpg
rename to res/drawable-large-nodpi/lotus_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/village.jpg b/res/drawable-large-nodpi/village.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/village.jpg
rename to res/drawable-large-nodpi/village.jpg
Binary files differ
diff --git a/res/drawable-xlarge-nodpi/village_small.jpg b/res/drawable-large-nodpi/village_small.jpg
similarity index 100%
rename from res/drawable-xlarge-nodpi/village_small.jpg
rename to res/drawable-large-nodpi/village_small.jpg
Binary files differ
diff --git a/res/drawable-xlarge/delete_zone_selector.xml b/res/drawable-large/delete_zone_selector.xml
similarity index 100%
rename from res/drawable-xlarge/delete_zone_selector.xml
rename to res/drawable-large/delete_zone_selector.xml
diff --git a/res/drawable-mdpi/box_launcher_top_normal.9.png b/res/drawable-mdpi/box_launcher_top_normal.9.png
index 8adf2cf..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_normal.9.png
+++ b/res/drawable-mdpi/box_launcher_top_normal.9.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_top_pressed.9.png b/res/drawable-mdpi/box_launcher_top_pressed.9.png
index 7a20c54..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_pressed.9.png
+++ b/res/drawable-mdpi/box_launcher_top_pressed.9.png
Binary files differ
diff --git a/res/drawable-mdpi/box_launcher_top_selected.9.png b/res/drawable-mdpi/box_launcher_top_selected.9.png
index 9e636f0..af04b07 100644
--- a/res/drawable-mdpi/box_launcher_top_selected.9.png
+++ b/res/drawable-mdpi/box_launcher_top_selected.9.png
Binary files differ
diff --git a/res/drawable-mdpi/focused_bg.9.png b/res/drawable-mdpi/focused_bg.9.png
new file mode 100644
index 0000000..1b0d3fa
--- /dev/null
+++ b/res/drawable-mdpi/focused_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi/folder_bg.9.png b/res/drawable-mdpi/folder_bg.9.png
new file mode 100644
index 0000000..6f1bbe5
--- /dev/null
+++ b/res/drawable-mdpi/folder_bg.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/home_press.9.png b/res/drawable-mdpi/home_press.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/home_press.9.png
rename to res/drawable-mdpi/home_press.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_delete_holo_dark.png b/res/drawable-mdpi/ic_home_delete_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_home_delete_holo_dark.png
rename to res/drawable-mdpi/ic_home_delete_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_delete_hover_holo_dark.png b/res/drawable-mdpi/ic_home_delete_hover_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_home_delete_hover_holo_dark.png
rename to res/drawable-mdpi/ic_home_delete_hover_holo_dark.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/ic_home_info_holo_dark.png b/res/drawable-mdpi/ic_home_info_holo_dark.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/ic_home_info_holo_dark.png
rename to res/drawable-mdpi/ic_home_info_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/wallpaper_divider.png b/res/drawable-mdpi/wallpaper_divider.png
new file mode 100644
index 0000000..1b453c5
--- /dev/null
+++ b/res/drawable-mdpi/wallpaper_divider.png
Binary files differ
diff --git a/res/drawable-nodpi/apps_customize_bg_gradient.9.png b/res/drawable-nodpi/apps_customize_bg_gradient.9.png
new file mode 100644
index 0000000..e766bd6
--- /dev/null
+++ b/res/drawable-nodpi/apps_customize_bg_gradient.9.png
Binary files differ
diff --git a/res/drawable-xlarge/button_bg.xml b/res/drawable/button_bg.xml
similarity index 85%
rename from res/drawable-xlarge/button_bg.xml
rename to res/drawable/button_bg.xml
index 9e6e1ff..a830594 100644
--- a/res/drawable-xlarge/button_bg.xml
+++ b/res/drawable/button_bg.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -15,6 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:drawable="@drawable/focused_bg" />
     <item android:state_pressed="true" android:drawable="@drawable/home_press" />
     <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/res/drawable/delete_zone_selector.xml b/res/drawable/delete_zone_selector.xml
index 0c54b1d7..e2b37f4 100644
--- a/res/drawable/delete_zone_selector.xml
+++ b/res/drawable/delete_zone_selector.xml
@@ -19,6 +19,6 @@
 -->
 
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/trashcan"  />
-    <item android:drawable="@drawable/trashcan_hover"  />
+    <item android:drawable="@drawable/ic_home_delete_holo_dark"  />
+    <item android:drawable="@drawable/ic_home_delete_hover_holo_dark"  />
 </transition>
diff --git a/res/drawable-xlarge/button_bg.xml b/res/drawable/focusable_view_bg.xml
similarity index 77%
copy from res/drawable-xlarge/button_bg.xml
copy to res/drawable/focusable_view_bg.xml
index 9e6e1ff..66661e2 100644
--- a/res/drawable-xlarge/button_bg.xml
+++ b/res/drawable/focusable_view_bg.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -15,6 +15,5 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true" android:drawable="@drawable/home_press" />
-    <item android:drawable="@android:color/transparent" />
+    <item android:state_focused="true" android:drawable="@drawable/focused_bg" />
 </selector>
diff --git a/res/layout-land/all_apps_2d.xml b/res/layout-land/all_apps_2d.xml
deleted file mode 100644
index b7fcd45..0000000
--- a/res/layout-land/all_apps_2d.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Sapphire gets 2D all apps view -->
-<com.android.launcher2.AllApps2D
-    xmlns:android="http://schemas.android.com/apk/res/android"
-
-    android:id="@+id/all_apps_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:padding="2dip"
-    android:background="#FF000000">
-
-    <GridView android:id="@+id/all_apps_2d_grid"
-        android:tag="all_apps_2d_grid"
-        android:scrollbars="none"
-        android:drawSelectorOnTop="false"
-        android:listSelector="@drawable/grid_selector"
-        android:verticalSpacing="10dip"
-        android:numColumns="6"
-        android:fadingEdgeLength="48dip"
-        android:cacheColorHint="#FF000000"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentRight="true"
-        android:layout_marginRight="@dimen/button_bar_height_portrait"
-        android:nextFocusRight="@+id/all_apps_2d_home"
-        android:nextFocusUp="@null"
-        android:nextFocusLeft="@null"
-        android:nextFocusDown="@null"
-        />
-
-    <view
-        class="com.android.launcher2.AllApps2D$HomeButton"
-        android:id="@+id/all_apps_2d_home"
-        android:tag="all_apps_2d_home"
-        android:src="@drawable/home_button"
-        android:background="#FF000000"
-        android:layout_alignParentRight="true"
-        android:layout_centerVertical="true"
-        android:layout_height="wrap_content"
-        android:layout_width="@dimen/button_bar_height_portrait"
-        android:paddingBottom="@dimen/status_bar_height"
-        android:nextFocusLeft="@+id/all_apps_2d_grid"
-        android:nextFocusDown="@null"
-        android:nextFocusUp="@null"
-        android:nextFocusRight="@null"
-        />
-
-</com.android.launcher2.AllApps2D>
diff --git a/res/layout-land/application.xml b/res/layout-land/application.xml
index 6e8c31e..9ed1fa1 100644
--- a/res/layout-land/application.xml
+++ b/res/layout-land/application.xml
@@ -15,4 +15,6 @@
 -->
 
 <com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon.Landscape" />
+   style="@style/WorkspaceIcon.Landscape"
+   android:focusable="true"
+   android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 6e797f8..b2b2c9f 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -22,8 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <include layout="@layout/all_apps" />
-
     <!-- The workspace contains 5 screens of cells -->
     <com.android.launcher2.Workspace
         android:id="@+id/workspace"
@@ -43,6 +41,12 @@
 
     </com.android.launcher2.Workspace>
 
+    <include layout="@layout/apps_customize_pane"
+        android:id="@+id/apps_customize_pane"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <com.android.launcher2.ClippedImageView
         android:id="@+id/previous_screen"
         android:layout_width="93dip"
@@ -96,38 +100,26 @@
         android:layout_height="fill_parent"
         android:layout_width="@dimen/button_bar_height_portrait"
         android:layout_gravity="right|center_vertical"
-        android:layout_marginBottom="@dimen/half_status_bar_height"
-        >
-
+        android:layout_marginBottom="@dimen/half_status_bar_height">
+        <ImageView
+            android:id="@+id/hotseat_left"
+            style="@style/HotseatButton.Left"
+            android:layout_below="@id/all_apps_button"
+            android:src="@drawable/hotseat_phone"
+            android:onClick="launchHotSeat" />
         <com.android.launcher2.HandleView
             style="@style/HotseatButton"
             android:id="@+id/all_apps_button"
             android:layout_centerVertical="true"
             android:layout_alignParentRight="true"
-
             android:src="@drawable/all_apps_button"
-            launcher:direction="vertical"
-            />
-
-        <ImageView
-            android:id="@+id/hotseat_left"
-            style="@style/HotseatButton.Left"
-            android:layout_below="@id/all_apps_button"
-
-            android:src="@drawable/hotseat_phone"
-
-            android:onClick="launchHotSeat"
-            />
-
+            launcher:direction="vertical" />
         <ImageView
             android:id="@+id/hotseat_right"
             style="@style/HotseatButton.Right"
             android:layout_above="@id/all_apps_button"
-
             android:src="@drawable/hotseat_browser"
-
-            android:onClick="launchHotSeat"
-            />
+            android:onClick="launchHotSeat" />
 
     </RelativeLayout>
 </com.android.launcher2.DragLayer>
diff --git a/res/layout-land/user_folder.xml b/res/layout-land/user_folder.xml
index 5da4aa5..b814462 100644
--- a/res/layout-land/user_folder.xml
+++ b/res/layout-land/user_folder.xml
@@ -14,8 +14,11 @@
      limitations under the License.
 -->
 
-<com.android.launcher2.UserFolder xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical">
+<com.android.launcher2.Folder
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:orientation="vertical"
+    android:background="@drawable/folder_bg">
     
     <Button
         android:id="@+id/folder_close"
@@ -29,17 +32,23 @@
 
     <FrameLayout
          android:layout_width="match_parent"
-	   android:layout_height="0dip"
-         android:layout_weight="1"
-         android:background="@drawable/box_launcher_bottom">
+         android:layout_height="0dip"
+         android:layout_weight="1">
 
-        <GridView
+        <com.android.launcher2.CellLayout
              android:id="@id/folder_content"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
 
              android:cacheColorHint="#ff333333"
 
+             launcher:cellWidth="@dimen/folder_cell_width"
+             launcher:cellHeight="@dimen/folder_cell_height"
+             launcher:xAxisStartPadding="0dip"
+             launcher:xAxisEndPadding="0dip"
+             launcher:yAxisStartPadding="0dip"
+             launcher:yAxisEndPadding="0dip"
+
              android:scrollbarAlwaysDrawVerticalTrack="true"
              android:scrollbarStyle="insideInset"
              android:drawSelectorOnTop="false"
@@ -49,4 +58,4 @@
              android:numColumns="5" />
     </FrameLayout>
 
-</com.android.launcher2.UserFolder>
+</com.android.launcher2.Folder>
diff --git a/res/layout-xlarge-land/application.xml b/res/layout-large-land/application.xml
similarity index 85%
rename from res/layout-xlarge-land/application.xml
rename to res/layout-large-land/application.xml
index 2598e5a..9393f7e 100644
--- a/res/layout-xlarge-land/application.xml
+++ b/res/layout-large-land/application.xml
@@ -15,4 +15,6 @@
 -->
 
 <com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon.Landscape" />
+   style="@style/WorkspaceIcon.Landscape"
+   android:focusable="true"
+   android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-xlarge-land/workspace_screen.xml b/res/layout-large-land/workspace_screen.xml
similarity index 100%
rename from res/layout-xlarge-land/workspace_screen.xml
rename to res/layout-large-land/workspace_screen.xml
diff --git a/res/layout-xlarge-port/application.xml b/res/layout-large-port/application.xml
similarity index 100%
rename from res/layout-xlarge-port/application.xml
rename to res/layout-large-port/application.xml
diff --git a/res/layout-xlarge-port/workspace_screen.xml b/res/layout-large-port/workspace_screen.xml
similarity index 100%
rename from res/layout-xlarge-port/workspace_screen.xml
rename to res/layout-large-port/workspace_screen.xml
diff --git a/res/layout-xlarge/all_apps_no_items_placeholder.xml b/res/layout-large/all_apps_no_items_placeholder.xml
similarity index 94%
rename from res/layout-xlarge/all_apps_no_items_placeholder.xml
rename to res/layout-large/all_apps_no_items_placeholder.xml
index 247870c..b766df1 100644
--- a/res/layout-xlarge/all_apps_no_items_placeholder.xml
+++ b/res/layout-large/all_apps_no_items_placeholder.xml
@@ -32,4 +32,5 @@
     android:drawablePadding="0dip"
 
     android:maxLines="2"
-    android:fadingEdge="horizontal" />
+    android:fadingEdge="horizontal"
+    android:focusable="false" />
diff --git a/res/layout-xlarge/all_apps_paged_view_application.xml b/res/layout-large/all_apps_paged_view_application.xml
similarity index 89%
rename from res/layout-xlarge/all_apps_paged_view_application.xml
rename to res/layout-large/all_apps_paged_view_application.xml
index e5f07bf..16e5d82 100644
--- a/res/layout-xlarge/all_apps_paged_view_application.xml
+++ b/res/layout-large/all_apps_paged_view_application.xml
@@ -21,9 +21,12 @@
     launcher:blurColor="#FF6B8CF0"
     launcher:outlineColor="#FF8CD2FF"
 
+    style="@style/WorkspaceIcon.AllApps"
+
     android:id="@+id/application_icon"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal"
 
-    style="@style/WorkspaceIcon.AllApps" />
+    android:focusable="true"
+    android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-xlarge/all_apps_tabbed.xml b/res/layout-large/all_apps_tabbed.xml
similarity index 90%
rename from res/layout-xlarge/all_apps_tabbed.xml
rename to res/layout-large/all_apps_tabbed.xml
index 9937338..b00b3c3 100644
--- a/res/layout-xlarge/all_apps_tabbed.xml
+++ b/res/layout-large/all_apps_tabbed.xml
@@ -32,7 +32,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal"
             android:background="@drawable/tab_unselected_holo">
-            <TabWidget
+            <com.android.launcher2.FocusOnlyTabWidget
                 android:id="@android:id/tabs"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -50,7 +50,9 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_gravity="center"
-                    android:visibility="invisible"/>
+                    android:visibility="invisible"
+                    android:background="@drawable/focusable_view_bg"
+                    android:focusable="true" />
                 <TextView
                     android:id="@+id/market_button"
                     android:layout_width="wrap_content"
@@ -64,7 +66,9 @@
                     android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
                     android:shadowDx="0.0"
                     android:shadowDy="0.0"
-                    android:shadowRadius="2.0" />
+                    android:shadowRadius="2.0"
+                    android:background="@drawable/focusable_view_bg"
+                    android:focusable="true" />
             </FrameLayout>
             <com.android.launcher2.DeleteZone
                 android:id="@+id/all_apps_delete_zone"
@@ -84,7 +88,10 @@
                 android:shadowColor="@color/workspace_all_apps_and_delete_zone_text_shadow_color"
                 android:shadowDx="0.0"
                 android:shadowDy="0.0"
-                android:shadowRadius="2.0" />
+                android:shadowRadius="2.0"
+
+                android:background="@drawable/focusable_view_bg"
+                android:focusable="true" />
         </RelativeLayout>
         <FrameLayout
             android:id="@android:id/tabcontent"
diff --git a/res/layout-xlarge/button_bar.xml b/res/layout-large/button_bar.xml
similarity index 78%
rename from res/layout-xlarge/button_bar.xml
rename to res/layout-large/button_bar.xml
index 5c96c5c..62115f7 100644
--- a/res/layout-xlarge/button_bar.xml
+++ b/res/layout-large/button_bar.xml
@@ -15,31 +15,34 @@
 -->
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:focusable="false">
 
    <!-- Global search icon -->
    <ImageView
-       android:id="@+id/search_button"
-       android:layout_width="wrap_content"
-       android:layout_height="wrap_content"
-       android:layout_alignParentTop="true"
-       android:layout_alignParentLeft="true"
-       android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-       android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-       android:paddingTop="@dimen/toolbar_button_vertical_padding"
-       android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-       android:src="@drawable/ic_generic_search"
-       android:background="@drawable/button_bg"
-       android:onClick="onClickSearchButton"
-       android:focusable="true"
-       android:clickable="true" />
+        android:id="@+id/search_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:src="@drawable/ic_generic_search"
+        android:background="@drawable/button_bg"
+        android:onClick="onClickSearchButton"
+
+        android:focusable="true"
+        android:clickable="true"
+        android:contentDescription="@string/accessibility_search_button" />
 
     <ImageView
         android:id="@+id/search_divider"
         android:src="@drawable/divider_launcher_holo"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_toRightOf="@id/search_button"
+        android:layout_toRightOf="@+id/search_button"
         android:paddingTop="@dimen/toolbar_button_vertical_padding"
         android:paddingBottom="@dimen/toolbar_button_vertical_padding"
 
@@ -52,7 +55,7 @@
         android:id="@+id/voice_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_toRightOf="@id/search_divider"
+        android:layout_toRightOf="@+id/search_divider"
         android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
         android:paddingRight="@dimen/toolbar_button_horizontal_padding"
         android:paddingTop="@dimen/toolbar_button_vertical_padding"
@@ -60,35 +63,12 @@
         android:src="@drawable/ic_voice_search"
         android:background="@drawable/button_bg"
         android:onClick="onClickVoiceButton"
-        android:focusable="true"
-        android:clickable="true"/>
-
-    <ImageView
-        android:id="@+id/configure_button"
-        android:src="@drawable/ic_home_add_holo_dark"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        android:layout_alignParentRight="true"
-        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
-        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
-        android:paddingTop="@dimen/toolbar_button_vertical_padding"
-        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-        android:background="@drawable/button_bg"
 
         android:focusable="true"
-        android:clickable="true" />
-    <ImageView
-        android:id="@+id/divider"
-        android:src="@drawable/divider_launcher_holo"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_toLeftOf="@id/configure_button"
-        android:paddingTop="@dimen/toolbar_button_vertical_padding"
-        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:clickable="true"
+        android:contentDescription="@string/accessibility_voice_search_button" />
 
-        android:focusable="false"
-        android:clickable="true" />
+    <!-- AllApps icon -->
     <com.android.launcher2.StrokedTextView
         android:id="@+id/all_apps_button"
         android:text="@string/all_apps_button_label"
@@ -96,7 +76,7 @@
         android:drawableLeft="@drawable/ic_home_all_apps_holo_dark"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_toLeftOf="@id/divider"
+        android:layout_toLeftOf="@+id/all_apps_divider"
         android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
         android:paddingRight="@dimen/toolbar_button_horizontal_padding"
         android:paddingTop="@dimen/all_apps_button_vertical_padding"
@@ -117,16 +97,38 @@
         android:shadowRadius="2.5"
 
         android:focusable="true"
-        android:clickable="true" />
+        android:clickable="true"
+        android:contentDescription="@string/accessibility_all_apps_button" />
+
     <ImageView
-        android:id="@+id/divider_during_drag"
+        android:id="@+id/all_apps_divider"
         android:src="@drawable/divider_launcher_holo"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_toLeftOf="@id/configure_button"
+        android:layout_toLeftOf="@+id/configure_button"
         android:paddingTop="@dimen/toolbar_button_vertical_padding"
         android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-        android:visibility="gone" />
+
+        android:focusable="false"
+        android:clickable="true" />
+
+    <!-- Customize icon -->
+    <ImageView
+        android:id="@+id/configure_button"
+        android:src="@drawable/ic_home_add_holo_dark"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentRight="true"
+        android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
+        android:paddingRight="@dimen/toolbar_button_horizontal_padding"
+        android:paddingTop="@dimen/toolbar_button_vertical_padding"
+        android:paddingBottom="@dimen/toolbar_button_vertical_padding"
+        android:background="@drawable/button_bg"
+        android:focusable="true"
+        android:contentDescription="@string/accessibility_customize_button" />
+
+    <!-- Delete icon -->
     <com.android.launcher2.DeleteZone
         android:id="@+id/delete_zone"
         android:text="@string/delete_zone_label_workspace"
@@ -134,12 +136,12 @@
         android:drawableLeft="@drawable/delete_zone_selector"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_alignRight="@id/configure_button"
+        android:layout_alignRight="@+id/configure_button"
         android:paddingLeft="@dimen/toolbar_button_horizontal_padding"
         android:paddingRight="@dimen/toolbar_button_horizontal_padding"
         android:paddingTop="@dimen/toolbar_button_vertical_padding"
         android:paddingBottom="@dimen/toolbar_button_vertical_padding"
-        android:background="@drawable/button_bg"
+       android:background="@drawable/button_bg"
 
         android:gravity="center_horizontal|center_vertical"
         android:textColor="@color/workspace_all_apps_and_delete_zone_text_color"
@@ -150,5 +152,8 @@
         android:shadowRadius="2.0"
 
         android:visibility="gone"
-        launcher:direction="horizontal" />
-</RelativeLayout>
\ No newline at end of file
+        launcher:direction="horizontal"
+
+        android:focusable="true"
+        android:contentDescription="@string/accessibility_delete_button" />
+</RelativeLayout>
diff --git a/res/layout-xlarge/customization_drawer.xml b/res/layout-large/customization_drawer.xml
similarity index 91%
rename from res/layout-xlarge/customization_drawer.xml
rename to res/layout-large/customization_drawer.xml
index 98fc9d9..d8db066 100644
--- a/res/layout-xlarge/customization_drawer.xml
+++ b/res/layout-large/customization_drawer.xml
@@ -22,7 +22,7 @@
         android:layout_height="match_parent">
         <!-- The layout_width of this RelativeLayout gets overwritten in
              CustomizeTrayTabHost.onFinishInflate -->
-        <TabWidget
+        <com.android.launcher2.FocusOnlyTabWidget
             android:id="@android:id/tabs"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
@@ -32,7 +32,7 @@
         <FrameLayout
             android:id="@android:id/tabcontent"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/customization_drawer_content_height">
+            android:layout_height="match_parent">
             <com.android.launcher2.CustomizePagedView
                 android:id="@+id/customization_drawer_tab_contents"
                 android:layout_width="match_parent"
@@ -47,7 +47,8 @@
                 launcher:pageLayoutPaddingTop="40dp"
                 launcher:pageLayoutPaddingBottom="25dp"
                 launcher:pageLayoutPaddingLeft="20dp"
-                launcher:pageLayoutPaddingRight="20dp" />
+                launcher:pageLayoutPaddingRight="20dp"
+                launcher:pageLayoutMaxHeight="@dimen/customization_drawer_content_height" />
          </FrameLayout>
       </LinearLayout>
 </com.android.launcher2.CustomizeTrayTabHost>
\ No newline at end of file
diff --git a/res/layout-xlarge/customize_paged_view_item.xml b/res/layout-large/customize_paged_view_item.xml
similarity index 88%
rename from res/layout-xlarge/customize_paged_view_item.xml
rename to res/layout-large/customize_paged_view_item.xml
index b2e5f08..80d678e 100644
--- a/res/layout-xlarge/customize_paged_view_item.xml
+++ b/res/layout-large/customize_paged_view_item.xml
@@ -25,4 +25,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
 
-    style="@style/WorkspaceIcon.Landscape" />
+    style="@style/WorkspaceIcon.Landscape"
+
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true" />
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper.xml b/res/layout-large/customize_paged_view_wallpaper.xml
similarity index 94%
rename from res/layout-xlarge/customize_paged_view_wallpaper.xml
rename to res/layout-large/customize_paged_view_wallpaper.xml
index 8c5abc8..d6284c2 100644
--- a/res/layout-xlarge/customize_paged_view_wallpaper.xml
+++ b/res/layout-large/customize_paged_view_wallpaper.xml
@@ -25,7 +25,10 @@
     android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
-    launcher:outlineColor="#FF8CD2FF">
+    launcher:outlineColor="#FF8CD2FF"
+
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true">
 
     <!-- The preview image for the wallpaper. -->
     <ImageView
diff --git a/res/layout-xlarge/customize_paged_view_widget.xml b/res/layout-large/customize_paged_view_widget.xml
similarity index 95%
rename from res/layout-xlarge/customize_paged_view_widget.xml
rename to res/layout-large/customize_paged_view_widget.xml
index c0b4552..35791f5 100644
--- a/res/layout-xlarge/customize_paged_view_widget.xml
+++ b/res/layout-large/customize_paged_view_widget.xml
@@ -25,7 +25,10 @@
     android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
-    launcher:outlineColor="#FF8CD2FF">
+    launcher:outlineColor="#FF8CD2FF"
+
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true">
 
     <!-- The icon of the widget. -->
     <ImageView
diff --git a/res/layout-xlarge/external_widget_drop_list_item.xml b/res/layout-large/external_widget_drop_list_item.xml
similarity index 100%
rename from res/layout-xlarge/external_widget_drop_list_item.xml
rename to res/layout-large/external_widget_drop_list_item.xml
diff --git a/res/layout-xlarge/launcher.xml b/res/layout-large/launcher.xml
similarity index 91%
rename from res/layout-xlarge/launcher.xml
rename to res/layout-large/launcher.xml
index acf62f9..6c6fecf 100644
--- a/res/layout-xlarge/launcher.xml
+++ b/res/layout-large/launcher.xml
@@ -20,7 +20,8 @@
 
     android:id="@+id/drag_layer"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:focusable="false">
 
     <!-- The workspace contains 5 screens of cells -->
     <com.android.launcher2.Workspace
@@ -41,22 +42,24 @@
         <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
     </com.android.launcher2.Workspace>
 
-    <include
-        layout="@layout/all_apps_tabbed"
-        android:id="@+id/all_apps_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="top" />
-
     <include layout="@layout/button_bar"
         android:id="@+id/all_apps_button_cluster"
         android:layout_width="fill_parent"
         android:layout_height="?android:attr/actionBarSize"
         android:layout_gravity="top" />
 
+    <include
+        layout="@layout/all_apps_tabbed"
+        android:id="@+id/all_apps_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="top"
+        android:visibility="invisible" />
+
     <include layout="@layout/customization_drawer"
         android:id="@+id/customization_drawer"
         android:layout_width="match_parent"
         android:layout_height="@dimen/customization_drawer_height"
-        android:layout_gravity="bottom" />
+        android:layout_gravity="bottom"
+        android:visibility="invisible" />
 </com.android.launcher2.DragLayer>
diff --git a/res/layout-xlarge/tab_widget_indicator.xml b/res/layout-large/tab_widget_indicator.xml
similarity index 89%
rename from res/layout-xlarge/tab_widget_indicator.xml
rename to res/layout-large/tab_widget_indicator.xml
index 7794e29..c09c853 100644
--- a/res/layout-xlarge/tab_widget_indicator.xml
+++ b/res/layout-large/tab_widget_indicator.xml
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<TextView
+<com.android.launcher2.AccessibleTabView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TabIndicator" />
+    style="@style/TabIndicator.Wide" />
diff --git a/res/layout-xlarge/wallpaper_chooser.xml b/res/layout-large/wallpaper_chooser.xml
similarity index 100%
rename from res/layout-xlarge/wallpaper_chooser.xml
rename to res/layout-large/wallpaper_chooser.xml
diff --git a/res/layout-xlarge/wallpaper_chooser_base.xml b/res/layout-large/wallpaper_chooser_base.xml
similarity index 100%
rename from res/layout-xlarge/wallpaper_chooser_base.xml
rename to res/layout-large/wallpaper_chooser_base.xml
diff --git a/res/layout-xlarge/wallpaper_item.xml b/res/layout-large/wallpaper_item.xml
similarity index 100%
rename from res/layout-xlarge/wallpaper_item.xml
rename to res/layout-large/wallpaper_item.xml
diff --git a/res/layout-port/all_apps_2d.xml b/res/layout-port/all_apps_2d.xml
deleted file mode 100644
index 081cba2..0000000
--- a/res/layout-port/all_apps_2d.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Sapphire gets 2D all apps view -->
-<com.android.launcher2.AllApps2D
-    xmlns:android="http://schemas.android.com/apk/res/android"
-
-    android:id="@+id/all_apps_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:padding="2dip"
-    android:background="#FF000000">
-
-    <GridView android:id="@+id/all_apps_2d_grid"
-        android:tag="all_apps_2d_grid"
-        android:scrollbars="none"
-        android:drawSelectorOnTop="false"
-        android:listSelector="@drawable/grid_selector"
-        android:verticalSpacing="10dip"
-        android:numColumns="4"
-        android:fadingEdgeLength="48dip"
-        android:cacheColorHint="#FF000000"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_alignParentBottom="true"
-        android:layout_marginBottom="@dimen/button_bar_height"
-        android:layout_marginTop="8dip"
-        android:nextFocusDown="@+id/all_apps_2d_home"
-        android:nextFocusUp="@null"
-        android:nextFocusLeft="@null"
-        android:nextFocusRight="@null"
-        />
-
-    <view
-        class="com.android.launcher2.AllApps2D$HomeButton"
-        android:id="@+id/all_apps_2d_home"
-        android:tag="all_apps_2d_home"
-        android:src="@drawable/home_button"
-        android:background="#FF000000"
-        android:layout_centerHorizontal="true"
-        android:layout_alignParentBottom="true"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/button_bar_height"
-        android:nextFocusUp="@+id/all_apps_2d_grid"
-        android:nextFocusDown="@null"
-        android:nextFocusLeft="@null"
-        android:nextFocusRight="@null"
-        />
-
-</com.android.launcher2.AllApps2D>
diff --git a/res/layout-port/application.xml b/res/layout-port/application.xml
index 32c1510..ddc8354 100644
--- a/res/layout-port/application.xml
+++ b/res/layout-port/application.xml
@@ -15,4 +15,6 @@
 -->
 
 <com.android.launcher2.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
-   style="@style/WorkspaceIcon.Portrait" />
+   style="@style/WorkspaceIcon.Portrait"
+   android:focusable="true"
+   android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index b7c61d8..c7bcbb0 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -22,8 +22,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <include layout="@layout/all_apps" />
-
     <!-- The workspace contains 5 screens of cells -->
     <com.android.launcher2.Workspace
         android:id="@+id/workspace"
@@ -41,6 +39,12 @@
                 
     </com.android.launcher2.Workspace>
 
+    <include layout="@layout/apps_customize_pane"
+        android:id="@+id/apps_customize_pane"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible" />
+
     <ImageView
         android:id="@+id/previous_screen"
         android:layout_width="93dip"
@@ -89,39 +93,26 @@
         android:layout_width="fill_parent"
         android:layout_height="@dimen/button_bar_height"
         android:layout_gravity="bottom|center_horizontal"
-        android:paddingTop="2dip"
-        >
-
+        android:paddingTop="2dip">
+        <ImageView
+            android:id="@+id/hotseat_left"
+            style="@style/HotseatButton.Left"
+            android:layout_toLeftOf="@id/all_apps_button"
+            android:src="@drawable/hotseat_phone"
+            android:onClick="launchHotSeat" />
         <com.android.launcher2.HandleView
             style="@style/HotseatButton"
             android:id="@+id/all_apps_button"
             android:layout_centerHorizontal="true"
             android:layout_alignParentBottom="true"
-
             android:src="@drawable/all_apps_button"
-            launcher:direction="horizontal"
-            />
-
-        <ImageView
-            android:id="@+id/hotseat_left"
-            style="@style/HotseatButton.Left"
-            android:layout_toLeftOf="@id/all_apps_button"
-
-            android:src="@drawable/hotseat_phone"
-
-            android:onClick="launchHotSeat"
-            />
-
+            launcher:direction="horizontal" />
         <ImageView
             android:id="@+id/hotseat_right"
             style="@style/HotseatButton.Right"
             android:layout_toRightOf="@id/all_apps_button"
-
             android:src="@drawable/hotseat_browser"
-
-            android:onClick="launchHotSeat"
-            />
-
+            android:onClick="launchHotSeat" />
     </RelativeLayout>
 
 </com.android.launcher2.DragLayer>
diff --git a/res/layout-port/user_folder.xml b/res/layout-port/user_folder.xml
index 0e6df66..4901eb2 100644
--- a/res/layout-port/user_folder.xml
+++ b/res/layout-port/user_folder.xml
@@ -14,12 +14,15 @@
      limitations under the License.
 -->
 
-<com.android.launcher2.UserFolder xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical">
-        
+<com.android.launcher2.Folder
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
+    android:orientation="vertical"
+    android:background="@drawable/folder_bg">
+
     <Button
         android:id="@+id/folder_close"
-   		android:background="@drawable/box_launcher_top"
+	android:background="@drawable/box_launcher_top"
         android:gravity="left|center_vertical"
         android:textSize="14sp"
         android:textColor="#404040"
@@ -29,23 +32,30 @@
 
     <FrameLayout
          android:layout_width="match_parent"
-	   android:layout_height="0dip"
-         android:layout_weight="1"
-         android:background="@drawable/box_launcher_bottom">
-        <GridView
+         android:layout_height="0dip"
+         android:layout_weight="1">
+
+        <com.android.launcher2.CellLayout
              android:id="@id/folder_content"
              android:layout_width="match_parent"
-	       android:layout_height="match_parent"
+             android:layout_height="match_parent"
 
              android:cacheColorHint="#ff333333"
 
+             launcher:cellWidth="@dimen/folder_cell_width"
+             launcher:cellHeight="@dimen/folder_cell_height"
+             launcher:xAxisStartPadding="0dip"
+             launcher:xAxisEndPadding="0dip"
+             launcher:yAxisStartPadding="0dip"
+             launcher:yAxisEndPadding="0dip"
+
              android:scrollbarAlwaysDrawVerticalTrack="true"
              android:scrollbarStyle="insideInset"
              android:drawSelectorOnTop="false"
              android:listSelector="@drawable/grid_selector"
 
              android:verticalSpacing="10dip"
-             android:numColumns="4" />
+             android:numColumns="5" />
     </FrameLayout>
 
-</com.android.launcher2.UserFolder>
+</com.android.launcher2.Folder>
diff --git a/res/layout-xlarge-port/tab_widget_indicator.xml b/res/layout-xlarge-port/tab_widget_indicator.xml
deleted file mode 100644
index b113b7b..0000000
--- a/res/layout-xlarge-port/tab_widget_indicator.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TabIndicator.Portrait" />
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
deleted file mode 100644
index fadf736..0000000
--- a/res/layout/all_apps.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- switch to all_apps_3d on devices that support RenderScript -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/all_apps_2d" />
-</merge>
diff --git a/res/layout/all_apps_3d.xml b/res/layout/all_apps_3d.xml
deleted file mode 100644
index 7975df4..0000000
--- a/res/layout/all_apps_3d.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Replace with AllAppsView to use 2D version -->
-<com.android.launcher2.AllApps3D
-    xmlns:android="http://schemas.android.com/apk/res/android"
-
-    android:id="@+id/all_apps_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-
-    android:scrollbarStyle="outsideInset"
-    android:drawSelectorOnTop="false"
-    android:listSelector="@drawable/grid_selector"
-    android:verticalSpacing="10dip"
-    android:numColumns="4"
-    android:fadingEdgeLength="20dip"
-    android:padding="2dip"
-    android:cacheColorHint="#FF000000"
-    />
diff --git a/res/layout/application_list.xml b/res/layout/application_list.xml
deleted file mode 100644
index b515c9e..0000000
--- a/res/layout/application_list.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright (c) 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="?android:attr/listPreferredItemHeight"
-
-    android:paddingLeft="10dip"
-
-    android:orientation="horizontal">
-
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@android:dimen/app_icon_size"
-        android:layout_height="@android:dimen/app_icon_size"
-        android:layout_gravity="center_vertical"
-        android:scaleType="fitCenter" />
-
-    <LinearLayout
-        android:layout_width="0dip"
-        android:layout_weight="1.0"
-        android:layout_height="match_parent"
-
-        android:paddingLeft="8dip"
-        android:paddingRight="8dip"
-
-        android:orientation="vertical"
-        android:gravity="center_vertical">
-
-        <TextView android:id="@+id/name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-
-            android:singleLine="true"
-            android:ellipsize="end"
-
-            android:textAppearance="?android:attr/textAppearanceLarge" />
-
-        <TextView android:id="@+id/description"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-
-            android:layout_below="@id/name"
-            android:layout_alignLeft="@id/name"
-
-            android:singleLine="true"
-            android:ellipsize="end"
-
-            android:textAppearance="?android:attr/textAppearanceSmall"
-            android:textColor="?android:attr/textColorSecondary" />
-
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/res/layout-xlarge/all_apps_paged_view_application.xml b/res/layout/apps_customize_application.xml
similarity index 84%
copy from res/layout-xlarge/all_apps_paged_view_application.xml
copy to res/layout/apps_customize_application.xml
index e5f07bf..4f36326 100644
--- a/res/layout-xlarge/all_apps_paged_view_application.xml
+++ b/res/layout/apps_customize_application.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -18,12 +18,15 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
-    launcher:blurColor="#FF6B8CF0"
-    launcher:outlineColor="#FF8CD2FF"
+    style="@style/WorkspaceIcon.AllApps"
 
     android:id="@+id/application_icon"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:gravity="center_horizontal"
 
-    style="@style/WorkspaceIcon.AllApps" />
+    launcher:blurColor="#FF6B8CF0"
+    launcher:outlineColor="#FF8CD2FF"
+
+    android:focusable="true"
+    android:background="@drawable/focusable_view_bg" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
new file mode 100644
index 0000000..05884ef
--- /dev/null
+++ b/res/layout/apps_customize_pane.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher2.AppsCustomizeTabHost
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/apps_customize_bg_gradient">
+        <!-- The layout_width of the tab bar gets overriden to align the content
+             with the text in the tabs in AppsCustomizeTabHost. -->
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/apps_customize_tab_bar_height"
+            android:layout_gravity="center_horizontal">
+            <com.android.launcher2.FocusOnlyTabWidget
+                android:id="@android:id/tabs"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="left"
+                android:background="@drawable/tab_unselected_holo"
+                android:tabStripEnabled="false" />
+            <FrameLayout
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="right">
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:visibility="gone">
+                    <com.android.launcher2.ApplicationInfoDropTarget
+                        android:id="@+id/all_apps_info_target"
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:layout_gravity="center"
+                        android:gravity="center"
+                        android:drawableLeft="@drawable/ic_home_info_holo_dark"
+                        android:background="@drawable/focusable_view_bg"
+                        android:focusable="true"
+                        android:visibility="gone" />
+                    <com.android.launcher2.DeleteZone
+                        style="@style/DeleteZone"
+                        android:id="@+id/all_apps_delete_zone"
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:layout_gravity="center"
+                        android:gravity="center"
+                        android:background="@drawable/focusable_view_bg"
+                        android:focusable="true"
+                        android:visibility="gone"
+                        launcher:direction="horizontal" />
+                </LinearLayout>
+                <TextView
+                    style="@style/MarketButton"
+                    android:id="@+id/market_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:layout_gravity="center"
+                    android:gravity="center"
+                    android:background="@drawable/tab_widget_indicator_selector"
+                    android:focusable="true" />
+            </FrameLayout>
+        </FrameLayout>
+        <FrameLayout
+            android:id="@android:id/tabcontent"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <com.android.launcher2.AppsCustomizePagedView
+                android:id="@+id/apps_customize_pane_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                launcher:cellCountX="@integer/all_apps_view_cellCountX"
+                launcher:cellCountY="@integer/all_apps_view_cellCountY"
+                launcher:pageLayoutWidthGap="@dimen/all_apps_view_pageLayoutWidthGap"
+                launcher:pageLayoutHeightGap="@dimen/all_apps_view_pageLayoutHeightGap"
+                launcher:pageLayoutPaddingTop="@dimen/all_apps_view_pageLayoutPaddingTop"
+                launcher:pageLayoutPaddingBottom="@dimen/all_apps_view_pageLayoutPaddingBottom"
+                launcher:pageLayoutPaddingLeft="@dimen/all_apps_view_pageLayoutPaddingLeft"
+                launcher:pageLayoutPaddingRight="@dimen/all_apps_view_pageLayoutPaddingRight"
+                launcher:widgetCellWidthGap="@dimen/apps_customize_widget_cell_width_gap"
+                launcher:widgetCellHeightGap="@dimen/apps_customize_widget_cell_height_gap"
+                launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
+                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
+                launcher:wallpaperCountX="@integer/apps_customize_wallpaper_cell_count_x"
+                launcher:wallpaperCountY="@integer/apps_customize_wallpaper_cell_count_y" />
+         </FrameLayout>
+      </LinearLayout>
+</com.android.launcher2.AppsCustomizeTabHost>
diff --git a/res/layout-xlarge/customize_paged_view_wallpaper.xml b/res/layout/apps_customize_wallpaper.xml
similarity index 77%
copy from res/layout-xlarge/customize_paged_view_wallpaper.xml
copy to res/layout/apps_customize_wallpaper.xml
index 8c5abc8..d93825f 100644
--- a/res/layout-xlarge/customize_paged_view_wallpaper.xml
+++ b/res/layout/apps_customize_wallpaper.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -17,22 +17,24 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_weight="1"
     android:orientation="vertical"
-    android:paddingRight="25dp"
-    android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
-    launcher:outlineColor="#FF8CD2FF">
+    launcher:outlineColor="#FF8CD2FF"
 
-    <!-- The preview image for the wallpaper. -->
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true">
+
+    <!-- The wallpaper preview. -->
     <ImageView
-        android:id="@+id/wallpaper_preview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:id="@+id/widget_preview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         android:layout_weight="1"
+        android:paddingBottom="10dp"
         android:adjustViewBounds="true"
         android:scaleType="fitStart" />
 
@@ -46,13 +48,13 @@
         android:paddingBottom="10dp"
         android:src="@drawable/widget_divider" />
 
-    <!-- The name of the wallpaper -->
+    <!-- The name of the wallpaper. -->
     <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/wallpaper_name"
+        android:id="@+id/widget_name"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="0"
-        android:gravity="left"
+        android:gravity="left|bottom"
 
         android:textColor="#FFFFFFFF"
         android:textSize="14sp"
diff --git a/res/layout-xlarge/customize_paged_view_widget.xml b/res/layout/apps_customize_widget.xml
similarity index 76%
copy from res/layout-xlarge/customize_paged_view_widget.xml
copy to res/layout/apps_customize_widget.xml
index c0b4552..9d0764c 100644
--- a/res/layout-xlarge/customize_paged_view_widget.xml
+++ b/res/layout/apps_customize_widget.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -17,42 +17,34 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
 
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:layout_weight="1"
     android:orientation="vertical"
-    android:paddingRight="25dp"
-    android:paddingBottom="50dp"
 
     launcher:blurColor="#FF6B8CF0"
-    launcher:outlineColor="#FF8CD2FF">
+    launcher:outlineColor="#FF8CD2FF"
+
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true">
 
     <!-- The icon of the widget. -->
     <ImageView
         android:id="@+id/widget_preview"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         android:layout_weight="1"
+        android:paddingBottom="5dp"
         android:adjustViewBounds="true"
         android:scaleType="fitStart" />
 
-    <!-- The divider image. -->
-    <ImageView
-        android:id="@+id/divider"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_weight="0"
-        android:paddingTop="10dp"
-        android:paddingBottom="10dp"
-        android:src="@drawable/widget_divider" />
-
     <!-- The name of the widget. -->
     <TextView xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/widget_name"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="0"
-        android:gravity="left"
+        android:gravity="left|bottom"
 
         android:textColor="#FFFFFFFF"
         android:textSize="14sp"
@@ -71,7 +63,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_weight="0"
-        android:gravity="left"
+        android:gravity="left|bottom"
 
         android:textColor="#FF999999"
         android:textSize="14sp"
diff --git a/res/layout-xlarge/tab_widget_indicator.xml b/res/layout/tab_widget_indicator.xml
similarity index 87%
copy from res/layout-xlarge/tab_widget_indicator.xml
copy to res/layout/tab_widget_indicator.xml
index 7794e29..b3694fe 100644
--- a/res/layout-xlarge/tab_widget_indicator.xml
+++ b/res/layout/tab_widget_indicator.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
+<!-- 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.
@@ -14,6 +14,6 @@
      limitations under the License.
 -->
 
-<TextView
+<com.android.launcher2.AccessibleTabView
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/TabIndicator" />
diff --git a/res/values-ar-xlarge/strings.xml b/res/values-ar-large/strings.xml
similarity index 100%
rename from res/values-ar-xlarge/strings.xml
rename to res/values-ar-large/strings.xml
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index df0a210..cb4c1f3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"الرئيسية"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"إزالة"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"إزالة"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"بحث"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"البحث الصوتي"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"التطبيقات"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"تخصيص"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"إزالة"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"إزالة التحديث"</string>
     <string name="menu_add" msgid="3065046628354640854">"إضافة"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"إدارة التطبيقات"</string>
diff --git a/res/values-bg-xlarge/strings.xml b/res/values-bg-large/strings.xml
similarity index 100%
rename from res/values-bg-xlarge/strings.xml
rename to res/values-bg-large/strings.xml
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5be82f1..0f0f07d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Начало"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Премахване"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталиране"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Търсене"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Гласово търсене"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Приложения"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Персонализиране"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Премахване"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинстал. на актуализацията"</string>
     <string name="menu_add" msgid="3065046628354640854">"Добавяне"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Управление на приложенията"</string>
diff --git a/res/values-ca-xlarge/strings.xml b/res/values-ca-large/strings.xml
similarity index 100%
rename from res/values-ca-xlarge/strings.xml
rename to res/values-ca-large/strings.xml
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 56ada67..85058ba 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Pàgina d\'inici"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Elimina"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstal·la"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Cerca"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Cerca per veu"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicacions"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalitza"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Elimina"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstal·la l\'actualització"</string>
     <string name="menu_add" msgid="3065046628354640854">"Afegeix"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestiona les aplicacions"</string>
diff --git a/res/values-cs-xlarge/strings.xml b/res/values-cs-large/strings.xml
similarity index 100%
rename from res/values-cs-xlarge/strings.xml
rename to res/values-cs-large/strings.xml
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 47fb726..af04cb6 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Plocha"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odebrat"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstalovat"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Hledat"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hlasové vyhledávání"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikace"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizovat"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Odebrat"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstalovat aktualizaci"</string>
     <string name="menu_add" msgid="3065046628354640854">"Přidat"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Spravovat aplikace"</string>
diff --git a/res/values-da-xlarge/strings.xml b/res/values-da-large/strings.xml
similarity index 100%
rename from res/values-da-xlarge/strings.xml
rename to res/values-da-large/strings.xml
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index f481234..10bd77f 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Start"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Afinstaller"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Søg"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Stemmesøgning"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programmer"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Tilpas"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Fjern"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Afinstaller opdatering"</string>
     <string name="menu_add" msgid="3065046628354640854">"Tilføj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
diff --git a/res/values-de-xlarge/strings.xml b/res/values-de-large/strings.xml
similarity index 100%
rename from res/values-de-xlarge/strings.xml
rename to res/values-de-large/strings.xml
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index fdb2a41..87124a3 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startseite"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Entfernen"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstallieren"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Suchen"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Sprachsuche"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Apps"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Anpassen"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Entfernen"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update deinstallieren"</string>
     <string name="menu_add" msgid="3065046628354640854">"Hinzufügen"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Apps verwalten"</string>
diff --git a/res/values-el-xlarge/strings.xml b/res/values-el-large/strings.xml
similarity index 100%
rename from res/values-el-xlarge/strings.xml
rename to res/values-el-large/strings.xml
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 5e9b644..59ef926 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Αρχική σελίδα"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Κατάργηση"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Κατάργηση εγκατάστασης"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Αναζήτηση"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Φωνητική αναζήτηση"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Εφαρμογές"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Προσαρμογή"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Κατάργηση"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Κατάργηση εγκατάστασης ενημέρωσης"</string>
     <string name="menu_add" msgid="3065046628354640854">"Προσθήκη"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Διαχείριση εφαρμογών"</string>
diff --git a/res/values-en-rGB-xlarge/strings.xml b/res/values-en-rGB-large/strings.xml
similarity index 100%
rename from res/values-en-rGB-xlarge/strings.xml
rename to res/values-en-rGB-large/strings.xml
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 7334133..f07752c 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remove"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Uninstall"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Search"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Voice Search"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applications"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Customise"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Remove"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Uninstall update"</string>
     <string name="menu_add" msgid="3065046628354640854">"Add"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Manage apps"</string>
diff --git a/res/values-es-xlarge/strings.xml b/res/values-es-large/strings.xml
similarity index 100%
rename from res/values-es-xlarge/strings.xml
rename to res/values-es-large/strings.xml
diff --git a/res/values-es-rUS-xlarge/strings.xml b/res/values-es-rUS-large/strings.xml
similarity index 100%
rename from res/values-es-rUS-xlarge/strings.xml
rename to res/values-es-rUS-large/strings.xml
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index eadcbae..46781f1 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página principal"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Quitar"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Buscar"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Búsqueda por voz"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaciones"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminar"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar la actualización"</string>
     <string name="menu_add" msgid="3065046628354640854">"Agregar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 90b4e1d..3d162b9 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Inicio"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminar del  escritorio"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Buscar"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Búsqueda por voz"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaciones"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminar"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar actualización"</string>
     <string name="menu_add" msgid="3065046628354640854">"Añadir"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrar aplicaciones"</string>
diff --git a/res/values-fa-xlarge/strings.xml b/res/values-fa-large/strings.xml
similarity index 100%
rename from res/values-fa-xlarge/strings.xml
rename to res/values-fa-large/strings.xml
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 0d53ea5..1170d79 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"صفحه اصلی"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"حذف"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"حذف نصب"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"جستجو"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"جستجوی صوتی"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"برنامه های کاربردی"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"سفارشی کردن"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"حذف"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"حذف نصب به روزرسانی"</string>
     <string name="menu_add" msgid="3065046628354640854">"افزودن"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"مدیریت برنامه ها"</string>
diff --git a/res/values-fi-xlarge/strings.xml b/res/values-fi-large/strings.xml
similarity index 100%
rename from res/values-fi-xlarge/strings.xml
rename to res/values-fi-large/strings.xml
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 7b02c8d..4e40e56 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Etusivu"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Poista"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Poista"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Haku"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Äänihaku"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Sovellukset"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Muokkaa"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Poista"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Poista päivitys"</string>
     <string name="menu_add" msgid="3065046628354640854">"Lisää"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Hallinnoi sovelluksia"</string>
diff --git a/res/values-fr-xlarge/strings.xml b/res/values-fr-large/strings.xml
similarity index 100%
rename from res/values-fr-xlarge/strings.xml
rename to res/values-fr-large/strings.xml
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 7ff39d7..83d71d8 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Page d\'accueil"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Supprimer"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Désinstaller"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Rechercher"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Recherche vocale"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applications"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personnaliser"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Supprimer"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Désinstaller la mise à jour"</string>
     <string name="menu_add" msgid="3065046628354640854">"Ajouter"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gérer les applications"</string>
diff --git a/res/values-hr-xlarge/strings.xml b/res/values-hr-large/strings.xml
similarity index 100%
rename from res/values-hr-xlarge/strings.xml
rename to res/values-hr-large/strings.xml
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index ea09db0..34487a5 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Početna"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ukloni"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Deinstaliraj"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Pretraži"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Glasovno pretraživanje"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikacije"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Prilagodi"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Ukloni"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Deinstalacija ažuriranja"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj aplikacijama"</string>
diff --git a/res/values-hu-xlarge/strings.xml b/res/values-hu-large/strings.xml
similarity index 100%
rename from res/values-hu-xlarge/strings.xml
rename to res/values-hu-large/strings.xml
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 77d9dda..dfa267b 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Főoldal"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eltávolítás"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Eltávolítás"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Keresés"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hangalapú keresés"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Alkalmazások"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Személyre szabás"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Törlés"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Eltávolítja a frissítést"</string>
     <string name="menu_add" msgid="3065046628354640854">"Hozzáadás"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Alkalmazások kezelése"</string>
diff --git a/res/values-in-xlarge/strings.xml b/res/values-in-large/strings.xml
similarity index 100%
rename from res/values-in-xlarge/strings.xml
rename to res/values-in-large/strings.xml
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index a7ed856..d9a6d28 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Rumah"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Hapus"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Copot pemasangan"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Telusuri"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Penelusuran Suara"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikasi"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Ubahsuaikan"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Hapus"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Copot pemasangan pemutakhiran"</string>
     <string name="menu_add" msgid="3065046628354640854">"Tambahkan"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Mengelola aplikasi"</string>
diff --git a/res/values-it-xlarge/strings.xml b/res/values-it-large/strings.xml
similarity index 100%
rename from res/values-it-xlarge/strings.xml
rename to res/values-it-large/strings.xml
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 003db6f..0a1f4fd 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Rimuovi"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Disinstalla"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Cerca"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Ricerca vocale"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applicazioni"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizza"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Rimuovi"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Disinstalla aggiornamento"</string>
     <string name="menu_add" msgid="3065046628354640854">"Aggiungi"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestisci applicazioni"</string>
diff --git a/res/values-iw-xlarge/strings.xml b/res/values-iw-large/strings.xml
similarity index 100%
rename from res/values-iw-xlarge/strings.xml
rename to res/values-iw-large/strings.xml
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 75df245..535cf73 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"דף הבית"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"הסר"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"הסר התקנה"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"חפש"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"חיפוש קולי"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"יישומים"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"התאם אישית"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"הסר"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"הסר את התקנת העדכון"</string>
     <string name="menu_add" msgid="3065046628354640854">"הוסף"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"נהל יישומים"</string>
diff --git a/res/values-ja-xlarge/strings.xml b/res/values-ja-large/strings.xml
similarity index 100%
rename from res/values-ja-xlarge/strings.xml
rename to res/values-ja-large/strings.xml
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index ee6ab83..4b2d31d 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"ホーム"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"削除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"アンインストール"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"検索"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"音声検索"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"アプリケーション"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"カスタマイズ"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"削除"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"アップデートをアンインストール"</string>
     <string name="menu_add" msgid="3065046628354640854">"追加"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"アプリの管理"</string>
diff --git a/res/values-ko-xlarge/strings.xml b/res/values-ko-large/strings.xml
similarity index 100%
rename from res/values-ko-xlarge/strings.xml
rename to res/values-ko-large/strings.xml
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index f2b8b0c..9f6ee4a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"홈"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"삭제"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"제거"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"검색"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"음성 검색"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"애플리케이션"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"맞춤설정"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"삭제"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"업데이트 제거"</string>
     <string name="menu_add" msgid="3065046628354640854">"추가"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"애플리케이션 관리"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 159cbb4..e1b0214 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -17,5 +17,23 @@
 <resources>
     <dimen name="workspace_cell_width">106dip</dimen>
     <dimen name="workspace_cell_height">74dip</dimen>
+    <dimen name="folder_cell_width">100dip</dimen>
+    <dimen name="folder_cell_height">74dip</dimen>
     <dimen name="button_bar_height">62dip</dimen>
+
+    <integer name="all_apps_view_cellCountX">6</integer>
+    <integer name="all_apps_view_cellCountY">3</integer>
+    <dimen name="all_apps_view_pageLayoutWidthGap">10dp</dimen>
+    <dimen name="all_apps_view_pageLayoutHeightGap">5dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingTop">10dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingBottom">10dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingLeft">2dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingRight">2dp</dimen>
+
+    <dimen name="apps_customize_widget_cell_width_gap">30dp</dimen>
+    <dimen name="apps_customize_widget_cell_height_gap">0dp</dimen>
+    <integer name="apps_customize_widget_cell_count_x">3</integer>
+    <integer name="apps_customize_widget_cell_count_y">1</integer>
+    <integer name="apps_customize_wallpaper_cell_count_x">3</integer>
+    <integer name="apps_customize_wallpaper_cell_count_y">1</integer>
 </resources>
diff --git a/res/values-xlarge-land/dimens.xml b/res/values-large-land/dimens.xml
similarity index 93%
rename from res/values-xlarge-land/dimens.xml
rename to res/values-large-land/dimens.xml
index b44a94a..8d25555 100644
--- a/res/values-xlarge-land/dimens.xml
+++ b/res/values-large-land/dimens.xml
@@ -27,8 +27,6 @@
 
     <dimen name="customization_drawer_height">480dp</dimen>
     <dimen name="customization_drawer_content_height">420dp</dimen>
-    <dimen name="customization_drawer_content_min_width">952dp</dimen>
-    <dimen name="customization_drawer_tab_widget_width">952dp</dimen>
 
     <integer name="all_apps_view_cellCountX">7</integer>
     <integer name="all_apps_view_cellCountY">5</integer>
diff --git a/res/values-xlarge-port/dimens.xml b/res/values-large-port/dimens.xml
similarity index 93%
rename from res/values-xlarge-port/dimens.xml
rename to res/values-large-port/dimens.xml
index bb410b1..e696e34 100644
--- a/res/values-xlarge-port/dimens.xml
+++ b/res/values-large-port/dimens.xml
@@ -27,8 +27,6 @@
 
     <dimen name="customization_drawer_height">800dp</dimen>
     <dimen name="customization_drawer_content_height">420dp</dimen>
-    <dimen name="customization_drawer_content_min_width">640dp</dimen>
-    <dimen name="customization_drawer_tab_widget_width">700dp</dimen>
 
     <integer name="all_apps_view_cellCountX">5</integer>
     <integer name="all_apps_view_cellCountY">7</integer>
diff --git a/res/values-large/config.xml b/res/values-large/config.xml
new file mode 100644
index 0000000..99ee1ec
--- /dev/null
+++ b/res/values-large/config.xml
@@ -0,0 +1,32 @@
+<resources>
+<!-- AllApps/Customize/AppsCustomize -->
+    <!-- Fade/zoom in/out duration & scale in the Customize transition.
+         Note: This should be less than the workspaceShrinkTime as they happen together. -->
+    <integer name="config_customizeZoomInTime">800</integer>
+    <integer name="config_customizeZoomOutTime">600</integer>
+    <integer name="config_customizeZoomScaleFactor">7</integer>
+    <integer name="config_customizeFadeInTime">800</integer>
+
+    <!-- The slope, in percent, of the drag movement needed to drag an item out of
+         Customize (y / x * 100%)  -->
+    <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
+
+    <!-- Duration in milliseconds of the animations between all apps, customize, & home.
+         NOTE: If these are changed, the toolbar animation times below should also be. -->
+    <integer name="config_customizeWorkspaceShrinkTime">800</integer>
+
+<!-- Workspace -->
+    <!-- When dragging items on the workspace, how much bigger (in pixels) the dragged view
+         should be, as compared to the original view. If 0, it will not be scaled at all.
+         Should be an even number, for pixel alignment. -->
+    <integer name="config_dragViewExtraPixels">0</integer>
+
+    <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
+         of the bright green hover outline, and then fade out the outline at the end. These are
+         the values used in that animation -->
+    <integer name="config_screenOnDropScalePercent">120</integer>
+    <integer name="config_screenOnDropScaleUpDuration">200</integer>
+    <integer name="config_screenOnDropScaleDownDuration">200</integer>
+    <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
+    <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
+</resources>
diff --git a/res/values-xlarge/dimens.xml b/res/values-large/dimens.xml
similarity index 88%
rename from res/values-xlarge/dimens.xml
rename to res/values-large/dimens.xml
index 2b97697..11f85ab 100644
--- a/res/values-xlarge/dimens.xml
+++ b/res/values-large/dimens.xml
@@ -15,6 +15,8 @@
 -->
 
 <resources>
+    <dimen name="apps_customize_cell_width">96dp</dimen>
+    <dimen name="apps_customize_cell_height">96dp</dimen>
     <dimen name="workspace_cell_width">96dip</dimen>
     <dimen name="workspace_cell_height">96dip</dimen>
 
@@ -40,7 +42,6 @@
     <dimen name="allAppsSmallScreenVerticalMarginLandscape">30dip</dimen>
     <dimen name="allAppsSmallScreenVerticalMarginPortrait">60dip</dimen>
 
-    <dimen name="delete_zone_drawable_padding">8dip</dimen>
     <dimen name="all_apps_button_drawable_padding">0dip</dimen>
     <dimen name="all_apps_button_vertical_padding">4dip</dimen>
 
@@ -62,4 +63,9 @@
     <!-- How much the content view of an alert dialog should be inset (currently used
         for the WallpaperChooser in XLarge mode) -->
     <dimen name="alert_dialog_content_inset">0dp</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">-12dp</dimen>
 </resources>
diff --git a/res/values-xlarge/strings.xml b/res/values-large/strings.xml
similarity index 100%
rename from res/values-xlarge/strings.xml
rename to res/values-large/strings.xml
diff --git a/res/values-xlarge/styles.xml b/res/values-large/styles.xml
similarity index 78%
rename from res/values-xlarge/styles.xml
rename to res/values-large/styles.xml
index 7208d97..bcbe038 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-large/styles.xml
@@ -41,4 +41,16 @@
         <item name="android:paddingTop">0dip</item>
         <item name="android:includeFontPadding">false</item>
     </style>
+
+    <style name="TabIndicator.Wide">
+        <item name="android:paddingLeft">40dp</item>
+        <item name="android:paddingRight">40dp</item>
+        <item name="android:paddingTop">15dp</item>
+        <item name="android:paddingBottom">20dp</item>
+        <item name="android:textSize">20sp</item>
+    </style>
+
+    <style name="config_orientation">
+        <item name="@android:screenOrientation">unspecified</item>
+    </style>
 </resources>
diff --git a/res/values-xlarge/wallpapers.xml b/res/values-large/wallpapers.xml
similarity index 100%
rename from res/values-xlarge/wallpapers.xml
rename to res/values-large/wallpapers.xml
diff --git a/res/values-lt-xlarge/strings.xml b/res/values-lt-large/strings.xml
similarity index 100%
rename from res/values-lt-xlarge/strings.xml
rename to res/values-lt-large/strings.xml
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index acf0e27..e84360d 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Pagrindinis"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Pašalinti"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Pašalinti"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Ieškoti"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Balso paieška"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programos"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Tinkinti"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Pašalinti"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Pašalinti naujinį"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pridėti"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Valdyti programas"</string>
diff --git a/res/values-lv-xlarge/strings.xml b/res/values-lv-large/strings.xml
similarity index 100%
rename from res/values-lv-xlarge/strings.xml
rename to res/values-lv-large/strings.xml
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 9c1b389..963c332 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Sākums"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Noņemt"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Atinstalēt"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Meklēt"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Balss meklēšana"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Lietojumprogrammas"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Pielāgot"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Noņemt"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Atinstalēt atjauninājumu"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pievienot"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Lietotņu pārvaldība"</string>
diff --git a/res/values-nb-xlarge/strings.xml b/res/values-nb-large/strings.xml
similarity index 100%
rename from res/values-nb-xlarge/strings.xml
rename to res/values-nb-large/strings.xml
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index ccdab7e..382bac4 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsiden"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Fjern"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstaller"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Søk"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Talesøk"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Applikasjoner"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Tilpass"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Fjern"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstaller oppdateringen"</string>
     <string name="menu_add" msgid="3065046628354640854">"Legg til"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Administrer programmer"</string>
diff --git a/res/values-nl-xlarge/strings.xml b/res/values-nl-large/strings.xml
similarity index 100%
rename from res/values-nl-xlarge/strings.xml
rename to res/values-nl-large/strings.xml
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 3d7c7ac..abcf29a 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startpagina"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Verwijderen"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Verwijderen"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Zoeken"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Spraakgestuurd zoeken"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Apps"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Aanpassen"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Verwijderen"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Update verwijderen"</string>
     <string name="menu_add" msgid="3065046628354640854">"Toevoegen"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Apps beheren"</string>
diff --git a/res/values-pl-xlarge/strings.xml b/res/values-pl-large/strings.xml
similarity index 100%
rename from res/values-pl-xlarge/strings.xml
rename to res/values-pl-large/strings.xml
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f116165..97b54af 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Ekran główny"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Usuń"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinstaluj"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Szukaj"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Wyszukiwanie głosowe"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikacje"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Dostosuj"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Usuń"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinstaluj aktualizację"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Zarządzaj aplikacjami"</string>
diff --git a/res/values-port/dimens.xml b/res/values-port/dimens.xml
index 65a3fd3..7d50c1a 100644
--- a/res/values-port/dimens.xml
+++ b/res/values-port/dimens.xml
@@ -17,4 +17,22 @@
 <resources>
     <dimen name="workspace_cell_width">80dip</dimen>
     <dimen name="workspace_cell_height">100dip</dimen>
+    <dimen name="folder_cell_width">74dip</dimen>
+    <dimen name="folder_cell_height">86dip</dimen>
+
+    <integer name="all_apps_view_cellCountX">4</integer>
+    <integer name="all_apps_view_cellCountY">5</integer>
+    <dimen name="all_apps_view_pageLayoutWidthGap">3dp</dimen>
+    <dimen name="all_apps_view_pageLayoutHeightGap">12dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingTop">15dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingBottom">15dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingLeft">0dp</dimen>
+    <dimen name="all_apps_view_pageLayoutPaddingRight">0dp</dimen>
+
+    <dimen name="apps_customize_widget_cell_width_gap">20dp</dimen>
+    <dimen name="apps_customize_widget_cell_height_gap">40dp</dimen>
+    <integer name="apps_customize_widget_cell_count_x">2</integer>
+    <integer name="apps_customize_widget_cell_count_y">2</integer>
+    <integer name="apps_customize_wallpaper_cell_count_x">1</integer>
+    <integer name="apps_customize_wallpaper_cell_count_y">1</integer>
 </resources>
diff --git a/res/values-pt-xlarge/strings.xml b/res/values-pt-large/strings.xml
similarity index 100%
rename from res/values-pt-xlarge/strings.xml
rename to res/values-pt-large/strings.xml
diff --git a/res/values-pt-rPT-xlarge/strings.xml b/res/values-pt-rPT-large/strings.xml
similarity index 100%
rename from res/values-pt-rPT-xlarge/strings.xml
rename to res/values-pt-rPT-large/strings.xml
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index a3a5a8d..71f634d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Pesquisar"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Pesquisa por Voz"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicações"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Remover"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gerir aplicações"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 55deb94..2714fde 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Página inicial"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Remover"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Desinstalar"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Pesquisar"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Pesquisa por voz"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicativos"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizar"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Remover"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Desinstalar atualização"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adicionar"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gerenciar aplicativos"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 1b5729b..a8453ed 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -85,6 +85,16 @@
     <skip />
     <!-- no translation found for delete_zone_label_all_apps (6664588234817475108) -->
     <skip />
+    <!-- no translation found for accessibility_search_button (816822994629942611) -->
+    <skip />
+    <!-- no translation found for accessibility_voice_search_button (3938249215065842475) -->
+    <skip />
+    <!-- no translation found for accessibility_all_apps_button (1595097919145716305) -->
+    <skip />
+    <!-- no translation found for accessibility_customize_button (585539669413531163) -->
+    <skip />
+    <!-- no translation found for accessibility_delete_button (3628162007991023603) -->
+    <skip />
     <!-- no translation found for delete_zone_label_all_apps_system_app (3683920959591819044) -->
     <skip />
     <string name="menu_add" msgid="3065046628354640854">"Agiuntar"</string>
diff --git a/res/values-ro-xlarge/strings.xml b/res/values-ro-large/strings.xml
similarity index 100%
rename from res/values-ro-xlarge/strings.xml
rename to res/values-ro-large/strings.xml
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 3a72c51..6bed5d0 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Domiciliu"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Eliminaţi"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Dezinstalaţi"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Căutaţi"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Căutare vocală"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplicaţii"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Personalizaţi"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Eliminaţi"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Dezinstalaţi actualizarea"</string>
     <string name="menu_add" msgid="3065046628354640854">"Adăugaţi"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Gestionaţi aplicaţii"</string>
diff --git a/res/values-ru-xlarge/strings.xml b/res/values-ru-large/strings.xml
similarity index 100%
rename from res/values-ru-xlarge/strings.xml
rename to res/values-ru-large/strings.xml
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 912c3f4..0456e4c 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Главная"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Удалить"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Удалить"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Поиск"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Голосовой поиск"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Приложения"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Настроить"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Удалить"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Удалить обновление"</string>
     <string name="menu_add" msgid="3065046628354640854">"Добавить"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Приложения"</string>
diff --git a/res/values-sk-xlarge/strings.xml b/res/values-sk-large/strings.xml
similarity index 100%
rename from res/values-sk-xlarge/strings.xml
rename to res/values-sk-large/strings.xml
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 3cadf3b..064309d 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Domovská stránka"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrániť"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odinštalovať"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Hľadať"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Hlasové vyhľadávanie"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Aplikácie"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Prispôsobiť"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Odstrániť"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odinštalovať aktualizáciu"</string>
     <string name="menu_add" msgid="3065046628354640854">"Pridať"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Spravovať aplikácie"</string>
diff --git a/res/values-sl-xlarge/strings.xml b/res/values-sl-large/strings.xml
similarity index 100%
rename from res/values-sl-xlarge/strings.xml
rename to res/values-sl-large/strings.xml
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index daf0899..78b5187 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Začetni zaslon"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Odstrani"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Odstrani"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Išči"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Glasovno iskanje"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Programi"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Prilagodi"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Odstrani"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Odstrani posodobitev"</string>
     <string name="menu_add" msgid="3065046628354640854">"Dodaj"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Upravljaj programe"</string>
diff --git a/res/values-sr-xlarge/strings.xml b/res/values-sr-large/strings.xml
similarity index 100%
rename from res/values-sr-xlarge/strings.xml
rename to res/values-sr-large/strings.xml
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 1d92080..cbc4bf2 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Почетна"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Уклони"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Деинсталирај"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Претражи"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Гласовна претрага"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Апликације"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Прилагоди"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Уклони"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Деинсталирај ажурирања"</string>
     <string name="menu_add" msgid="3065046628354640854">"Додај"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Управљање апликацијама"</string>
diff --git a/res/values-sv-xlarge/strings.xml b/res/values-sv-large/strings.xml
similarity index 100%
rename from res/values-sv-xlarge/strings.xml
rename to res/values-sv-large/strings.xml
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8094f05..68859e3 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Startsida"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Ta bort"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Avinstallera"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Sök"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Röstsökning"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Appar"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Anpassa"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Ta bort"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Avinstallera uppdatering"</string>
     <string name="menu_add" msgid="3065046628354640854">"Lägg till"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Hantera appar"</string>
diff --git a/res/values-th-xlarge/strings.xml b/res/values-th-large/strings.xml
similarity index 100%
rename from res/values-th-xlarge/strings.xml
rename to res/values-th-large/strings.xml
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 26c33c9..1562135 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"บ้าน"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"นำออก"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"ถอนการติดตั้ง"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"ค้นหา"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Voice Search"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"แอปพลิเคชัน"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"กำหนดค่า"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"ลบ"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"ถอนการติดตั้งการอัปเดต"</string>
     <string name="menu_add" msgid="3065046628354640854">"เพิ่ม"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"จัดการแอปพลิเคชัน"</string>
diff --git a/res/values-tl-xlarge/strings.xml b/res/values-tl-large/strings.xml
similarity index 100%
rename from res/values-tl-xlarge/strings.xml
rename to res/values-tl-large/strings.xml
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index f21dc3c..50ed317 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Home"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Alisin"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"I-uninstall"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Maghanap"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Paghahanap gamit ang Boses"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Mga Application"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"I-customize"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Alisin"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"I-uninstall ang update"</string>
     <string name="menu_add" msgid="3065046628354640854">"Idagdag"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Pamahalaan ang apps"</string>
diff --git a/res/values-tr-xlarge/strings.xml b/res/values-tr-large/strings.xml
similarity index 100%
rename from res/values-tr-xlarge/strings.xml
rename to res/values-tr-large/strings.xml
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index bf80bf5..2057828 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Ana Sayfa"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Kaldır"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Yüklemeyi Kaldır"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Ara"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Sesli Arama"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Uygulamalar"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Özelleştir"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Kaldır"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Güncelleme kaldırılsın mı?"</string>
     <string name="menu_add" msgid="3065046628354640854">"Ekle"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Uyglm yönet"</string>
diff --git a/res/values-uk-xlarge/strings.xml b/res/values-uk-large/strings.xml
similarity index 100%
rename from res/values-uk-xlarge/strings.xml
rename to res/values-uk-large/strings.xml
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 267ca88..b3f0846 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Головна"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Видалити"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Видалити"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Пошук"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Голосовий пошук"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Програми"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Налаштувати"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Видалити"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Видалити оновлення"</string>
     <string name="menu_add" msgid="3065046628354640854">"Додати"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Керув. прогр."</string>
diff --git a/res/values-vi-xlarge/strings.xml b/res/values-vi-large/strings.xml
similarity index 100%
rename from res/values-vi-xlarge/strings.xml
rename to res/values-vi-large/strings.xml
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index d3f549f..9238c4a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"Màn hình trang chủ"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"Xóa"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"Gỡ cài đặt"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"Tìm kiếm"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"Tìm kiếm bằng giọng nói"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"Ứng dụng"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"Tùy chỉnh"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"Xóa"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"Gỡ cài đặt cập nhật"</string>
     <string name="menu_add" msgid="3065046628354640854">"Thêm"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"Quản lý ứng dụng"</string>
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
deleted file mode 100644
index 56c7bc6..0000000
--- a/res/values-xlarge/config.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<resources>
-    <!--  NOTE: Many of the all apps values here are also used for the customization drawer -->
-
-    <!-- Duration in milliseconds of the fade-in/out of the icons as they are being dragged
-         from the AllApps or Customization trays -->
-    <integer name="icon_allAppsCustomizeFadeInTime">150</integer>
-    <integer name="icon_allAppsCustomizeFadeOutTime">200</integer>
-    <integer name="icon_allAppsCustomizeFadeAlpha">102</integer>
-
-    <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
-    <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
-    <integer name="config_allAppsZoomInTime">1000</integer>
-    <integer name="config_allAppsFadeInTime">250</integer>
-
-    <!-- Duration in milliseconds of the transition between tabs in the all apps/customize
-         tray -->
-    <integer name="config_tabTransitionTime">100</integer>
-
-    <!-- Duration in milliseconds of the all apps zoom-out animation -->
-    <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
-    <integer name="config_allAppsZoomOutTime">1200</integer>
-
-    <!-- Scaling factor used in the all apps zooming animations -->
-    <integer name="config_allAppsZoomScaleFactor">20</integer>
-
-    <!-- Duration in milliseconds of the all apps / configuration zoom-in animation. -->
-    <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
-    <integer name="config_customizeZoomInTime">800</integer>
-    <integer name="config_customizeFadeInTime">800</integer>
-
-    <!-- Duration in milliseconds of the all apps zoom-out animation -->
-    <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
-    <integer name="config_customizeZoomOutTime">600</integer>
-
-    <!-- Scaling factor used in the all apps zooming animations -->
-    <integer name="config_customizeZoomScaleFactor">7</integer>
-
-    <!-- Duration in milliseconds of the animations between all apps, customize, & home.
-         NOTE: If these are changed, the toolbar animation times below should also be. -->
-    <integer name="config_allAppsFadeOutTime">500</integer>
-    <integer name="config_customizeWorkspaceShrinkTime">800</integer>
-    <integer name="config_allAppsWorkspaceShrinkTime">1000</integer>
-    <integer name="config_workspaceUnshrinkTime">650</integer>
-
-    <!-- Duration in milliseconds toolbar fade in and fade out animations.
-         NOTE: Fade in and fade out time should together be less the transition
-         animations between all apps, customize, & the workspace. -->
-    <integer name="config_toolbarButtonFadeInTime">350</integer>
-    <integer name="config_toolbarButtonFadeOutTime">200</integer>
-
-    <!-- When dragging items on the workspace, how much bigger (in pixels) the dragged view
-         should be, as compared to the original view. If 0, it will not be scaled at all.
-         Should be an even number, for pixel alignment. -->
-    <integer name="config_dragViewExtraPixels">0</integer>
-
-    <!-- When dragging items on the workspace, the number of pixels by which the position of
-         the drag view should be offset from the position of the original view. -->
-    <integer name="config_dragViewOffsetX">0</integer>
-    <integer name="config_dragViewOffsetY">-12</integer>
-
-    <!-- When items are dropped on the mini screens in customize mode, we have a bounce animation
-         of the bright green hover outline, and then fade out the outline at the end. These are
-         the values used in that animation -->
-    <integer name="config_screenOnDropScalePercent">120</integer>
-    <integer name="config_screenOnDropScaleUpDuration">200</integer>
-    <integer name="config_screenOnDropScaleDownDuration">200</integer>
-    <integer name="config_screenOnDropAlphaFadeDelay">350</integer>
-    <integer name="config_screenOnDropAlphaFadeDuration">50</integer>
-
-    <!-- The slope, in percent, of the drag movement needed to drag an item out of the customization
-         drawer (y / x * 100%)  -->
-    <integer name="config_customizationDrawerDragSlopeThreshold">150</integer>
-    <integer name="config_allAppsDrawerDragSlopeThreshold">150</integer>
-
-    <style name="config_orientation">
-        <item name="@android:screenOrientation">unspecified</item>
-    </style>
-</resources>
diff --git a/res/values-zh-rCN-xlarge/strings.xml b/res/values-zh-rCN-large/strings.xml
similarity index 100%
rename from res/values-zh-rCN-xlarge/strings.xml
rename to res/values-zh-rCN-large/strings.xml
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index a3dc212..b2f228c 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"主屏幕"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"删除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"卸载"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"搜索"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"语音搜索"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"应用程序"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"自定义"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"删除"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"卸载更新"</string>
     <string name="menu_add" msgid="3065046628354640854">"添加"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"管理应用程序"</string>
diff --git a/res/values-zh-rTW-xlarge/strings.xml b/res/values-zh-rTW-large/strings.xml
similarity index 100%
rename from res/values-zh-rTW-xlarge/strings.xml
rename to res/values-zh-rTW-large/strings.xml
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 2274274..f172ef6 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -67,6 +67,11 @@
     <string name="all_apps_home_button_label" msgid="1022222300329398558">"主螢幕"</string>
     <string name="delete_zone_label_workspace" msgid="7153615831493049150">"移除"</string>
     <string name="delete_zone_label_all_apps" msgid="6664588234817475108">"解除安裝"</string>
+    <string name="accessibility_search_button" msgid="816822994629942611">"搜尋"</string>
+    <string name="accessibility_voice_search_button" msgid="3938249215065842475">"語音搜尋"</string>
+    <string name="accessibility_all_apps_button" msgid="1595097919145716305">"應用程式"</string>
+    <string name="accessibility_customize_button" msgid="585539669413531163">"自訂"</string>
+    <string name="accessibility_delete_button" msgid="3628162007991023603">"移除"</string>
     <string name="delete_zone_label_all_apps_system_app" msgid="3683920959591819044">"解除安裝更新"</string>
     <string name="menu_add" msgid="3065046628354640854">"新增"</string>
     <string name="menu_manage_apps" msgid="2308685199463588895">"管理應用程式"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 2be5999..75b93bf 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -104,10 +104,28 @@
         <attr name="pageLayoutPaddingBottom" format="dimension" />
         <attr name="pageLayoutPaddingLeft" format="dimension" />
         <attr name="pageLayoutPaddingRight" format="dimension" />
+        <attr name="pageLayoutMaxHeight" format="dimension" />
         <!-- The space between adjacent pages of the PagedView. -->
         <attr name="pageSpacing" format="dimension" />
     </declare-styleable>
 
+    <!-- AppsCustomizePagedView specific attributes.  These attributes are used to
+         customize an AppsCustomizePagedView in xml files. -->
+    <declare-styleable name="AppsCustomizePagedView">
+        <!-- Horizontal spacing between widgets and wallpapers -->
+        <attr name="widgetCellWidthGap" format="dimension" />
+        <!-- Vertical spacing between widgets -->
+        <attr name="widgetCellHeightGap" format="dimension" />
+        <!-- Number of widgets horizontally -->
+        <attr name="widgetCountX" format="integer" />
+        <!-- Number of widgets vertically -->
+        <attr name="widgetCountY" format="integer" />
+        <!-- Number of wallpaper pickers horizontally -->
+        <attr name="wallpaperCountX" format="integer" />
+        <!-- Number of wallpaper pickers vertically -->
+        <attr name="wallpaperCountY" format="integer" />
+    </declare-styleable>
+
     <!-- CustomizePagedView specific attributes. These attributes are used to customize
          a CustomizePagedView view in XML files. -->
     <declare-styleable name="CustomizePagedView">
diff --git a/res/values/config.xml b/res/values/config.xml
index c56a8ce..0aa1ee4 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,10 +1,41 @@
 <resources>
-    <integer name="config_allAppsFadeInTime">700</integer>
-    <integer name="config_allAppsFadeOutTime">700</integer>
-    <integer name="config_allAppsBatchLoadDelay">0</integer>
-    <integer name="config_allAppsBatchSize">0</integer>
+<!-- System -->
     <bool name="config_hardwareAccelerated">false</bool>
 
+<!-- AllApps/Customize/AppsCustomize -->
+    <!-- Fade in/out duration of icons being dragged from the trays -->
+    <integer name="config_dragAppsCustomizeIconFadeInDuration">150</integer>
+    <integer name="config_dragAppsCustomizeIconFadeOutDuration">200</integer>
+    <integer name="config_dragAppsCustomizeIconFadeAlpha">100</integer>
+    <integer name="config_workspaceUnshrinkTime">650</integer>
+
+    <!-- Fade/zoom in/out duration & scale in the AllApps transition.
+         Note: This should be less than the workspaceShrinkTime as they happen together. -->
+    <integer name="config_appsCustomizeZoomInTime">1000</integer>
+    <integer name="config_appsCustomizeZoomOutTime">1200</integer>
+    <integer name="config_appsCustomizeZoomScaleFactor">20</integer>
+    <integer name="config_appsCustomizeFadeInTime">250</integer>
+    <integer name="config_appsCustomizeFadeOutTime">500</integer>
+    <integer name="config_appsCustomizeWorkspaceShrinkTime">1000</integer>
+
+    <!-- Tab transition animation duration -->
+    <integer name="config_tabTransitionDuration">100</integer>
+
+    <!-- The slope, in percent, of the drag movement needed to drag an item out of
+         AppsCustomize (y / x * 100%)  -->
+    <integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
+
+    <!-- Fade in/out duration of toolbar/button bar icons.
+         Note: In + Out duration together should be less the duration of the transition
+               between AllApps, Customize & the Workspace. -->
+    <integer name="config_toolbarButtonFadeInTime">350</integer>
+    <integer name="config_toolbarButtonFadeOutTime">200</integer>
+
+    <!-- Batch loading for loading in LauncherModel -->
+    <integer name="config_allAppsBatchLoadDelay">0</integer>
+    <integer name="config_allAppsBatchSize">0</integer>
+
+<!-- Workspace -->
     <integer name="config_crosshairsFadeInTime">600</integer>
 
     <!--  When dragging an item on the workspace, how much bigger (in pixels) the dragged view
@@ -12,12 +43,6 @@
           Should be an even number, for pixel alignment. -->
     <integer name="config_dragViewExtraPixels">40</integer>
 
-    <!-- When dragging items on the workspace, the number of pixels by which the position of
-         the drag view should be offset from the position of the original view.
-         Setting to 1/2 of config_dragViewExtraPixels keeps it centered on its old position. -->
-    <integer name="config_dragViewOffsetX">20</integer>
-    <integer name="config_dragViewOffsetY">20</integer>
-
     <!-- The duration (in ms) of the fade animation on the object outlines, used when
          we are dragging objects around on the home screen. -->
     <integer name="config_dragOutlineFadeTime">900</integer>
@@ -30,6 +55,9 @@
 
     <integer name="config_dropAnimMaxDuration">400</integer>
 
+    <!-- The duration of the UserFolder opening and closing animation -->
+    <integer name="config_folderAnimDuration">150</integer>
+
     <!-- The distance at which the animation should take the max duration -->
     <integer name="config_dropAnimMaxDist">800</integer>
 
@@ -38,8 +66,4 @@
          than the view itself (workspaceScreenBitmapCacheScale)  -->
     <integer name="config_workspaceScreenBitmapCacheScale">20</integer>
     <integer name="config_maxScaleForUsingWorkspaceScreenBitmapCache">50</integer>
-
-    <style name="config_orientation">
-        <item name="@android:screenOrientation">nosensor</item>
-    </style>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d6cd3ee..62e55d2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -15,8 +15,16 @@
 -->
 
 <resources>
+<!-- AllApps/Customize/AppsCustomize -->
+    <!-- Size of icons in Workspace/AppsCustomize -->
+    <dimen name="app_icon_size">50dp</dimen>
+    <dimen name="apps_customize_cell_width">68dp</dimen>
+    <dimen name="apps_customize_cell_height">68dp</dimen>
     <dimen name="title_texture_width">120px</dimen>
 
+    <!-- height of the tab bar in AppsCustomize -->
+    <dimen name="apps_customize_tab_bar_height">56dp</dimen>
+
     <!-- height of the bottom row of controls -->
     <dimen name="button_bar_height">56dip</dimen>
 
@@ -24,6 +32,24 @@
          button_bar_height changes -->
     <dimen name="button_bar_height_portrait">56dip</dimen>
 
+    <!-- extra horizontal spacing between mini screen thumbnails ie. in all
+         apps and in customization mode -->
+    <dimen name="smallScreenExtraSpacing">0dip</dimen>
+
+    <!-- Vertical spacing between edge of screen and mini cell layouts when they
+         are minimized to the bottom in all apps -->
+    <dimen name="allAppsSmallScreenVerticalMarginLandscape">30dip</dimen>
+    <dimen name="allAppsSmallScreenVerticalMarginPortrait">60dip</dimen>
+
+    <!-- height & width of the drop rectangle for the trash icon -->
+    <dimen name="delete_zone_size">70dip</dimen>
+
+    <!-- delete_zone_size_full - button_bar_height_portrait -->
+    <dimen name="delete_zone_padding">14dip</dimen>
+
+    <!-- padding between the delete zone drawable and text -->
+    <dimen name="delete_zone_drawable_padding">8dip</dimen>
+
     <!-- roughly a status bar (for vertically centering the all apps
          home icon in landscape) -->
     <dimen name="status_bar_height">25dip</dimen>
@@ -32,16 +58,13 @@
          button cluster in landscape) -->
     <dimen name="half_status_bar_height">12dip</dimen>
 
-    <!-- Size of icons in workspace -->
-    <dimen name="app_icon_size">50dp</dimen>
-
-    <!-- height & width of the drop rectangle for the trash icon -->
-    <dimen name="delete_zone_size">70dip</dimen>
-    
-    <!-- delete_zone_size_full - button_bar_height_portrait -->
-    <dimen name="delete_zone_padding">14dip</dimen>
-
+<!-- Dragging -->
     <!-- the area at the edge of the screen that makes the workspace go left
          or right while you're dragging. -->
     <dimen name="scroll_zone">20dp</dimen>
+
+    <!-- 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">-8dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index eedbd6a..9ad3e24 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -151,6 +151,17 @@
          device. [CHAR_LIMIT=30]-->
     <string name="delete_zone_label_all_apps">Uninstall</string>
 
+    <!-- Accessibility: Search button -->
+    <string name="accessibility_search_button">Search</string>
+    <!-- Accessibility: Voice Search button -->
+    <string name="accessibility_voice_search_button">Voice Search</string>
+    <!-- Accessibility: AllApps button -->
+    <string name="accessibility_all_apps_button">Applications</string>
+    <!-- Accessibility: Customize button -->
+    <string name="accessibility_customize_button">Customize</string>
+    <!-- Accessibility: Delete button -->
+    <string name="accessibility_delete_button">Remove</string>
+
     <!-- Label for trash icon in All Apps, when an updated system app is selected. The update will
          be uninstalled. [CHAR_LIMIT=30] -->
     <string name="delete_zone_label_all_apps_system_app">Uninstall update</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0c74a6a..abe6ac4 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -35,17 +35,17 @@
     </style>
     
     <style name="WorkspaceIcon">
-        <item name="android:textSize">13dip</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:ellipsize">marquee</item>
-        <item name="android:shadowColor">#B0000000</item>
-        <item name="android:shadowRadius">2.0</item>
-        <item name="android:textColor">#FFF</item>
-        <item name="android:gravity">center_horizontal</item>
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:paddingLeft">5dip</item>
         <item name="android:paddingRight">5dip</item>
+        <item name="android:gravity">center_horizontal</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">marquee</item>
+        <item name="android:textSize">13dip</item>
+        <item name="android:textColor">#FFF</item>
+        <item name="android:shadowRadius">2.0</item>
+        <item name="android:shadowColor">#B0000000</item>
     </style>
 
     <style name="WorkspaceIcon.AllApps">
@@ -54,7 +54,7 @@
 
     <style name="WorkspaceIcon.Portrait">
         <item name="android:drawablePadding">5dip</item>
-        <item name="android:paddingTop">4dip</item>
+        <item name="android:paddingTop">0dip</item>
         <item name="android:layout_marginLeft">3dip</item>
         <item name="android:layout_marginRight">3dip</item>
         <item name="android:layout_marginTop">13dip</item>
@@ -72,24 +72,19 @@
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">match_parent</item>
         <item name="android:gravity">center</item>
-        <item name="android:paddingLeft">40dp</item>
-        <item name="android:paddingRight">40dp</item>
-        <item name="android:paddingTop">15dp</item>
-        <item name="android:paddingBottom">20dp</item>
-        <item name="android:textColor">@color/tab_widget_indicator_color</item>
+        <item name="android:paddingLeft">15dp</item>
+        <item name="android:paddingRight">15dp</item>
+        <item name="android:paddingTop">10dp</item>
+        <item name="android:paddingBottom">15dp</item>
         <item name="android:background">@drawable/tab_widget_indicator_selector</item>
-        <item name="android:textSize">20sp</item>
+        <item name="android:textColor">@color/tab_widget_indicator_color</item>
+        <item name="android:textSize">16sp</item>
         <item name="android:shadowColor">#393939</item>
         <item name="android:shadowDx">0.0</item>
         <item name="android:shadowDy">1.0</item>
         <item name="android:shadowRadius">1.0</item>
     </style>
 
-    <style name="TabIndicator.Portrait">
-        <item name="android:paddingLeft">20dp</item>
-        <item name="android:paddingRight">20dp</item>
-    </style>
-
     <style name="SearchButton" parent="@android:style/Widget.Button.Small">
         <item name="android:paddingTop">7dip</item>
         <item name="android:paddingBottom">9dip</item>
@@ -97,6 +92,29 @@
         <item name="android:paddingRight">10dip</item>
     </style>
 
+    <style name="MarketButton">
+        <item name="android:paddingRight">20dp</item>
+        <item name="android:text">@string/market</item>
+        <item name="android:textColor">@color/workspace_all_apps_and_delete_zone_text_color</item>
+        <item name="android:textSize">18sp</item>
+        <item name="android:shadowColor">@color/workspace_all_apps_and_delete_zone_text_shadow_color</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">0.0</item>
+        <item name="android:shadowRadius">2.0</item>
+    </style>
+
+    <style name="DeleteZone">
+        <item name="android:drawableLeft">@drawable/delete_zone_selector</item>
+        <item name="android:drawablePadding">@dimen/delete_zone_drawable_padding</item>
+        <item name="android:paddingRight">20dp</item>
+        <item name="android:textColor">@color/workspace_all_apps_and_delete_zone_text_color</item>
+        <item name="android:textSize">18sp</item>
+        <item name="android:shadowColor">@color/workspace_all_apps_and_delete_zone_text_shadow_color</item>
+        <item name="android:shadowDx">0.0</item>
+        <item name="android:shadowDy">0.0</item>
+        <item name="android:shadowRadius">2.0</item>
+    </style>
+
     <style name="HotseatButton">
         <item name="android:paddingLeft">12dip</item>
         <item name="android:paddingRight">12dip</item>
@@ -116,4 +134,7 @@
         <item name="android:background">@drawable/hotseat_bg_right</item>
     </style>
 
+    <style name="config_orientation">
+        <item name="@android:screenOrientation">nosensor</item>
+    </style>
 </resources>
diff --git a/src/com/android/launcher2/AccessibleTabView.java b/src/com/android/launcher2/AccessibleTabView.java
new file mode 100644
index 0000000..101f139
--- /dev/null
+++ b/src/com/android/launcher2/AccessibleTabView.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.TextView;
+
+/**
+ * We use a custom tab view to process our own focus traversals.
+ */
+public class AccessibleTabView extends TextView {
+    public AccessibleTabView(Context context) {
+        super(context);
+    }
+
+    public AccessibleTabView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public AccessibleTabView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return FocusHelper.handleTabKeyEvent(this, keyCode, event)
+                || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return FocusHelper.handleTabKeyEvent(this, keyCode, event)
+                || super.onKeyUp(keyCode, event);
+    }
+}
diff --git a/src/com/android/launcher2/AddAdapter.java b/src/com/android/launcher2/AddAdapter.java
index 24c31ff..6f97d72 100644
--- a/src/com/android/launcher2/AddAdapter.java
+++ b/src/com/android/launcher2/AddAdapter.java
@@ -40,7 +40,6 @@
     
     public static final int ITEM_SHORTCUT = 0;
     public static final int ITEM_APPWIDGET = 1;
-    public static final int ITEM_LIVE_FOLDER = 2;
     public static final int ITEM_WALLPAPER = 3;
     
     /**
@@ -76,9 +75,6 @@
         mItems.add(new ListItem(res, R.string.group_widgets,
                 R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET));
         
-        mItems.add(new ListItem(res, R.string.group_live_folders,
-                R.drawable.ic_launcher_folder, ITEM_LIVE_FOLDER));
-        
         mItems.add(new ListItem(res, R.string.group_wallpapers,
                 R.drawable.ic_launcher_wallpaper, ITEM_WALLPAPER));
 
diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java
index 1cbb999..44af7b7 100644
--- a/src/com/android/launcher2/AllApps2D.java
+++ b/src/com/android/launcher2/AllApps2D.java
@@ -143,7 +143,7 @@
                 homeButton.setOnClickListener(
                     new View.OnClickListener() {
                         public void onClick(View v) {
-                            mLauncher.closeAllApps(true);
+                            mLauncher.showWorkspace(true);
                         }
                     });
             }
@@ -158,8 +158,10 @@
         this(context, attrs);
     }
 
-    public void setLauncher(Launcher launcher) {
+    @Override
+    public void setup(Launcher launcher, DragController dragController) {
         mLauncher = launcher;
+        mDragController = dragController;
     }
 
     public boolean onKey(View v, int keyCode, KeyEvent event) {
@@ -167,7 +169,7 @@
 
         switch (keyCode) {
             case KeyEvent.KEYCODE_BACK:
-                mLauncher.closeAllApps(true);
+                mLauncher.showWorkspace(true);
                 break;
             default:
                 return false;
@@ -190,7 +192,7 @@
         app = new ApplicationInfo(app);
 
         mDragController.startDrag(view, this, app, DragController.DRAG_ACTION_COPY);
-        mLauncher.closeAllApps(true);
+        mLauncher.showWorkspace(true);
 
         return true;
     }
@@ -202,11 +204,6 @@
     }
 
     @Override
-    public void setDragController(DragController dragger) {
-        mDragController = dragger;
-    }
-
-    @Override
     public void onDragViewVisible() {
     }
 
@@ -341,6 +338,10 @@
     
     public void surrender() {
     }
+
+    public void reset() {
+        // Do nothing
+    }
 }
 
 
diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java
index 29f49af..0e512c6 100644
--- a/src/com/android/launcher2/AllApps3D.java
+++ b/src/com/android/launcher2/AllApps3D.java
@@ -155,13 +155,6 @@
             setRenderScriptGL(sRS);
         }
 
-        final DisplayMetrics metrics = getResources().getDisplayMetrics();
-        final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
-        mColumnsPerPage = isPortrait ? Defines.COLUMNS_PER_PAGE_PORTRAIT :
-                Defines.COLUMNS_PER_PAGE_LANDSCAPE;
-        mRowsPerPage = isPortrait ? Defines.ROWS_PER_PAGE_PORTRAIT :
-                Defines.ROWS_PER_PAGE_LANDSCAPE;
-
         if (sRollo != null) {
             sRollo.mAllApps = this;
             sRollo.mRes = getResources();
@@ -208,8 +201,10 @@
         setSoundEffectsEnabled(old);
     }
 
-    public void setLauncher(Launcher launcher) {
+    @Override
+    public void setup(Launcher launcher, DragController dragController) {
         mLauncher = launcher;
+        mDragController = dragController;
     }
 
     @Override
@@ -231,6 +226,12 @@
 
         super.surfaceChanged(holder, format, w, h);
 
+        final boolean isPortrait = w < h;
+        mColumnsPerPage = isPortrait ? Defines.COLUMNS_PER_PAGE_PORTRAIT :
+                Defines.COLUMNS_PER_PAGE_LANDSCAPE;
+        mRowsPerPage = isPortrait ? Defines.ROWS_PER_PAGE_PORTRAIT :
+                Defines.ROWS_PER_PAGE_LANDSCAPE;
+
         if (mSurrendered) return;
 
         mHaveSurface = true;
@@ -350,7 +351,7 @@
             if (mArrowNavigation) {
                 if (mLastSelection == SELECTION_HOME) {
                     reallyPlaySoundEffect(SoundEffectConstants.CLICK);
-                    mLauncher.closeAllApps(true);
+                    mLauncher.showWorkspace(true);
                 } else {
                     int whichApp = sRollo.mScript.get_gSelectedIconIndex();
                     if (whichApp >= 0) {
@@ -637,7 +638,7 @@
                     if ((isPortrait && y > mTouchYBorders[mTouchYBorders.length-1]) ||
                         (!isPortrait && x > mTouchXBorders[mTouchXBorders.length-1])) {
                         reallyPlaySoundEffect(SoundEffectConstants.CLICK);
-                        mLauncher.closeAllApps(true);
+                        mLauncher.showWorkspace(true);
                     }
                     sRollo.setHomeSelected(SELECTED_NONE);
                 }
@@ -691,10 +692,12 @@
             int screenX = mMotionDownRawX - (bmp.getWidth() / 2);
             int screenY = mMotionDownRawY - bmp.getHeight();
 
+            mLauncher.lockScreenOrientation();
+            mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, bmp);
             mDragController.startDrag(
                     bmp, screenX, screenY, this, app, DragController.DRAG_ACTION_COPY);
 
-            mLauncher.closeAllApps(true);
+            mLauncher.showWorkspace(true);
         }
         return true;
     }
@@ -737,16 +740,13 @@
     }
 
     @Override
-    public void setDragController(DragController dragger) {
-        mDragController = dragger;
-    }
-
-    @Override
     public void onDragViewVisible() {
     }
 
     @Override
     public void onDropCompleted(View target, Object dragInfo, boolean success) {
+        mLauncher.getWorkspace().onDragStopped(success);
+        mLauncher.unlockScreenOrientation();
     }
 
     /**
@@ -1045,13 +1045,16 @@
                 i.ScaleOffset.x = (2.f / 480.f);
                 i.ScaleOffset.y = 0;
                 i.ScaleOffset.z = -((float)w / 2) - 0.25f;
-                i.ScaleOffset.w = -380.25f;
-                i.BendPos.x = 120.f;
-                i.BendPos.y = 680.f;
-                if (w > h) {
-                    i.ScaleOffset.z = 40.f;
-                    i.ScaleOffset.w = h - 40.f;
-                    i.BendPos.y = 1.f;
+                if (w < h) {
+                    // portrait
+                    i.ScaleOffset.w = -380.25f;
+                    i.BendPos.x = 120.f;        // bottom of screen
+                    i.BendPos.y = h - 82.f;     // top of screen
+                } else {
+                    // landscape
+                    i.ScaleOffset.w = -206.25f;
+                    i.BendPos.x = 50.f;
+                    i.BendPos.y = h - 30.f;
                 }
                 mUniformAlloc.set(i, 0, true);
             }
@@ -1091,7 +1094,7 @@
                     "  float aDy = cos(bendAngle);\n" +
                     "  float aDz = sin(bendAngle);\n" +
 
-                    "  float scale = (2.0 / 480.0);\n" +
+                    "  float scale = (2.0 / " + mWidth + ".0);\n" +
                     "  float x = UNI_Position.x + UNI_ImgSize.x * (1.0 - ani) * (ATTRIB_position.x - 0.5);\n" +
                     "  float ys= UNI_Position.y + UNI_ImgSize.y * (1.0 - ani) * ATTRIB_position.y;\n" +
                     "  float y = 0.0;\n" +
@@ -1466,4 +1469,8 @@
             sRS.contextDump();
         }
     }
+
+    public void reset() {
+        // Do nothing
+    }
 }
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 87d255e..d9a503f 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -66,6 +67,7 @@
     private boolean mAllowHardwareLayerCreation;
 
     private int mPageContentWidth;
+    private boolean mHasMadeSuccessfulDrop;
 
     public AllAppsPagedView(Context context) {
         this(context, null);
@@ -88,7 +90,7 @@
 
         Resources r = context.getResources();
         setDragSlopeThreshold(
-                r.getInteger(R.integer.config_allAppsDrawerDragSlopeThreshold) / 100.0f);
+                r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold) / 100.0f);
 
         // Create a dummy page and set it up to find out the content width (used by our parent)
         PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
@@ -119,14 +121,10 @@
     }
 
     @Override
-    public void setLauncher(Launcher launcher) {
+    public void setup(Launcher launcher, DragController dragController) {
         mLauncher = launcher;
         mLauncher.setAllAppsPagedView(this);
-    }
-
-    @Override
-    public void setDragController(DragController dragger) {
-        mDragController = dragger;
+        mDragController = dragController;
     }
 
     public void setAppFilter(int filterType) {
@@ -138,6 +136,10 @@
         }
     }
 
+    void resetSuccessfulDropFlag() {
+        mHasMadeSuccessfulDrop = false;
+    }
+
     @Override
     public void zoom(float zoom, boolean animate) {
         mZoom = zoom;
@@ -285,6 +287,16 @@
         c.translate((v.getWidth() - icon.getIntrinsicWidth()) / 2, v.getPaddingTop());
         icon.draw(c);
 
+        Rect dragRect = null;
+        if (v instanceof TextView) {
+            int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+            int top = v.getPaddingTop();
+            int left = (b.getWidth() - iconSize) / 2;
+            int right = left + iconSize;
+            int bottom = top + iconSize;
+            dragRect = new Rect(left, top, right, bottom);
+        }
+
         // We toggle the checked state _after_ we create the view for the drag in case toggling the
         // checked state changes the view's look
         if (v instanceof Checkable) {
@@ -304,7 +316,7 @@
         // Start the drag
         mLauncher.lockScreenOrientation();
         mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
-        mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
+        mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, dragRect);
         b.recycle();
         return true;
     }
@@ -322,6 +334,12 @@
         tearDownDragMode();
         mLauncher.getWorkspace().onDragStopped(success);
         mLauncher.unlockScreenOrientation();
+
+        if (!success && !mHasMadeSuccessfulDrop) {
+            mLauncher.getWorkspace().shrink(Workspace.ShrinkState.BOTTOM_HIDDEN);
+        } else {
+            mHasMadeSuccessfulDrop |= success;
+        }
     }
 
     int getPageContentWidth() {
@@ -450,6 +468,11 @@
         // do nothing?
     }
 
+    public void reset() {
+        setCurrentPage(0);
+        invalidatePageData();
+    }
+
     private void setupPage(PagedViewCellLayout layout) {
         layout.setCellCount(mCellCountX, mCellCountY);
         layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop, mPageLayoutPaddingRight,
@@ -485,6 +508,7 @@
     @Override
     public void syncPageItems(int page) {
         // Ensure that we have the right number of items on the pages
+        final int numPages = getPageCount();
         final int cellsPerPage = mCellCountX * mCellCountY;
         final int startIndex = page * cellsPerPage;
         final int endIndex = Math.min(startIndex + cellsPerPage, mFilteredApps.size());
@@ -517,6 +541,7 @@
 
             // Add any necessary items
             for (int i = curNumPageItems; i < numPageItems; ++i) {
+                final boolean createHolographicOutlines = (numPages > 1);
                 TextView text = (TextView) mInflater.inflate(
                         R.layout.all_apps_paged_view_application, layout, false);
                 text.setOnClickListener(this);
@@ -524,16 +549,17 @@
                 text.setOnTouchListener(this);
 
                 layout.addViewToCellLayout(text, -1, i,
-                    new PagedViewCellLayout.LayoutParams(0, 0, 1, 1));
+                    new PagedViewCellLayout.LayoutParams(0, 0, 1, 1), createHolographicOutlines);
             }
 
             // Actually reapply to the existing text views
-            final int numPages = getPageCount();
             for (int i = startIndex; i < endIndex; ++i) {
                 final int index = i - startIndex;
                 final ApplicationInfo info = mFilteredApps.get(i);
+                final boolean createHolographicOutlines = (numPages > 1);
                 PagedViewIcon icon = (PagedViewIcon) layout.getChildOnPageAt(index);
-                icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+                icon.applyFromApplicationInfo(
+                        info, mPageViewIconCache, true, createHolographicOutlines);
 
                 PagedViewCellLayout.LayoutParams params =
                     (PagedViewCellLayout.LayoutParams) icon.getLayoutParams();
@@ -555,10 +581,11 @@
             }
 
             // Center-align the message
+            final boolean createHolographicOutlines = (numPages > 1);
             layout.enableCenteredContent(true);
             layout.removeAllViewsOnPage();
             layout.addViewToCellLayout(icon, -1, 0,
-                    new PagedViewCellLayout.LayoutParams(0, 0, 4, 1));
+                    new PagedViewCellLayout.LayoutParams(0, 0, 4, 1), createHolographicOutlines);
         }
         layout.createHardwareLayers();
     }
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index ee7bfc0..96de5a7 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -29,11 +29,13 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TabHost;
 import android.widget.TabWidget;
 import android.widget.TextView;
 
 import java.util.ArrayList;
+import java.util.Random;
 
 /**
  * Implements a tabbed version of AllApps2D.
@@ -80,6 +82,7 @@
         };
 
         // Create the tabs and wire them up properly
+        AllAppsTabKeyEventListener keyListener = new AllAppsTabKeyEventListener();
         TextView tabView;
         TabWidget tabWidget = (TabWidget) findViewById(com.android.internal.R.id.tabs);
         tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
@@ -90,11 +93,17 @@
         tabView.setText(mContext.getString(R.string.all_apps_tab_downloaded));
         addTab(newTabSpec(TAG_DOWNLOADED).setIndicator(tabView).setContent(contentFactory));
 
+        // Setup the key listener to jump between the last tab view and the market icon
+        View lastTab = tabWidget.getChildTabViewAt(tabWidget.getTabCount() - 1);
+        lastTab.setOnKeyListener(keyListener);
+        View shopButton = findViewById(R.id.market_button);
+        shopButton.setOnKeyListener(keyListener);
+
         setOnTabChangedListener(new OnTabChangeListener() {
             public void onTabChanged(String tabId) {
                 // animate the changing of the tab content by fading pages in and out
                 final Resources res = getResources();
-                final int duration = res.getInteger(R.integer.config_tabTransitionTime);
+                final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
                 final float alpha = mAllApps.getAlpha();
                 ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 0.0f).
                         setDuration(duration);
@@ -134,14 +143,9 @@
     }
 
     @Override
-    public void setLauncher(Launcher launcher) {
-        mAllApps.setLauncher(launcher);
+    public void setup(Launcher launcher, DragController dragController) {
         mLauncher = launcher;
-    }
-
-    @Override
-    public void setDragController(DragController dragger) {
-        mAllApps.setDragController(dragger);
+        mAllApps.setup(launcher, dragController);
     }
 
     @Override
@@ -248,6 +252,10 @@
         mAllApps.surrender();
     }
 
+    public void reset() {
+        mAllApps.reset();
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (ev.getY() > mAllApps.getBottom()) {
@@ -255,4 +263,12 @@
         }
         return true;
     }
+
+    @Override
+    public int getDescendantFocusability() {
+        if (getVisibility() != View.VISIBLE) {
+            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+        }
+        return super.getDescendantFocusability();
+    }
 }
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java
index 007ecf8..e8ca61f 100644
--- a/src/com/android/launcher2/AllAppsView.java
+++ b/src/com/android/launcher2/AllAppsView.java
@@ -23,9 +23,7 @@
         public void zoomed(float zoom);
     }
 
-    public void setLauncher(Launcher launcher);
-
-    public void setDragController(DragController dragger);
+    public void setup(Launcher launcher, DragController dragController);
 
     public void zoom(float zoom, boolean animate);
 
@@ -41,6 +39,9 @@
 
     public void updateApps(ArrayList<ApplicationInfo> list);
     
+    // Resets the AllApps page to the front
+    public void reset();
+
     public void dumpState();
 
     public void surrender();
diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java
index 2b2662f..4390c59 100644
--- a/src/com/android/launcher2/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher2/AppWidgetResizeFrame.java
@@ -18,6 +18,8 @@
     private ItemInfo mItemInfo;
     private LauncherAppWidgetHostView mWidgetView;
     private CellLayout mCellLayout;
+    private DragLayer mDragLayer;
+    private Workspace mWorkspace;
     private ImageView mLeftHandle;
     private ImageView mRightHandle;
     private ImageView mTopHandle;
@@ -57,7 +59,7 @@
     public static final int BOTTOM = 3;
 
     public AppWidgetResizeFrame(Context context, ItemInfo itemInfo, 
-            LauncherAppWidgetHostView widgetView, CellLayout cellLayout) {
+            LauncherAppWidgetHostView widgetView, CellLayout cellLayout, DragLayer dragLayer) {
 
         super(context);
         mContext = context;
@@ -65,6 +67,8 @@
         mCellLayout = cellLayout;
         mWidgetView = widgetView;
         mResizeMode = widgetView.getAppWidgetInfo().resizeMode;
+        mDragLayer = dragLayer;
+        mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
 
         final AppWidgetProviderInfo info = widgetView.getAppWidgetInfo();
         int[] result = mCellLayout.rectToCell(info.minWidth, info.minHeight, null);
@@ -150,7 +154,7 @@
             mDeltaX = Math.max(-mBaselineX, deltaX); 
             mDeltaX = Math.min(mBaselineWidth - 2 * mTouchTargetWidth, mDeltaX);
         } else if (mRightBorderActive) {
-            mDeltaX = Math.min(mCellLayout.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
+            mDeltaX = Math.min(mDragLayer.getWidth() - (mBaselineX + mBaselineWidth), deltaX);
             mDeltaX = Math.max(-mBaselineWidth + 2 * mTouchTargetWidth, mDeltaX);
         }
 
@@ -158,7 +162,7 @@
             mDeltaY = Math.max(-mBaselineY, deltaY);
             mDeltaY = Math.min(mBaselineHeight - 2 * mTouchTargetWidth, mDeltaY);
         } else if (mBottomBorderActive) {
-            mDeltaY = Math.min(mCellLayout.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
+            mDeltaY = Math.min(mDragLayer.getHeight() - (mBaselineY + mBaselineHeight), deltaY);
             mDeltaY = Math.max(-mBaselineHeight + 2 * mTouchTargetWidth, mDeltaY);
         }
     }
@@ -168,7 +172,8 @@
      */
     public void visualizeResizeForDelta(int deltaX, int deltaY) {
         updateDeltas(deltaX, deltaY);
-        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+        DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+
         if (mLeftBorderActive) {
             lp.x = mBaselineX + mDeltaX;
             lp.width = mBaselineWidth - mDeltaX;
@@ -261,6 +266,7 @@
 
         // Update the cells occupied by this widget
         mCellLayout.markCellsAsOccupiedForView(mWidgetView);
+        mWidgetView.requestLayout();
     }
 
     /**
@@ -284,20 +290,22 @@
     }
 
     public void snapToWidget(boolean animate) {
-        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+        final DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+        int xOffset = mCellLayout.getLeft() + mCellLayout.getLeftPadding() - mWorkspace.getScrollX();
+        int yOffset = mCellLayout.getTop() + mCellLayout.getTopPadding() - mWorkspace.getScrollY();
 
         int newWidth = mWidgetView.getWidth() + 2 * mBackgroundPadding;
         int newHeight = mWidgetView.getHeight() + 2 * mBackgroundPadding;
-        int newX = mWidgetView.getLeft() - mBackgroundPadding;
-        int newY = mWidgetView.getTop() - mBackgroundPadding;
+        int newX = mWidgetView.getLeft() - mBackgroundPadding + xOffset;
+        int newY = mWidgetView.getTop() - mBackgroundPadding + yOffset;
 
         // We need to make sure the frame stays within the bounds of the CellLayout
         if (newY < 0) {
             newHeight -= -newY;
             newY = 0;
         }
-        if (newY + newHeight > mCellLayout.getHeight()) {
-            newHeight -= newY + newHeight - mCellLayout.getHeight();
+        if (newY + newHeight > mDragLayer.getHeight()) {
+            newHeight -= newY + newHeight - mDragLayer.getHeight();
         }
 
         if (!animate) {
diff --git a/src/com/android/launcher2/ApplicationInfoDropTarget.java b/src/com/android/launcher2/ApplicationInfoDropTarget.java
index 78a9d2d..f42aaf5 100644
--- a/src/com/android/launcher2/ApplicationInfoDropTarget.java
+++ b/src/com/android/launcher2/ApplicationInfoDropTarget.java
@@ -50,7 +50,7 @@
         int colour = getContext().getResources().getColor(R.color.app_info_filter);
         mHoverPaint.setColorFilter(new PorterDuffColorFilter(colour, PorterDuff.Mode.SRC_ATOP));
 
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             // For the application info drop target, we just ignore the left padding since we don't want
             // to overlap with the delete zone padding
             int tb = getResources().getDimensionPixelSize(
@@ -162,10 +162,13 @@
         // Fade in the overlapping views
         if (mOverlappingViews != null) {
             for (View view : mOverlappingViews) {
-                ObjectAnimator oa = ObjectAnimator.ofFloat(view, "alpha", 1.0f);
-                oa.setDuration(sFadeInAnimationDuration);
-                mFadeAnimator.play(oa);
-                view.setVisibility(VISIBLE);
+                // Check whether the views are enabled first, before trying to fade them in
+                if (view.isEnabled()) {
+                    ObjectAnimator oa = ObjectAnimator.ofFloat(view, "alpha", 1.0f);
+                    oa.setDuration(sFadeInAnimationDuration);
+                    mFadeAnimator.play(oa);
+                    view.setVisibility(VISIBLE);
+                }
             }
         }
         mFadeAnimator.start();
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
new file mode 100644
index 0000000..14e051c
--- /dev/null
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.app.WallpaperManager;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.LruCache;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
+        AllAppsView, View.OnClickListener, DragSource {
+    static final String LOG_TAG = "AppsCustomizePagedView";
+
+    /**
+     * The different content types that this paged view can show.
+     */
+    public enum ContentType {
+        Applications,
+        Widgets,
+        Wallpapers
+    }
+
+    // Refs
+    private Launcher mLauncher;
+    private DragController mDragController;
+    private final LayoutInflater mLayoutInflater;
+    private final PackageManager mPackageManager;
+
+    // Content
+    private ContentType mContentType;
+    private ArrayList<ApplicationInfo> mApps;
+    private List<Object> mWidgets;
+    private List<ResolveInfo> mWallpapers;
+
+    // Caching
+    private Drawable mDefaultWidgetBackground;
+    private final int sWidgetPreviewCacheSize = 1 * 1024 * 1024; // 1 MiB
+    private LruCache<Object, Bitmap> mWidgetPreviewCache;
+    private IconCache mIconCache;
+
+    // Dimens
+    private int mContentWidth;
+    private int mMaxWidgetSpan, mMinWidgetSpan;
+    private int mCellWidthGap, mCellHeightGap;
+    private int mWidgetCountX, mWidgetCountY;
+    private int mWallpaperCountX, mWallpaperCountY;
+    private final int mWidgetPreviewIconPaddedDimension;
+    private final float sWidgetPreviewIconPaddingPercentage = 0.25f;
+    private PagedViewCellLayout mWidgetSpacingLayout;
+
+    // Animations
+    private final float ANIMATION_SCALE = 0.5f;
+    private final int TRANSLATE_ANIM_DURATION = 400;
+    private final int DROP_ANIM_DURATION = 200;
+
+    public AppsCustomizePagedView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLayoutInflater = LayoutInflater.from(context);
+        mPackageManager = context.getPackageManager();
+        mContentType = ContentType.Applications;
+        mApps = new ArrayList<ApplicationInfo>();
+        mWidgets = new ArrayList<Object>();
+        mWallpapers = new ArrayList<ResolveInfo>();
+        mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();
+        mWidgetPreviewCache = new LruCache<Object, Bitmap>(sWidgetPreviewCacheSize) {
+            protected int sizeOf(Object key, Bitmap value) {
+                return value.getByteCount();
+            }
+        };
+
+        // Save the default widget preview background
+        Resources resources = context.getResources();
+        mDefaultWidgetBackground = resources.getDrawable(R.drawable.default_widget_preview);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedView, 0, 0);
+        mCellCountX = a.getInt(R.styleable.PagedView_cellCountX, 6);
+        mCellCountY = a.getInt(R.styleable.PagedView_cellCountY, 4);
+        a.recycle();
+        a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
+        mCellWidthGap =
+            a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellWidthGap, 10);
+        mCellHeightGap =
+            a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 10);
+        mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
+        mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
+        mWallpaperCountX = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountX, 2);
+        mWallpaperCountY = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountY, 2);
+        a.recycle();
+
+        // Create a dummy page that we can use to approximate the cell dimensions of widgets and
+        // the content width (to be used by our parent)
+        mWidgetSpacingLayout = new PagedViewCellLayout(context);
+        setupPage(mWidgetSpacingLayout);
+        mContentWidth = mWidgetSpacingLayout.getContentWidth();
+
+        // The max widget span is the length N, such that NxN is the largest bounds that the widget
+        // preview can be before applying the widget scaling
+        mMinWidgetSpan = 1;
+        mMaxWidgetSpan = 3;
+
+        // The padding on the non-matched dimension for the default widget preview icons
+        // (top + bottom)
+        int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+        mWidgetPreviewIconPaddedDimension =
+            (int) (iconSize * (1 + (2 * sWidgetPreviewIconPaddingPercentage)));
+    }
+
+    @Override
+    protected void init() {
+        super.init();
+        mCenterPagesVertically = false;
+
+        Context context = getContext();
+        Resources r = context.getResources();
+        setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
+    }
+
+    public void onPackagesUpdated() {
+        // Get the list of widgets and shortcuts
+        mWidgets.clear();
+        mWidgets.addAll(AppWidgetManager.getInstance(mLauncher).getInstalledProviders());
+        Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+        mWidgets.addAll(mPackageManager.queryIntentActivities(shortcutsIntent, 0));
+        Collections.sort(mWidgets,
+                new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager));
+
+        // Get the list of wallpapers
+        Intent wallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+        mWallpapers = mPackageManager.queryIntentActivities(wallpapersIntent,
+                PackageManager.GET_META_DATA);
+        Collections.sort(mWallpapers,
+                new LauncherModel.ShortcutNameComparator(mPackageManager));
+    }
+
+    /**
+     * Animates the given item onto the center of a home screen, and then scales the item to
+     * look as though it's disappearing onto that screen.
+     */
+    private void animateItemOntoScreen(View dragView,
+            final CellLayout layout, final ItemInfo info) {
+        // On the phone, we only want to fade the widget preview out
+        float[] position = new float[2];
+        position[0] = layout.getWidth() / 2;
+        position[1] = layout.getHeight() / 2;
+
+        mLauncher.getWorkspace().mapPointFromChildToSelf(layout, position);
+
+        int dragViewWidth = dragView.getMeasuredWidth();
+        int dragViewHeight = dragView.getMeasuredHeight();
+        float heightOffset = 0;
+        float widthOffset = 0;
+
+        if (dragView instanceof ImageView) {
+            Drawable d = ((ImageView) dragView).getDrawable();
+            int width = d.getIntrinsicWidth();
+            int height = d.getIntrinsicHeight();
+
+            if ((1.0 * width / height) >= (1.0f * dragViewWidth) / dragViewHeight) {
+                float f = (dragViewWidth / (width * 1.0f));
+                heightOffset = ANIMATION_SCALE * (dragViewHeight - f * height) / 2;
+            } else {
+                float f = (dragViewHeight / (height * 1.0f));
+                widthOffset = ANIMATION_SCALE * (dragViewWidth - f * width) / 2;
+            }
+        }
+        final float toX = position[0] - dragView.getMeasuredWidth() / 2 + widthOffset;
+        final float toY = position[1] - dragView.getMeasuredHeight() / 2 + heightOffset;
+
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        final View dragCopy = dragLayer.createDragView(dragView);
+        dragCopy.setAlpha(1.0f);
+
+        // Translate the item to the center of the appropriate home screen
+        animateIntoPosition(dragCopy, toX, toY, null);
+
+        // The drop-onto-screen animation begins a bit later, but ends at the same time.
+        final int startDelay = TRANSLATE_ANIM_DURATION - DROP_ANIM_DURATION;
+
+        // Scale down the icon and fade out the alpha
+        animateDropOntoScreen(dragCopy, info, DROP_ANIM_DURATION, startDelay);
+    }
+
+    /**
+     * Animation which scales the view down and animates its alpha, making it appear to disappear
+     * onto a home screen.
+     */
+    private void animateDropOntoScreen(
+            final View view, final ItemInfo info, int duration, int delay) {
+        final DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        final CellLayout layout = mLauncher.getWorkspace().getCurrentDropLayout();
+
+        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
+                PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f),
+                PropertyValuesHolder.ofFloat("scaleX", ANIMATION_SCALE),
+                PropertyValuesHolder.ofFloat("scaleY", ANIMATION_SCALE));
+        anim.setInterpolator(new LinearInterpolator());
+        if (delay > 0) {
+            anim.setStartDelay(delay);
+        }
+        anim.setDuration(duration);
+        anim.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                dragLayer.removeView(view);
+                mLauncher.addExternalItemToScreen(info, layout);
+                info.dropPos = null;
+            }
+        });
+        anim.start();
+    }
+
+    /**
+     * Animates the x,y position of the view, and optionally execute a Runnable on animation end.
+     */
+    private void animateIntoPosition(
+            View view, float toX, float toY, final Runnable endRunnable) {
+        ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view,
+                PropertyValuesHolder.ofFloat("x", toX),
+                PropertyValuesHolder.ofFloat("y", toY));
+        anim.setInterpolator(new DecelerateInterpolator(2.5f));
+        anim.setDuration(TRANSLATE_ANIM_DURATION);
+        if (endRunnable != null) {
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    endRunnable.run();
+                }
+            });
+        }
+        anim.start();
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v instanceof PagedViewIcon) {
+            // Animate some feedback to the click
+            final ApplicationInfo appInfo = (ApplicationInfo) v.getTag();
+            animateClickFeedback(v, new Runnable() {
+                @Override
+                public void run() {
+                    mLauncher.startActivitySafely(appInfo.intent, appInfo);
+                }
+            });
+        } else if (v instanceof PagedViewWidget) {
+            final ResolveInfo info = (ResolveInfo) v.getTag();
+            if (mWallpapers.contains(info)) {
+                // Start the wallpaper picker
+                animateClickFeedback(v, new Runnable() {
+                    @Override
+                    public void run() {
+                        // add the shortcut
+                        Intent createWallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
+                        ComponentName name = new ComponentName(info.activityInfo.packageName,
+                                info.activityInfo.name);
+                        createWallpapersIntent.setComponent(name);
+                        mLauncher.processWallpaper(createWallpapersIntent);
+                    }
+                });
+            } else {
+                // Add the widget to the current workspace screen
+                Workspace w = mLauncher.getWorkspace();
+                int currentWorkspaceScreen = mLauncher.getCurrentWorkspaceScreen();
+                final CellLayout cl = (CellLayout) w.getChildAt(currentWorkspaceScreen);
+                final View dragView = v.findViewById(R.id.widget_preview);
+                final ItemInfo itemInfo = (ItemInfo) v.getTag();
+                animateClickFeedback(v, new Runnable() {
+                    @Override
+                    public void run() {
+                        cl.calculateSpans(itemInfo);
+                        if (cl.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY)) {
+                            if (LauncherApplication.isScreenLarge()) {
+                                animateItemOntoScreen(dragView, cl, itemInfo);
+                            } else {
+                                mLauncher.addExternalItemToScreen(itemInfo, cl);
+                                itemInfo.dropPos = null;
+                            }
+
+                            // Hide the pane so we can see the workspace we dropped on
+                            mLauncher.showWorkspace(true);
+                        } else {
+                            mLauncher.showOutOfSpaceMessage();
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    /*
+     * PagedViewWithDraggableItems implementation
+     */
+    @Override
+    protected void determineDraggingStart(android.view.MotionEvent ev) {
+        // Disable dragging by pulling an app down for now.
+    }
+    private void beginDraggingApplication(View v) {
+        // Make a copy of the ApplicationInfo
+        ApplicationInfo appInfo = new ApplicationInfo((ApplicationInfo) v.getTag());
+
+        // Show the uninstall button if the app is uninstallable.
+        if ((appInfo.flags & ApplicationInfo.DOWNLOADED_FLAG) != 0) {
+            DeleteZone allAppsDeleteZone = (DeleteZone)
+                    mLauncher.findViewById(R.id.all_apps_delete_zone);
+            allAppsDeleteZone.setDragAndDropEnabled(true);
+
+            if ((appInfo.flags & ApplicationInfo.UPDATED_SYSTEM_APP_FLAG) != 0) {
+                allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps_system_app);
+            } else {
+                allAppsDeleteZone.setText(R.string.delete_zone_label_all_apps);
+            }
+        }
+
+        // Show the info button
+        ApplicationInfoDropTarget allAppsInfoButton =
+            (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+        allAppsInfoButton.setDragAndDropEnabled(true);
+
+        // Compose the drag image (top compound drawable, index is 1)
+        final TextView tv = (TextView) v;
+        final Drawable icon = tv.getCompoundDrawables()[1];
+        Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(b);
+        c.translate((v.getWidth() - icon.getIntrinsicWidth()) / 2, v.getPaddingTop());
+        icon.draw(c);
+
+        // Compose the visible rect of the drag image
+        Rect dragRect = null;
+        if (v instanceof TextView) {
+            int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+            int top = v.getPaddingTop();
+            int left = (b.getWidth() - iconSize) / 2;
+            int right = left + iconSize;
+            int bottom = top + iconSize;
+            dragRect = new Rect(left, top, right, bottom);
+        }
+
+        // Start the drag
+        mLauncher.lockScreenOrientation();
+        mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+        mDragController.startDrag(v, b, this, appInfo, DragController.DRAG_ACTION_COPY, dragRect);
+        b.recycle();
+    }
+    private void beginDraggingWidget(View v) {
+        // Get the widget preview as the drag representation
+        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
+        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+        // Compose the drag image
+        Bitmap b;
+        Drawable preview = image.getDrawable();
+        int w = preview.getIntrinsicWidth();
+        int h = preview.getIntrinsicHeight();
+        if (createItemInfo instanceof PendingAddWidgetInfo) {
+            PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
+            int[] spanXY = CellLayout.rectToCell(getResources(),
+                    createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
+            createItemInfo.spanX = spanXY[0];
+            createItemInfo.spanY = spanXY[1];
+
+            b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+            renderDrawableToBitmap(preview, b, 0, 0, w, h, 1, 1);
+        } else {
+            // Workaround for the fact that we don't keep the original ResolveInfo associated with
+            // the shortcut around.  To get the icon, we just render the preview image (which has
+            // the shortcut icon) to a new drag bitmap that clips the non-icon space.
+            b = Bitmap.createBitmap(mWidgetPreviewIconPaddedDimension,
+                    mWidgetPreviewIconPaddedDimension, Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(b);
+            preview.draw(c);
+            createItemInfo.spanX = createItemInfo.spanY = 1;
+        }
+
+        // Start the drag
+        mLauncher.lockScreenOrientation();
+        mLauncher.getWorkspace().onDragStartedWithItemSpans(createItemInfo.spanX,
+                createItemInfo.spanY, b);
+        mDragController.startDrag(image, b, this, createItemInfo,
+                DragController.DRAG_ACTION_COPY, null);
+        b.recycle();
+    }
+    @Override
+    protected boolean beginDragging(View v) {
+        if (!super.beginDragging(v)) return false;
+
+        // Hide the pane so that the user can drop onto the workspace, we must do this first,
+        // due to how the drop target layout is computed when we start dragging to the workspace.
+        mLauncher.showWorkspace(true);
+
+        if (v instanceof PagedViewIcon) {
+            beginDraggingApplication(v);
+        } else if (v instanceof PagedViewWidget) {
+            beginDraggingWidget(v);
+        }
+
+        return true;
+    }
+    private void endDragging(boolean success) {
+        post(new Runnable() {
+            // Once the drag operation has fully completed, hence the post, we want to disable the
+            // deleteZone and the appInfoButton in all apps, and re-enable the instance which
+            // live in the workspace
+            public void run() {
+                // if onDestroy was called on Launcher, we might have already deleted the
+                // all apps delete zone / info button, so check if they are null
+                DeleteZone allAppsDeleteZone =
+                        (DeleteZone) mLauncher.findViewById(R.id.all_apps_delete_zone);
+                ApplicationInfoDropTarget allAppsInfoButton =
+                    (ApplicationInfoDropTarget) mLauncher.findViewById(R.id.all_apps_info_target);
+
+                if (allAppsDeleteZone != null) allAppsDeleteZone.setDragAndDropEnabled(false);
+                if (allAppsInfoButton != null) allAppsInfoButton.setDragAndDropEnabled(false);
+            }
+        });
+        mLauncher.getWorkspace().onDragStopped(success);
+        mLauncher.unlockScreenOrientation();
+    }
+
+    /*
+     * DragSource implementation
+     */
+    @Override
+    public void onDragViewVisible() {}
+    @Override
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+        endDragging(success);
+
+        // Display an error message if the drag failed due to there not being enough space on the
+        // target layout we were dropping on.
+        if (!success) {
+            boolean showOutOfSpaceMessage = false;
+            if (target instanceof Workspace) {
+                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
+                Workspace workspace = (Workspace) target;
+                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
+                ItemInfo itemInfo = (ItemInfo) dragInfo;
+                if (layout != null) {
+                    layout.calculateSpans(itemInfo);
+                    showOutOfSpaceMessage =
+                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+                }
+            }
+            // TODO-APPS_CUSTOMIZE: We need to handle this for folders as well later.
+            if (showOutOfSpaceMessage) {
+                mLauncher.showOutOfSpaceMessage();
+            }
+        }
+    }
+
+    public void setContentType(ContentType type) {
+        mContentType = type;
+        setCurrentPage(0);
+        invalidatePageData();
+    }
+
+    /*
+     * Apps PagedView implementation
+     */
+    private void setVisibilityOnChildren(ViewGroup layout, int visibility) {
+        int childCount = layout.getChildCount();
+        for (int i = 0; i < childCount; ++i) {
+            layout.getChildAt(i).setVisibility(visibility);
+        }
+    }
+    private void setupPage(PagedViewCellLayout layout) {
+        layout.setCellCount(mCellCountX, mCellCountY);
+        layout.setGap(mPageLayoutWidthGap, mPageLayoutHeightGap);
+        layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+                mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+        // Note: We force a measure here to get around the fact that when we do layout calculations
+        // immediately after syncing, we don't have a proper width.  That said, we already know the
+        // expected page width, so we can actually optimize by hiding all the TextView-based
+        // children that are expensive to measure, and let that happen naturally later.
+        setVisibilityOnChildren(layout, View.GONE);
+        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+        layout.setMinimumWidth(getPageContentWidth());
+        layout.measure(widthSpec, heightSpec);
+        setVisibilityOnChildren(layout, View.VISIBLE);
+    }
+    public void syncAppsPages() {
+        // Ensure that we have the right number of pages
+        Context context = getContext();
+        int numPages = (int) Math.ceil((float) mApps.size() / (mCellCountX * mCellCountY));
+        for (int i = 0; i < numPages; ++i) {
+            PagedViewCellLayout layout = new PagedViewCellLayout(context);
+            setupPage(layout);
+            addView(layout);
+        }
+    }
+    public void syncAppsPageItems(int page) {
+        // ensure that we have the right number of items on the pages
+        int numPages = getPageCount();
+        int numCells = mCellCountX * mCellCountY;
+        int startIndex = page * numCells;
+        int endIndex = Math.min(startIndex + numCells, mApps.size());
+        PagedViewCellLayout layout = (PagedViewCellLayout) getChildAt(page);
+        layout.removeAllViewsOnPage();
+        for (int i = startIndex; i < endIndex; ++i) {
+            ApplicationInfo info = mApps.get(i);
+            PagedViewIcon icon = (PagedViewIcon) mLayoutInflater.inflate(
+                    R.layout.apps_customize_application, layout, false);
+            icon.applyFromApplicationInfo(
+                    info, mPageViewIconCache, true, isHardwareAccelerated() && (numPages > 1));
+            icon.setOnClickListener(this);
+            icon.setOnLongClickListener(this);
+            icon.setOnTouchListener(this);
+
+            int index = i - startIndex;
+            int x = index % mCellCountX;
+            int y = index / mCellCountX;
+            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+                    isHardwareAccelerated() && (numPages > 1));
+        }
+    }
+    /*
+     * Widgets PagedView implementation
+     */
+    private void setupPage(PagedViewGridLayout layout) {
+        layout.setPadding(mPageLayoutPaddingLeft, mPageLayoutPaddingTop,
+                mPageLayoutPaddingRight, mPageLayoutPaddingBottom);
+
+        // Note: We force a measure here to get around the fact that when we do layout calculations
+        // immediately after syncing, we don't have a proper width.  That said, we already know the
+        // expected page width, so we can actually optimize by hiding all the TextView-based
+        // children that are expensive to measure, and let that happen naturally later.
+        setVisibilityOnChildren(layout, View.GONE);
+        int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+        int heightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+        layout.setMinimumWidth(getPageContentWidth());
+        layout.measure(widthSpec, heightSpec);
+        setVisibilityOnChildren(layout, View.VISIBLE);
+    }
+    private void renderDrawableToBitmap(Drawable d, Bitmap bitmap, int x, int y, int w, int h,
+            float scaleX, float scaleY) {
+        Canvas c = new Canvas();
+        if (bitmap != null) c.setBitmap(bitmap);
+        c.save();
+        c.scale(scaleX, scaleY);
+        Rect oldBounds = d.copyBounds();
+        d.setBounds(x, y, x + w, y + h);
+        d.draw(c);
+        d.setBounds(oldBounds); // Restore the bounds
+        c.restore();
+    }
+    private FastBitmapDrawable getShortcutPreview(ResolveInfo info, int cellWidth, int cellHeight) {
+        // Return the cached version if necessary
+        Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+        if (cachedBitmap != null) {
+            return new FastBitmapDrawable(cachedBitmap);
+        }
+
+        Resources resources = mLauncher.getResources();
+        int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+        // We only need to make it wide enough so as not allow the preview to be scaled
+        int expectedWidth = cellWidth;
+        int expectedHeight = mWidgetPreviewIconPaddedDimension;
+        int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+
+        // Render the icon
+        Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+        Drawable icon = mIconCache.getFullResIcon(info, mPackageManager);
+        renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0,
+                mWidgetPreviewIconPaddedDimension, mWidgetPreviewIconPaddedDimension, 1f, 1f);
+        renderDrawableToBitmap(icon, preview, offset, offset, iconSize, iconSize, 1f, 1f);
+        FastBitmapDrawable iconDrawable = new FastBitmapDrawable(preview);
+        iconDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+        mWidgetPreviewCache.put(info, preview);
+        return iconDrawable;
+    }
+    private FastBitmapDrawable getWidgetPreview(AppWidgetProviderInfo info, int cellHSpan,
+            int cellVSpan, int cellWidth, int cellHeight) {
+        // Return the cached version if necessary
+        Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+        if (cachedBitmap != null) {
+            return new FastBitmapDrawable(cachedBitmap);
+        }
+
+        // Calculate the size of the drawable
+        cellHSpan = Math.max(mMinWidgetSpan, Math.min(mMaxWidgetSpan, cellHSpan));
+        cellVSpan = Math.max(mMinWidgetSpan, Math.min(mMaxWidgetSpan, cellVSpan));
+        int expectedWidth = mWidgetSpacingLayout.estimateCellWidth(cellHSpan);
+        int expectedHeight = mWidgetSpacingLayout.estimateCellHeight(cellVSpan);
+
+        // Scale down the bitmap to fit the space
+        float widgetPreviewScale = (float) cellWidth / expectedWidth;
+        expectedWidth = (int) (widgetPreviewScale * expectedWidth);
+        expectedHeight = (int) (widgetPreviewScale * expectedHeight);
+
+        // Load the preview image if possible
+        String packageName = info.provider.getPackageName();
+        Drawable drawable = null;
+        FastBitmapDrawable newDrawable = null;
+        if (info.previewImage != 0) {
+            drawable = mPackageManager.getDrawable(packageName, info.previewImage, null);
+            if (drawable == null) {
+                Log.w(LOG_TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
+                        + " for provider: " + info.provider);
+            } else {
+                // Scale down the preview to the dimensions we want
+                int imageWidth = drawable.getIntrinsicWidth();
+                int imageHeight = drawable.getIntrinsicHeight();
+                float aspect = (float) imageWidth / imageHeight;
+                int newWidth = imageWidth;
+                int newHeight = imageHeight;
+                if (aspect > 1f) {
+                    newWidth = expectedWidth;
+                    newHeight = (int) (imageHeight * ((float) expectedWidth / imageWidth));
+                } else {
+                    newHeight = expectedHeight;
+                    newWidth = (int) (imageWidth * ((float) expectedHeight / imageHeight));
+                }
+
+                Bitmap preview = Bitmap.createBitmap(newWidth, newHeight, Config.ARGB_8888);
+                renderDrawableToBitmap(drawable, preview, 0, 0, newWidth, newHeight, 1f, 1f);
+                newDrawable = new FastBitmapDrawable(preview);
+                newDrawable.setBounds(0, 0, newWidth, newHeight);
+                mWidgetPreviewCache.put(info, preview);
+            }
+        }
+
+        // Generate a preview image if we couldn't load one
+        if (drawable == null) {
+            Resources resources = mLauncher.getResources();
+            int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+
+            // Specify the dimensions of the bitmap
+            if (info.minWidth >= info.minHeight) {
+                expectedWidth = cellWidth;
+                expectedHeight = mWidgetPreviewIconPaddedDimension;
+            } else {
+                // Note that in vertical widgets, we might not have enough space due to the text
+                // label, so be conservative and use the width as a height bound
+                expectedWidth = mWidgetPreviewIconPaddedDimension;
+                expectedHeight = cellWidth;
+            }
+
+            Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+            renderDrawableToBitmap(mDefaultWidgetBackground, preview, 0, 0, expectedWidth,
+                    expectedHeight, 1f,1f);
+
+            // Draw the icon in the top left corner
+            try {
+                Drawable icon = null;
+                if (info.icon > 0) icon = mPackageManager.getDrawable(packageName, info.icon, null);
+                if (icon == null) icon = resources.getDrawable(R.drawable.ic_launcher_application);
+
+                int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+                renderDrawableToBitmap(icon, preview, offset, offset, iconSize, iconSize, 1f, 1f);
+            } catch (Resources.NotFoundException e) {}
+
+            newDrawable = new FastBitmapDrawable(preview);
+            newDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+            mWidgetPreviewCache.put(info, preview);
+        }
+        return newDrawable;
+    }
+    public void syncWidgetPages() {
+        // Ensure that we have the right number of pages
+        Context context = getContext();
+        int numWidgetsPerPage = mWidgetCountX * mWidgetCountY;
+        int numPages = (int) Math.ceil(mWidgets.size() / (float) numWidgetsPerPage);
+        for (int i = 0; i < numPages; ++i) {
+            PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
+                    mWidgetCountY);
+            setupPage(layout);
+            addView(layout);
+        }
+    }
+    public void syncWidgetPageItems(int page) {
+        PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(page);
+        layout.removeAllViews();
+
+        // Calculate the dimensions of each cell we are giving to each widget
+        int numWidgetsPerPage = mWidgetCountX * mWidgetCountY;
+        int offset = page * numWidgetsPerPage;
+        int cellWidth = ((mWidgetSpacingLayout.getContentWidth() - mPageLayoutWidthGap
+                - ((mWidgetCountX - 1) * mCellWidthGap)) / mWidgetCountX);
+        int cellHeight = ((mWidgetSpacingLayout.getContentHeight() - mPageLayoutHeightGap
+                - ((mWidgetCountY - 1) * mCellHeightGap)) / mWidgetCountY);
+        for (int i = 0; i < Math.min(numWidgetsPerPage, mWidgets.size() - offset); ++i) {
+            Object rawInfo = mWidgets.get(offset + i);
+            PendingAddItemInfo createItemInfo = null;
+            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
+                    R.layout.apps_customize_widget, layout, false);
+            if (rawInfo instanceof AppWidgetProviderInfo) {
+                // Fill in the widget information
+                AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo;
+                createItemInfo = new PendingAddWidgetInfo(info, null, null);
+                final int[] cellSpans = CellLayout.rectToCell(getResources(), info.minWidth,
+                        info.minHeight, null);
+                FastBitmapDrawable preview = getWidgetPreview(info, cellSpans[0], cellSpans[1],
+                        cellWidth, cellHeight);
+                widget.applyFromAppWidgetProviderInfo(info, preview, -1, cellSpans, null, false);
+                widget.setTag(createItemInfo);
+            } else if (rawInfo instanceof ResolveInfo) {
+                // Fill in the shortcuts information
+                ResolveInfo info = (ResolveInfo) rawInfo;
+                createItemInfo = new PendingAddItemInfo();
+                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+                createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
+                        info.activityInfo.name);
+                FastBitmapDrawable preview = getShortcutPreview(info, cellWidth, cellHeight);
+                widget.applyFromResolveInfo(mPackageManager, info, preview, null, false);
+                widget.setTag(createItemInfo);
+            }
+            widget.setOnClickListener(this);
+            widget.setOnLongClickListener(this);
+            widget.setOnTouchListener(this);
+
+            // Layout each widget
+            int ix = i % mWidgetCountX;
+            int iy = i / mWidgetCountX;
+            PagedViewGridLayout.LayoutParams lp = new PagedViewGridLayout.LayoutParams(cellWidth,
+                    cellHeight);
+            lp.leftMargin = (ix * cellWidth) + (ix * mCellWidthGap);
+            lp.topMargin = (iy * cellHeight) + (iy * mCellHeightGap);
+            layout.addView(widget, lp);
+        }
+    }
+
+    /*
+     * This method fetches an xml file specified in the manifest identified by
+     * WallpaperManager.WALLPAPER_PREVIEW_META_DATA). The xml file specifies
+     * an image which will be used as the wallpaper preview for an activity
+     * which responds to ACTION_SET_WALLPAPER. This image is returned and used
+     * in the customize drawer.
+     */
+    private Drawable parseWallpaperPreviewXml(ResolveInfo ri) {
+        ActivityInfo activityInfo = ri.activityInfo;
+        XmlResourceParser parser = null;
+        ComponentName component = new ComponentName(ri.activityInfo.packageName,
+                ri.activityInfo.name);
+        try {
+            parser = activityInfo.loadXmlMetaData(mPackageManager,
+                    WallpaperManager.WALLPAPER_PREVIEW_META_DATA);
+            if (parser == null) {
+                Slog.w(LOG_TAG, "No " + WallpaperManager.WALLPAPER_PREVIEW_META_DATA
+                        + " meta-data for " + "wallpaper provider '" + component + '\'');
+                return null;
+            }
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+                // drain whitespace, comments, etc.
+            }
+
+            String nodeName = parser.getName();
+            if (!"wallpaper-preview".equals(nodeName)) {
+                Slog.w(LOG_TAG, "Meta-data does not start with wallpaper-preview tag for "
+                        + "wallpaper provider '" + component + '\'');
+                return null;
+            }
+
+            // If metaData was null, we would have returned earlier when getting
+            // the parser No need to do the check here
+            Resources res = mPackageManager.getResourcesForApplication(
+                    activityInfo.applicationInfo);
+
+            TypedArray sa = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.WallpaperPreviewInfo);
+
+            TypedValue value = sa.peekValue(
+                    com.android.internal.R.styleable.WallpaperPreviewInfo_staticWallpaperPreview);
+            if (value == null) return null;
+
+            return res.getDrawable(value.resourceId);
+        } catch (Exception e) {
+            Slog.w(LOG_TAG, "XML parsing failed for wallpaper provider '" + component + '\'', e);
+            return null;
+        } finally {
+            if (parser != null) parser.close();
+        }
+    }
+    private FastBitmapDrawable getWallpaperPreview(ResolveInfo info, int cellWidth, int cellHeight){
+        // Return the cached version if necessary
+        Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
+        if (cachedBitmap != null) {
+            return new FastBitmapDrawable(cachedBitmap);
+        }
+
+        // Get the preview
+        Resources resources = getContext().getResources();
+        Drawable wallpaperPreview = parseWallpaperPreviewXml(info);
+        Drawable wallpaperIcon = null;
+        int expectedWidth;
+        int expectedHeight;
+        if (wallpaperPreview != null) {
+            expectedWidth = wallpaperPreview.getIntrinsicWidth();
+            expectedHeight = wallpaperPreview.getIntrinsicHeight();
+        } else {
+            wallpaperPreview = mDefaultWidgetBackground;
+            expectedWidth = expectedHeight = Math.min(cellWidth, cellHeight);
+
+            // Draw the icon in the top left corner
+            String packageName = info.activityInfo.packageName;
+            try {
+                if (info.icon > 0) {
+                    wallpaperIcon = mPackageManager.getDrawable(packageName, info.icon, null);
+                }
+                if (wallpaperIcon == null) {
+                    wallpaperIcon = resources.getDrawable(R.drawable.ic_launcher_application);
+                }
+            } catch (Resources.NotFoundException e) {}
+        }
+
+        // Create the bitmap
+        Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
+        renderDrawableToBitmap(wallpaperPreview, preview, 0, 0, expectedWidth, expectedHeight,
+                1f, 1f);
+        if (wallpaperIcon != null) {
+            int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
+            int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
+            renderDrawableToBitmap(wallpaperIcon, preview, offset, offset, iconSize, iconSize,
+                    1f, 1f);
+        }
+
+        FastBitmapDrawable previewDrawable = new FastBitmapDrawable(preview);
+        previewDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
+        mWidgetPreviewCache.put(info, preview);
+        return previewDrawable;
+    }
+    /*
+     * Wallpapers PagedView implementation
+     */
+    public void syncWallpaperPages() {
+        // Ensure that we have the right number of pages
+        Context context = getContext();
+        int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
+        int numPages = (int) Math.ceil(mWallpapers.size() / (float) numWidgetsPerPage);
+        for (int i = 0; i < numPages; ++i) {
+            PagedViewGridLayout layout = new PagedViewGridLayout(context, mWallpaperCountX,
+                    mWallpaperCountY);
+            setupPage(layout);
+            addView(layout);
+        }
+    }
+    public void syncWallpaperPageItems(int page) {
+        PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(page);
+        layout.removeAllViews();
+
+        // Calculate the dimensions of each cell we are giving to each widget
+        int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
+        int offset = page * numWidgetsPerPage;
+        int cellWidth = ((mWidgetSpacingLayout.getContentWidth() - mPageLayoutWidthGap
+                - ((mWallpaperCountX - 1) * mCellWidthGap)) / mWallpaperCountX);
+        int cellHeight = ((mWidgetSpacingLayout.getContentHeight() - mPageLayoutHeightGap
+                - ((mWallpaperCountY - 1) * mCellHeightGap)) / mWallpaperCountY);
+        for (int i = 0; i < Math.min(numWidgetsPerPage, mWallpapers.size() - offset); ++i) {
+            ResolveInfo info = mWallpapers.get(offset + i);
+            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
+                    R.layout.apps_customize_wallpaper, layout, false);
+
+            // Fill in the shortcuts information
+            FastBitmapDrawable preview = getWallpaperPreview(info, cellWidth, cellHeight);
+            widget.applyFromResolveInfo(mPackageManager, info, preview, null, false);
+            widget.setTag(info);
+            widget.setOnClickListener(this);
+            widget.setOnLongClickListener(this);
+            widget.setOnTouchListener(this);
+
+            // Layout each widget
+            int ix = i % mWallpaperCountX;
+            int iy = i / mWallpaperCountX;
+            PagedViewGridLayout.LayoutParams lp = new PagedViewGridLayout.LayoutParams(cellWidth,
+                    cellHeight);
+            lp.leftMargin = (ix * cellWidth) + (ix * mCellWidthGap);
+            lp.topMargin = (iy * cellHeight) + (iy * mCellHeightGap);
+            layout.addView(widget, lp);
+        }
+    }
+
+    @Override
+    public void syncPages() {
+        removeAllViews();
+        switch (mContentType) {
+        case Applications:
+            syncAppsPages();
+            break;
+        case Widgets:
+            syncWidgetPages();
+            break;
+        case Wallpapers:
+            syncWallpaperPages();
+            break;
+        }
+    }
+    @Override
+    public void syncPageItems(int page) {
+        switch (mContentType) {
+        case Applications:
+            syncAppsPageItems(page);
+            break;
+        case Widgets:
+            syncWidgetPageItems(page);
+            break;
+        case Wallpapers:
+            syncWallpaperPageItems(page);
+            break;
+        }
+    }
+
+    /**
+     * Used by the parent to get the content width to set the tab bar to
+     * @return
+     */
+    public int getPageContentWidth() {
+        return mContentWidth;
+    }
+
+    /*
+     * AllAppsView implementation
+     */
+    @Override
+    public void setup(Launcher launcher, DragController dragController) {
+        mLauncher = launcher;
+        mDragController = dragController;
+    }
+    @Override
+    public void zoom(float zoom, boolean animate) {
+        // TODO-APPS_CUSTOMIZE: Call back to mLauncher.zoomed()
+    }
+    @Override
+    public boolean isVisible() {
+        return (getVisibility() == VISIBLE);
+    }
+    @Override
+    public boolean isAnimating() {
+        return false;
+    }
+    @Override
+    public void setApps(ArrayList<ApplicationInfo> list) {
+        mApps = list;
+        Collections.sort(mApps, LauncherModel.APP_NAME_COMPARATOR);
+        invalidatePageData();
+    }
+    private void addAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+        // We add it in place, in alphabetical order
+        int count = list.size();
+        for (int i = 0; i < count; ++i) {
+            ApplicationInfo info = list.get(i);
+            int index = Collections.binarySearch(mApps, info, LauncherModel.APP_NAME_COMPARATOR);
+            if (index < 0) {
+                mApps.add(-(index + 1), info);
+            }
+        }
+    }
+    @Override
+    public void addApps(ArrayList<ApplicationInfo> list) {
+        addAppsWithoutInvalidate(list);
+        invalidatePageData();
+    }
+    private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
+        ComponentName removeComponent = item.intent.getComponent();
+        int length = list.size();
+        for (int i = 0; i < length; ++i) {
+            ApplicationInfo info = list.get(i);
+            if (info.intent.getComponent().equals(removeComponent)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+    private void removeAppsWithoutInvalidate(ArrayList<ApplicationInfo> list) {
+        // loop through all the apps and remove apps that have the same component
+        int length = list.size();
+        for (int i = 0; i < length; ++i) {
+            ApplicationInfo info = list.get(i);
+            int removeIndex = findAppByComponent(mApps, info);
+            if (removeIndex > -1) {
+                mApps.remove(removeIndex);
+                mPageViewIconCache.removeOutline(new PagedViewIconCache.Key(info));
+            }
+        }
+    }
+    @Override
+    public void removeApps(ArrayList<ApplicationInfo> list) {
+        removeAppsWithoutInvalidate(list);
+        invalidatePageData();
+    }
+    @Override
+    public void updateApps(ArrayList<ApplicationInfo> list) {
+        // We remove and re-add the updated applications list because it's properties may have
+        // changed (ie. the title), and this will ensure that the items will be in their proper
+        // place in the list.
+        removeAppsWithoutInvalidate(list);
+        addAppsWithoutInvalidate(list);
+        invalidatePageData();
+    }
+    @Override
+    public void reset() {
+        if (mContentType != ContentType.Applications) {
+            // Reset to the first page of the Apps pane
+            AppsCustomizeTabHost tabs = (AppsCustomizeTabHost)
+                    mLauncher.findViewById(R.id.apps_customize_pane);
+            tabs.setCurrentTabByTag(tabs.getTabTagForContentType(ContentType.Applications));
+        } else {
+            setCurrentPage(0);
+            invalidatePageData();
+        }
+    }
+    @Override
+    public void dumpState() {
+        // TODO: Dump information related to current list of Applications, Widgets, etc.
+        ApplicationInfo.dumpApplicationInfoList(LOG_TAG, "mApps", mApps);
+        dumpAppWidgetProviderInfoList(LOG_TAG, "mWidgets", mWidgets);
+    }
+    private void dumpAppWidgetProviderInfoList(String tag, String label,
+            List<Object> list) {
+        Log.d(tag, label + " size=" + list.size());
+        for (Object i: list) {
+            if (i instanceof AppWidgetProviderInfo) {
+                AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
+                Log.d(tag, "   label=\"" + info.label + "\" previewImage=" + info.previewImage
+                        + " resizeMode=" + info.resizeMode + " configure=" + info.configure
+                        + " initialLayout=" + info.initialLayout
+                        + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
+            } else if (i instanceof ResolveInfo) {
+                ResolveInfo info = (ResolveInfo) i;
+                Log.d(tag, "   label=\"" + info.loadLabel(mPackageManager) + "\" icon="
+                        + info.icon);
+            }
+        }
+    }
+    @Override
+    public void surrender() {
+        // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
+        // should stop this now.
+    }
+}
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
new file mode 100644
index 0000000..e2d21b6
--- /dev/null
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TabHost;
+import android.widget.TextView;
+
+import com.android.launcher.R;
+
+public class AppsCustomizeTabHost extends TabHost implements LauncherTransitionable,
+        TabHost.OnTabChangeListener  {
+    static final String LOG_TAG = "AppsCustomizeTabHost";
+
+    private static final String APPS_TAB_TAG = "APPS";
+    private static final String WIDGETS_TAB_TAG = "WIDGETS";
+    private static final String WALLPAPERS_TAB_TAG = "WALLPAPERS";
+
+    private final LayoutInflater mLayoutInflater;
+
+    public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mLayoutInflater = LayoutInflater.from(context);
+    }
+
+    /**
+     * Setup the tab host and create all necessary tabs.
+     */
+    @Override
+    protected void onFinishInflate() {
+        // Setup the tab host
+        setup();
+
+        final ViewGroup tabs = (ViewGroup) findViewById(com.android.internal.R.id.tabs);
+        final AppsCustomizePagedView content = (AppsCustomizePagedView)
+                findViewById(R.id.apps_customize_pane_content);
+        if (tabs == null || content == null) throw new Resources.NotFoundException();
+
+        // Configure the tabs content factory to return the same paged view (that we change the
+        // content filter on)
+        TabContentFactory contentFactory = new TabContentFactory() {
+            public View createTabContent(String tag) {
+                return content;
+            }
+        };
+
+        // Create the tabs
+        TextView tabView;
+        tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+        tabView.setText(mContext.getString(R.string.all_apps_button_label));
+        addTab(newTabSpec(APPS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+        tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+        tabView.setText(mContext.getString(R.string.widgets_tab_label));
+        addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+        tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
+        tabView.setText(mContext.getString(R.string.wallpapers_tab_label));
+        addTab(newTabSpec(WALLPAPERS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
+        setOnTabChangedListener(this);
+
+        // Set the width of the tab bar to match the content (for now)
+        tabs.getLayoutParams().width = content.getPageContentWidth();
+    }
+
+    @Override
+    public void onTabChanged(String tabId) {
+        final AppsCustomizePagedView content = (AppsCustomizePagedView)
+                findViewById(R.id.apps_customize_pane_content);
+        content.setContentType(getContentTypeForTabTag(tabId));
+    }
+
+    /**
+     * Returns the content type for the specified tab tag.
+     */
+    public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
+        if (tag.equals(APPS_TAB_TAG)) {
+            return AppsCustomizePagedView.ContentType.Applications;
+        } else if (tag.equals(WIDGETS_TAB_TAG)) {
+            return AppsCustomizePagedView.ContentType.Widgets;
+        } else if (tag.equals(WALLPAPERS_TAB_TAG)) {
+            return AppsCustomizePagedView.ContentType.Wallpapers;
+        }
+        return AppsCustomizePagedView.ContentType.Applications;
+    }
+
+    /**
+     * Returns the tab tag for a given content type.
+     */
+    public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
+        if (type == AppsCustomizePagedView.ContentType.Applications) {
+            return APPS_TAB_TAG;
+        } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
+            return WIDGETS_TAB_TAG;
+        } else if (type == AppsCustomizePagedView.ContentType.Wallpapers) {
+            return WALLPAPERS_TAB_TAG;
+        }
+        return APPS_TAB_TAG;
+    }
+
+    /**
+     * Disable focus on anything under this view in the hierarchy if we are not visible.
+     */
+    @Override
+    public int getDescendantFocusability() {
+        if (getVisibility() != View.VISIBLE) {
+            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+        }
+        return super.getDescendantFocusability();
+    }
+
+    /* LauncherTransitionable overrides */
+    @Override
+    public void onLauncherTransitionStart(android.animation.Animator animation) {
+        // TODO-APPS_CUSTOMIZE: see AllAppsTabbed.onLauncherTransitionStart();
+    }
+    @Override
+    public void onLauncherTransitionEnd(android.animation.Animator animation) {
+        // TODO-APPS_CUSTOMIZE: see AllAppsTabbed.onLauncherTransitionEnd();
+    }
+}
diff --git a/src/com/android/launcher2/BubbleTextView.java b/src/com/android/launcher2/BubbleTextView.java
index 1464854..703b3a8 100644
--- a/src/com/android/launcher2/BubbleTextView.java
+++ b/src/com/android/launcher2/BubbleTextView.java
@@ -29,6 +29,7 @@
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.TextView;
@@ -87,8 +88,6 @@
 
     private void init() {
         mBackground = getBackground();
-        setFocusable(true);
-        setBackgroundDrawable(null);
 
         final Resources res = getContext().getResources();
         int bubbleColor = res.getColor(R.color.bubble_dark_background);
@@ -330,4 +329,16 @@
         }
         return true;
     }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return FocusHelper.handleBubbleTextViewKeyEvent(this, keyCode, event)
+                || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return FocusHelper.handleBubbleTextViewKeyEvent(this, keyCode, event)
+                || super.onKeyUp(keyCode, event);
+    }
 }
diff --git a/src/com/android/launcher2/CachedTextView.java b/src/com/android/launcher2/CachedTextView.java
index 403d856..d0f6dd8 100644
--- a/src/com/android/launcher2/CachedTextView.java
+++ b/src/com/android/launcher2/CachedTextView.java
@@ -18,10 +18,11 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.Bitmap.Config;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.Drawable;
 import android.text.Layout;
 import android.util.AttributeSet;
 import android.widget.TextView;
@@ -163,6 +164,16 @@
         if (mPrevAlpha != alpha) {
             mPrevAlpha = alpha;
             mCachePaint.setAlpha(alpha);
+
+            // We manually update the drawables alpha since the default TextView implementation may
+            // not do this if there is a background set (which we may due to the focus bg)
+            final Drawable[] dr = getCompoundDrawables();
+            for (int i = 0; i < dr.length; ++i) {
+                if (dr[i] != null) {
+                    dr[i].mutate().setAlpha(alpha);
+                }
+            }
+
             super.onSetAlpha(alpha);
         }
         return true;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 1111c53..8efb6ce 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.Arrays;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -39,7 +39,6 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.ContextMenu;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
@@ -48,7 +47,7 @@
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LayoutAnimationController;
 
-import java.util.Arrays;
+import com.android.launcher.R;
 
 public class CellLayout extends ViewGroup {
     static final String TAG = "CellLayout";
@@ -95,7 +94,7 @@
     private float mGlowBackgroundScale;
     private float mGlowBackgroundAlpha;
 
-    private boolean mAcceptsDrops = false;
+    private boolean mAcceptsDrops = true;
     // If we're actively dragging something over this screen, mIsDragOverlapping is true
     private boolean mIsDragOverlapping = false;
     private boolean mIsDragOccuring = false;
@@ -104,7 +103,7 @@
 
     // These arrays are used to implement the drag visualization on x-large screens.
     // They are used as circular arrays, indexed by mDragOutlineCurrent.
-    private Point[] mDragOutlines = new Point[8];
+    private Point[] mDragOutlines = new Point[4];
     private float[] mDragOutlineAlphas = new float[mDragOutlines.length];
     private InterruptibleInOutAnimator[] mDragOutlineAnims =
             new InterruptibleInOutAnimator[mDragOutlines.length];
@@ -168,7 +167,7 @@
 
         final Resources res = getResources();
 
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             mNormalBackground = res.getDrawable(R.drawable.homescreen_large_blue);
             mActiveBackground = res.getDrawable(R.drawable.homescreen_large_green);
             mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_large_green_strong);
@@ -264,17 +263,16 @@
         setHoverAlpha(1.0f);
 
         mChildren = new CellLayoutChildren(context);
-        mChildren.setCellDimensions(
-                mCellWidth, mCellHeight, mLeftPadding, mTopPadding, mWidthGap, mHeightGap);
+        mChildren.setCellDimensions(mCellWidth, mCellHeight, mWidthGap, mHeightGap);
         addView(mChildren);
     }
 
     private void invalidateBubbleTextView(BubbleTextView icon) {
         final int padding = icon.getPressedOrFocusedBackgroundPadding();
-        invalidate(icon.getLeft() - padding,
-                icon.getTop() - padding,
-                icon.getRight() + padding,
-                icon.getBottom() + padding);
+        invalidate(icon.getLeft() + getLeftPadding() - padding,
+                icon.getTop() + getTopPadding() - padding,
+                icon.getRight() + getLeftPadding() + padding,
+                icon.getBottom() + getTopPadding() + padding);
     }
 
     void setPressedOrFocusedIcon(BubbleTextView icon) {
@@ -355,7 +353,7 @@
     }
 
     void animateDrop() {
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             Resources res = getResources();
             float onDropScale = res.getInteger(R.integer.config_screenOnDropScalePercent) / 100.0f;
             ObjectAnimator scaleUp = ObjectAnimator.ofFloat(this, "hoverScale", onDropScale);
@@ -393,7 +391,7 @@
         // When we're small, we are either drawn normally or in the "accepts drops" state (during
         // a drag). However, we also drag the mini hover background *over* one of those two
         // backgrounds
-        if (LauncherApplication.isScreenXLarge() && mBackgroundAlpha > 0.0f) {
+        if (LauncherApplication.isScreenLarge() && mBackgroundAlpha > 0.0f) {
             Drawable bg;
             boolean mini = getScaleX() < 0.5f;
 
@@ -488,8 +486,8 @@
             final Bitmap b = mPressedOrFocusedIcon.getPressedOrFocusedBackground();
             if (b != null) {
                 canvas.drawBitmap(b,
-                        mPressedOrFocusedIcon.getLeft() - padding,
-                        mPressedOrFocusedIcon.getTop() - padding,
+                        mPressedOrFocusedIcon.getLeft() + getLeftPadding() - padding,
+                        mPressedOrFocusedIcon.getTop() + getTopPadding() - padding,
                         null);
             }
         }
@@ -736,6 +734,22 @@
         result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
     }
 
+    /**
+     * Given a cell coordinate, return the point that represents the upper left corner of that cell
+     *
+     * @param cellX X coordinate of the cell
+     * @param cellY Y coordinate of the cell
+     *
+     * @param result Array of 2 ints to hold the x and y coordinate of the point
+     */
+    void cellToCenterPoint(int cellX, int cellY, int[] result) {
+        final int hStartPadding = getLeftPadding();
+        final int vStartPadding = getTopPadding();
+
+        result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap) + mCellWidth / 2;
+        result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap) + mCellHeight / 2;
+    }
+
     int getCellWidth() {
         return mCellWidth;
     }
@@ -768,6 +782,18 @@
         return mBottomPadding;
     }
 
+    Rect getContentRect(Rect r) {
+        if (r == null) {
+            r = new Rect();
+        }
+        int left = getPaddingLeft();
+        int top = getPaddingTop();
+        int right = left + getWidth() - mLeftPadding - mRightPadding;
+        int bottom = top + getHeight() - mTopPadding - mBottomPadding;
+        r.set(left, top, right, bottom);
+        return r;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // TODO: currently ignoring padding
@@ -827,7 +853,7 @@
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
-            child.layout(0, 0, r - l, b - t);
+            child.layout(mLeftPadding, mTopPadding, r - l - mRightPadding , b - t - mBottomPadding);
         }
     }
 
@@ -956,15 +982,23 @@
             int top = topLeft[1];
 
             if (v != null) {
-                if (v.getParent() instanceof CellLayout) {
-                    LayoutParams lp = (LayoutParams) v.getLayoutParams();
-                    left += lp.leftMargin;
-                    top += lp.topMargin;
-                }
+                // When drawing the drag outline, it did not account for margin offsets
+                // added by the view's parent.
+                MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
+                left += lp.leftMargin;
+                top += lp.topMargin;
 
-                // Offsets due to the size difference between the View and the dragOutline
+                // Offsets due to the size difference between the View and the dragOutline.
+                // There is a size difference to account for the outer blur, which may lie
+                // outside the bounds of the view.
                 left += (v.getWidth() - dragOutline.getWidth()) / 2;
                 top += (v.getHeight() - dragOutline.getHeight()) / 2;
+            } else {
+                // Center the drag outline in the cell
+                left += ((mCellWidth * spanX) + ((spanX - 1) * mWidthGap)
+                        - dragOutline.getWidth()) / 2;
+                top += ((mCellHeight * spanY) + ((spanY - 1) * mHeightGap)
+                        - dragOutline.getHeight()) / 2;
             }
 
             final int oldIndex = mDragOutlineCurrent;
@@ -982,6 +1016,13 @@
         }
     }
 
+    public void clearDragOutlines() {
+        final int oldIndex = mDragOutlineCurrent;
+        mDragOutlineAnims[oldIndex].animateOut();
+        mDragCell[0] = -1;
+        mDragCell[1] = -1;
+    }
+
     /**
      * Find a vacant area that will fit the given bounds nearest the requested
      * cell location. Uses Euclidean distance to score multiple vacant areas.
@@ -1008,16 +1049,23 @@
      * @param pixelY The Y location at which you want to search for a vacant area.
      * @param spanX Horizontal span of the object.
      * @param spanY Vertical span of the object.
-     * @param ignoreView Considers space occupied by this view as unoccupied
-     * @param result Previously returned value to possibly recycle.
+     * @param ignoreOccupied If true, the result can be an occupied cell
+     * @param result Array in which to place the result, or null (in which case a new array will
+     *        be allocated)
      * @return The X, Y cell of a vacant area that can contain this object,
      *         nearest the requested location.
      */
-    int[] findNearestVacantArea(
-            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
+    int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
+            boolean ignoreOccupied, int[] result) {
         // mark space take by ignoreView as available (method checks if ignoreView is null)
         markCellsAsUnoccupiedForView(ignoreView);
 
+        // For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
+        // to the center of the item, but we are searching based on the top-left cell, so
+        // we translate the point over to correspond to the top-left.
+        pixelX -= (mCellWidth + mWidthGap) * (spanX - 1) / 2f;
+        pixelY -= (mCellHeight + mHeightGap) * (spanY - 1) / 2f;
+
         // Keep track of best-scoring drop area
         final int[] bestXY = result != null ? result : new int[2];
         double bestDistance = Double.MAX_VALUE;
@@ -1029,18 +1077,20 @@
         for (int y = 0; y < countY - (spanY - 1); y++) {
             inner:
             for (int x = 0; x < countX - (spanX - 1); x++) {
-                for (int i = 0; i < spanX; i++) {
-                    for (int j = 0; j < spanY; j++) {
-                        if (occupied[x + i][y + j]) {
-                            // small optimization: we can skip to after the column we just found
-                            // an occupied cell
-                            x += i;
-                            continue inner;
+                if (ignoreOccupied) {
+                    for (int i = 0; i < spanX; i++) {
+                        for (int j = 0; j < spanY; j++) {
+                            if (occupied[x + i][y + j]) {
+                                // small optimization: we can skip to after the column we
+                                // just found an occupied cell
+                                x += i;
+                                continue inner;
+                            }
                         }
                     }
                 }
                 final int[] cellXY = mTmpCellXY;
-                cellToPoint(x, y, cellXY);
+                cellToCenterPoint(x, y, cellXY);
 
                 double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
                         + Math.pow(cellXY[1] - pixelY, 2));
@@ -1062,6 +1112,42 @@
         }
     }
 
+    /**
+     * Find a vacant area that will fit the given bounds nearest the requested
+     * cell location. Uses Euclidean distance to score multiple vacant areas.
+     *
+     * @param pixelX The X location at which you want to search for a vacant area.
+     * @param pixelY The Y location at which you want to search for a vacant area.
+     * @param spanX Horizontal span of the object.
+     * @param spanY Vertical span of the object.
+     * @param ignoreView Considers space occupied by this view as unoccupied
+     * @param result Previously returned value to possibly recycle.
+     * @return The X, Y cell of a vacant area that can contain this object,
+     *         nearest the requested location.
+     */
+    int[] findNearestVacantArea(
+            int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
+        return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
+    }
+
+    /**
+     * Find a starting cell position that will fit the given bounds nearest the requested
+     * cell location. Uses Euclidean distance to score multiple vacant areas.
+     *
+     * @param pixelX The X location at which you want to search for a vacant area.
+     * @param pixelY The Y location at which you want to search for a vacant area.
+     * @param spanX Horizontal span of the object.
+     * @param spanY Vertical span of the object.
+     * @param ignoreView Considers space occupied by this view as unoccupied
+     * @param result Previously returned value to possibly recycle.
+     * @return The X, Y cell of a vacant area that can contain this object,
+     *         nearest the requested location.
+     */
+    int[] findNearestArea(
+            int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+        return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+    }
+
     boolean existsEmptyCell() {
         return findCellForSpan(null, 1, 1);
     }
@@ -1457,6 +1543,14 @@
         }
     }
 
+    public boolean isOccupied(int x, int y) {
+        if (x < mCountX && y < mCountY) {
+            return mOccupied[x][y];
+        } else {
+            throw new RuntimeException("Position exceeds the bound of this CellLayout");
+        }
+    }
+
     @Override
     public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
         return new CellLayout.LayoutParams(getContext(), attrs);
@@ -1570,8 +1664,7 @@
             this.cellVSpan = cellVSpan;
         }
 
-        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
-                int hStartPadding, int vStartPadding) {
+        public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap) {
             if (isLockedToGrid) {
                 final int myCellHSpan = cellHSpan;
                 final int myCellVSpan = cellVSpan;
@@ -1582,11 +1675,15 @@
                         leftMargin - rightMargin;
                 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
                         topMargin - bottomMargin;
-                x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
-                y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+                x = myCellX * (cellWidth + widthGap) + leftMargin;
+                y = myCellY * (cellHeight + heightGap) + topMargin;
             }
         }
 
+        public String toString() {
+            return "(" + this.cellX + ", " + this.cellY + ")";
+        }
+
         public void setWidth(int width) {
             this.width = width;
         }
@@ -1618,10 +1715,6 @@
         public int getY() {
             return y;
         }
-
-        public String toString() {
-            return "(" + this.cellX + ", " + this.cellY + ")";
-        }
     }
 
     // This class stores info for two purposes:
@@ -1630,7 +1723,7 @@
     // 2. When long clicking on an empty cell in a CellLayout, we save information about the
     //    cellX and cellY coordinates and which page was clicked. We then set this as a tag on
     //    the CellLayout that was long clicked
-    static final class CellInfo implements ContextMenu.ContextMenuInfo {
+    static final class CellInfo {
         View cell;
         int cellX = -1;
         int cellY = -1;
diff --git a/src/com/android/launcher2/CellLayoutChildren.java b/src/com/android/launcher2/CellLayoutChildren.java
index 04996f3..f9adce0 100644
--- a/src/com/android/launcher2/CellLayoutChildren.java
+++ b/src/com/android/launcher2/CellLayoutChildren.java
@@ -16,12 +16,9 @@
 
 package com.android.launcher2;
 
-import java.util.ArrayList;
-
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Rect;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -34,33 +31,21 @@
 
     private final WallpaperManager mWallpaperManager;
 
-    private int mLeftPadding;
-    private int mTopPadding;
-
     private int mCellWidth;
     private int mCellHeight;
 
     private int mWidthGap;
     private int mHeightGap;
 
-    // Variables relating to resizing widgets
-    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
-            new ArrayList<AppWidgetResizeFrame>();
-    private AppWidgetResizeFrame mCurrentResizeFrame;
-    private int mXDown, mYDown;
-
     public CellLayoutChildren(Context context) {
         super(context);
         mWallpaperManager = WallpaperManager.getInstance(context);
         setLayerType(LAYER_TYPE_HARDWARE, null);
     }
 
-    public void setCellDimensions(int cellWidth, int cellHeight,
-            int leftPadding, int topPadding, int widthGap, int heightGap ) {
+    public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) {
         mCellWidth = cellWidth;
         mCellHeight = cellHeight;
-        mLeftPadding = leftPadding;
-        mTopPadding = topPadding;
         mWidthGap = widthGap;
         mHeightGap = heightGap;
     }
@@ -72,7 +57,7 @@
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
 
             if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
-                    (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
+                    (lp.cellY <= y) && (y < lp.cellY + lp.cellVSpan)) {
                 return child;
             }
         }
@@ -81,27 +66,29 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int cellWidth = mCellWidth;
-        final int cellHeight = mCellHeight;
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
-            lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
-                    mLeftPadding, mTopPadding);
-
-            int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-            int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
-                    MeasureSpec.EXACTLY);
-
-            child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+            measureChild(child);
         }
         int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
         int heightSpecSize =  MeasureSpec.getSize(heightMeasureSpec);
         setMeasuredDimension(widthSpecSize, heightSpecSize);
     }
 
+    public void measureChild(View child) {
+        final int cellWidth = mCellWidth;
+        final int cellHeight = mCellHeight;
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+
+        lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap);
+        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+        int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
+                MeasureSpec.EXACTLY);
+
+        child.measure(childWidthMeasureSpec, childheightMeasureSpec);
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int count = getChildCount();
@@ -176,95 +163,4 @@
     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
         super.setChildrenDrawnWithCacheEnabled(enabled);
     }
-
-    public void clearAllResizeFrames() {
-        for (AppWidgetResizeFrame frame: mResizeFrames) {
-            removeView(frame);
-        }
-        mResizeFrames.clear();
-    }
-
-    public boolean hasResizeFrames() {
-        return mResizeFrames.size() > 0;
-    }
-
-    public boolean isWidgetBeingResized() {
-        return mCurrentResizeFrame != null;
-    }
-
-    private boolean handleTouchDown(MotionEvent ev) {
-        Rect hitRect = new Rect();
-
-        int x = (int) ev.getX();
-        int y = (int) ev.getY();
-
-        for (AppWidgetResizeFrame child: mResizeFrames) {
-            child.getHitRect(hitRect);
-            if (hitRect.contains(x, y)) {
-                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
-                    mCurrentResizeFrame = child;
-                    mXDown = x;
-                    mYDown = y;
-                    requestDisallowInterceptTouchEvent(true);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            if (handleTouchDown(ev)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean handled = false;
-        int action = ev.getAction();
-
-        int x = (int) ev.getX();
-        int y = (int) ev.getY();
-
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-                if (handleTouchDown(ev)) {
-                    return true;
-                }
-            }
-        }
-
-        if (mCurrentResizeFrame != null) {
-            handled = true;
-            switch (action) {
-                case MotionEvent.ACTION_MOVE:
-                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
-                    break;
-                case MotionEvent.ACTION_CANCEL:
-                case MotionEvent.ACTION_UP:
-                    mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
-                    mCurrentResizeFrame = null;
-            }
-        }
-        return handled;
-    }
-
-    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
-            CellLayout cellLayout) {
-        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
-                itemInfo, widget, cellLayout);
-
-        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(-1, -1, -1, -1);
-        lp.isLockedToGrid = false;
-
-        addView(resizeFrame, lp);
-        mResizeFrames.add(resizeFrame);
-
-        resizeFrame.snapToWidget(false);
-    }
 }
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 36a638b..e5bc8b8 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -172,12 +172,12 @@
         final Resources r = context.getResources();
         setDragSlopeThreshold(
                 r.getInteger(R.integer.config_customizationDrawerDragSlopeThreshold) / 100.0f);
-        mMinPageWidth = r.getDimensionPixelSize(R.dimen.customization_drawer_content_min_width);
 
         // Create a dummy page and set it up to find out the content width (used by our parent)
         PagedViewCellLayout layout = new PagedViewCellLayout(getContext());
         setupPage(layout);
         mPageContentWidth = layout.getContentWidth();
+        mMinPageWidth = layout.getWidthBeforeFirstLayout();
 
         setVisibility(View.GONE);
         setSoundEffectsEnabled(false);
@@ -301,13 +301,8 @@
             }
         });
 
-        Comparator<ResolveInfo> resolveInfoComparator = new Comparator<ResolveInfo>() {
-            @Override
-            public int compare(ResolveInfo object1, ResolveInfo object2) {
-                return object1.loadLabel(mPackageManager).toString().compareTo(
-                        object2.loadLabel(mPackageManager).toString());
-            }
-        };
+        LauncherModel.ShortcutNameComparator resolveInfoComparator =
+                new LauncherModel.ShortcutNameComparator(mPackageManager);
 
         // get the list of shortcuts
         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
@@ -488,8 +483,6 @@
 
     @Override
     public void onClick(final View v) {
-        // Return early if this is not initiated from a touch
-        if (!v.isInTouchMode()) return;
         // Return early if we are still animating the pages
         if (mNextPage != INVALID_PAGE) return;
 
@@ -936,12 +929,13 @@
             final int[] cellSpans = CellLayout.rectToCell(getResources(), info.minWidth,
                     info.minHeight, null);
             final FastBitmapDrawable icon = getWidgetPreview(info);
+            final boolean createHolographicOutlines = (numPages > 1);
 
             PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
                     R.layout.customize_paged_view_widget, layout, false);
 
             l.applyFromAppWidgetProviderInfo(info, icon, mMaxWidgetWidth, cellSpans,
-                    mPageViewIconCache, (numPages > 1));
+                    mPageViewIconCache, createHolographicOutlines);
             l.setTag(createItemInfo);
             l.setOnClickListener(this);
             l.setOnTouchListener(this);
@@ -982,11 +976,12 @@
         for (int i = startIndex; i < endIndex; ++i) {
             final ResolveInfo info = mWallpaperList.get(i);
             final FastBitmapDrawable icon = getWallpaperPreview(info);
+            final boolean createHolographicOutlines = (numPages > 1);
 
             PagedViewWidget l = (PagedViewWidget) mInflater.inflate(
                     R.layout.customize_paged_view_wallpaper, layout, false);
             l.applyFromWallpaperInfo(info, mPackageManager, icon, mMaxWidgetWidth,
-                    mPageViewIconCache, (numPages > 1));
+                    mPageViewIconCache, createHolographicOutlines);
             l.setTag(info);
             l.setOnClickListener(this);
 
@@ -1019,12 +1014,13 @@
         for (int i = startIndex; i < endIndex; ++i) {
             ResolveInfo info = list.get(i);
             PendingAddItemInfo createItemInfo = new PendingAddItemInfo();
+            final boolean createHolographicOutlines = (numPages > 1);
 
             PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
                     R.layout.customize_paged_view_item, layout, false);
             icon.applyFromResolveInfo(info, mPackageManager, mPageViewIconCache,
                     ((LauncherApplication) mLauncher.getApplication()).getIconCache(),
-                    (numPages > 1));
+                    createHolographicOutlines);
             switch (mCustomizationType) {
             case WallpaperCustomization:
                 icon.setOnClickListener(this);
@@ -1046,7 +1042,8 @@
             final int x = index % mCellCountX;
             final int y = index / mCellCountX;
             setupPage(layout);
-            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+                    createHolographicOutlines);
         }
     }
 
@@ -1078,9 +1075,11 @@
         layout.removeAllViewsOnPage();
         for (int i = startIndex; i < endIndex; ++i) {
             final ApplicationInfo info = mApps.get(i);
+            final boolean createHolographicOutlines = (numPages > 1);
             PagedViewIcon icon = (PagedViewIcon) mInflater.inflate(
                     R.layout.all_apps_paged_view_application, layout, false);
-            icon.applyFromApplicationInfo(info, mPageViewIconCache, true, (numPages > 1));
+            icon.applyFromApplicationInfo(
+                    info, mPageViewIconCache, true, createHolographicOutlines);
             icon.setOnClickListener(this);
             icon.setOnTouchListener(this);
             icon.setOnLongClickListener(this);
@@ -1089,7 +1088,8 @@
             final int x = index % mCellCountX;
             final int y = index / mCellCountX;
             setupPage(layout);
-            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1));
+            layout.addViewToCellLayout(icon, -1, i, new PagedViewCellLayout.LayoutParams(x,y, 1,1),
+                    createHolographicOutlines);
         }
     }
 
@@ -1135,8 +1135,10 @@
         }
 
         // Set a min page width for PagedView layout if we have more than a single page
-        if (enforceMinimumPagedWidths) {
-            setMinimumWidthOverride((childCount > 1) ? mMinPageWidth : 0);
+        if (enforceMinimumPagedWidths && childCount > 1) {
+            setMinimumWidthOverride(mMinPageWidth);
+        } else {
+            resetMinimumWidthOverride();
         }
 
         // Bound the current page index
diff --git a/src/com/android/launcher2/CustomizeTrayTabHost.java b/src/com/android/launcher2/CustomizeTrayTabHost.java
index 3e04025..2c47895 100644
--- a/src/com/android/launcher2/CustomizeTrayTabHost.java
+++ b/src/com/android/launcher2/CustomizeTrayTabHost.java
@@ -16,8 +16,7 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-import com.android.launcher2.CustomizePagedView.CustomizationType;
+import java.util.Random;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -28,10 +27,14 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.TabHost;
 import android.widget.TabWidget;
 import android.widget.TextView;
 
+import com.android.launcher.R;
+import com.android.launcher2.CustomizePagedView.CustomizationType;
+
 public class CustomizeTrayTabHost extends TabHost implements LauncherTransitionable  {
     // tags for the customization tabs
     private static final String WIDGETS_TAG = "widgets";
@@ -69,7 +72,8 @@
 
         tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
         tabView.setText(mContext.getString(R.string.widgets_tab_label));
-        addTab(newTabSpec(WIDGETS_TAG).setIndicator(tabView).setContent(contentFactory));
+        addTab(newTabSpec(WIDGETS_TAG)
+                .setIndicator(tabView).setContent(contentFactory));
         tabView = (TextView) mInflater.inflate(R.layout.tab_widget_indicator, tabWidget, false);
         tabView.setText(mContext.getString(R.string.applications_tab_label));
         addTab(newTabSpec(APPLICATIONS_TAG)
@@ -82,6 +86,7 @@
         tabView.setText(mContext.getString(R.string.shortcuts_tab_label));
         addTab(newTabSpec(SHORTCUTS_TAG)
                 .setIndicator(tabView).setContent(contentFactory));
+
         setOnTabChangedListener(new OnTabChangeListener() {
             public void onTabChanged(String tabId) {
                 final CustomizePagedView.CustomizationType newType =
@@ -89,7 +94,7 @@
                 if (newType != customizePagedView.getCustomizationFilter()) {
                     // animate the changing of the tab content by fading pages in and out
                     final Resources res = getResources();
-                    final int duration = res.getInteger(R.integer.config_tabTransitionTime);
+                    final int duration = res.getInteger(R.integer.config_tabTransitionDuration);
                     final float alpha = customizePagedView.getAlpha();
                     ValueAnimator alphaAnim = ObjectAnimator.ofFloat(customizePagedView,
                             "alpha", alpha, 0.0f);
@@ -149,6 +154,14 @@
         super.onLayout(changed, l, t, r, b);
     }
 
+    @Override
+    public int getDescendantFocusability() {
+        if (getVisibility() != View.VISIBLE) {
+            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+        }
+        return super.getDescendantFocusability();
+    }
+
     CustomizationType getCustomizeFilterForTabTag(String tag) {
         if (tag.equals(WIDGETS_TAG)) {
             return CustomizationType.WidgetCustomization;
diff --git a/src/com/android/launcher2/DeleteZone.java b/src/com/android/launcher2/DeleteZone.java
index 98d2b83..fdd4125 100644
--- a/src/com/android/launcher2/DeleteZone.java
+++ b/src/com/android/launcher2/DeleteZone.java
@@ -16,8 +16,10 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -29,10 +31,8 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.TranslateAnimation;
+
+import com.android.launcher.R;
 
 public class DeleteZone extends IconDropTarget {
     private static final int ORIENTATION_HORIZONTAL = 1;
@@ -42,10 +42,8 @@
     private static final int XLARGE_ANIMATION_DURATION = 200;
     private static final int LEFT_DRAWABLE = 0;
 
-    private AnimationSet mInAnimation;
-    private AnimationSet mOutAnimation;
-    private Animation mHandleInAnimation;
-    private Animation mHandleOutAnimation;
+    private AnimatorSet mInAnimation;
+    private AnimatorSet mOutAnimation;
 
     private int mOrientation;
     private DragController mDragController;
@@ -70,7 +68,7 @@
         mOrientation = a.getInt(R.styleable.DeleteZone_direction, ORIENTATION_HORIZONTAL);
         a.recycle();
 
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             int tb = getResources().getDimensionPixelSize(
                     R.dimen.delete_zone_vertical_drag_padding);
             int lr = getResources().getDimensionPixelSize(
@@ -83,7 +81,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mTransition = (TransitionDrawable) getCompoundDrawables()[LEFT_DRAWABLE];
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             mTransition.setCrossFadeEnabled(false);
         }
 
@@ -104,7 +102,7 @@
         final ItemInfo item = (ItemInfo) dragInfo;
 
         // On x-large screens, you can uninstall an app by dragging from all apps
-        if (item instanceof ApplicationInfo && LauncherApplication.isScreenXLarge()) {
+        if (item instanceof ApplicationInfo && LauncherApplication.isScreenLarge()) {
             mLauncher.startApplicationUninstallActivity((ApplicationInfo) item);
         }
 
@@ -114,18 +112,18 @@
             if (item instanceof LauncherAppWidgetInfo) {
                 mLauncher.removeAppWidget((LauncherAppWidgetInfo) item);
             }
-        } else if (source instanceof UserFolder) {
-            final UserFolder userFolder = (UserFolder) source;
-            final UserFolderInfo userFolderInfo = (UserFolderInfo) userFolder.getInfo();
+        } else if (source instanceof Folder) {
+            final Folder folder = (Folder) source;
+            final FolderInfo folderInfo = (FolderInfo) folder.getInfo();
             // Item must be a ShortcutInfo otherwise it couldn't have been in the folder
             // in the first place.
-            userFolderInfo.remove((ShortcutInfo)item);
+            folderInfo.remove((ShortcutInfo)item);
         }
 
-        if (item instanceof UserFolderInfo) {
-            final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
-            LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
-            mLauncher.removeFolder(userFolderInfo);
+        if (item instanceof FolderInfo) {
+            final FolderInfo folderInfo = (FolderInfo)item;
+            LauncherModel.deleteFolderContentsFromDatabase(mLauncher, folderInfo);
+            mLauncher.removeFolder(folderInfo);
         } else if (item instanceof LauncherAppWidgetInfo) {
             final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
             final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
@@ -168,7 +166,7 @@
             getHitRect(mRegion);
             mRegionF.set(mRegion);
 
-            if (LauncherApplication.isScreenXLarge()) {
+            if (LauncherApplication.isScreenLarge()) {
                 // This region will be a "dead zone" for scrolling; make it extend to the edge of
                 // the screen so users don't accidentally trigger a scroll while deleting items
                 mRegionF.top = mLauncher.getWorkspace().getTop();
@@ -181,10 +179,10 @@
             mTransition.resetTransition();
 
             createAnimations();
-            startAnimation(mInAnimation);
+            mInAnimation.start();
             if (mOverlappingViews != null) {
                 for (View view : mOverlappingViews) {
-                    view.startAnimation(mHandleOutAnimation);
+                    createOutAlphaAnim(view).start();
                 }
             }
             setVisibility(VISIBLE);
@@ -196,68 +194,72 @@
             mActive = false;
             mDragController.setDeleteRegion(null);
 
-            if (mOutAnimation != null) startAnimation(mOutAnimation);
-            if (mHandleInAnimation != null && mOverlappingViews != null) {
+            mOutAnimation.start();
+            if (mOverlappingViews != null) {
                 for (View view : mOverlappingViews) {
-                    view.startAnimation(mHandleInAnimation);
+                    createInAlphaAnim(view).start();
                 }
             }
-            setVisibility(GONE);
         }
     }
 
+    private Animator createAlphaAnim(View v, float start, float end) {
+        Animator anim = ObjectAnimator.ofFloat(v, "alpha", start, end);
+        anim.setDuration(getAnimationDuration());
+        return anim;
+    }
+    private Animator createInAlphaAnim(View v) {
+        return createAlphaAnim(v, 0f, 1f);
+    }
+    private Animator createOutAlphaAnim(View v) {
+        return createAlphaAnim(v, 1f, 0f);
+    }
+
     private void createAnimations() {
         int duration = getAnimationDuration();
-        if (mHandleInAnimation == null) {
-            mHandleInAnimation = new AlphaAnimation(0.0f, 1.0f);
-            mHandleInAnimation.setDuration(duration);
-        }
 
+        Animator inAlphaAnim = createInAlphaAnim(this);
         if (mInAnimation == null) {
-            mInAnimation = new FastAnimationSet();
-            if (!LauncherApplication.isScreenXLarge()) {
-                final AnimationSet animationSet = mInAnimation;
-                animationSet.setInterpolator(new AccelerateInterpolator());
-                animationSet.addAnimation(new AlphaAnimation(0.0f, 1.0f));
+            mInAnimation = new AnimatorSet();
+            mInAnimation.setInterpolator(new AccelerateInterpolator());
+            mInAnimation.setDuration(duration);
+            if (!LauncherApplication.isScreenLarge()) {
+                Animator translateAnim;
                 if (mOrientation == ORIENTATION_HORIZONTAL) {
-                    animationSet.addAnimation(new TranslateAnimation(Animation.ABSOLUTE, 0.0f,
-                            Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f,
-                            Animation.RELATIVE_TO_SELF, 0.0f));
+                    translateAnim = ObjectAnimator.ofFloat(this, "translationY", 
+                            getMeasuredWidth(), 0f);
                 } else {
-                    animationSet.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF,
-                            1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.ABSOLUTE, 0.0f,
-                            Animation.ABSOLUTE, 0.0f));
+                    translateAnim = ObjectAnimator.ofFloat(this, "translationX", 
+                            getMeasuredHeight(), 0f);
                 }
-                animationSet.setDuration(duration);
+                mInAnimation.playTogether(translateAnim, inAlphaAnim);
             } else {
-                mInAnimation.addAnimation(mHandleInAnimation);
+                mInAnimation.play(inAlphaAnim);
             }
         }
 
-        if (mHandleOutAnimation == null) {
-            mHandleOutAnimation = new AlphaAnimation(1.0f, 0.0f);
-            mHandleOutAnimation.setFillAfter(true);
-            mHandleOutAnimation.setDuration(duration);
-        }
-
+        Animator outAlphaAnim = createOutAlphaAnim(this);
         if (mOutAnimation == null) {
-            mOutAnimation = new FastAnimationSet();
-            if (!LauncherApplication.isScreenXLarge()) {
-                final AnimationSet animationSet = mOutAnimation;
-                animationSet.setInterpolator(new AccelerateInterpolator());
-                animationSet.addAnimation(new AlphaAnimation(1.0f, 0.0f));
+            mOutAnimation = new AnimatorSet();
+            mOutAnimation.setInterpolator(new AccelerateInterpolator());
+            mOutAnimation.setDuration(duration);
+            if (!LauncherApplication.isScreenLarge()) {
+                Animator translateAnim;
                 if (mOrientation == ORIENTATION_HORIZONTAL) {
-                    animationSet.addAnimation(new FastTranslateAnimation(Animation.ABSOLUTE, 0.0f,
-                            Animation.ABSOLUTE, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
-                            Animation.RELATIVE_TO_SELF, 1.0f));
+                    translateAnim = ObjectAnimator.ofFloat(this, "translationY", 0f, 
+                            getMeasuredWidth());
                 } else {
-                    animationSet.addAnimation(new FastTranslateAnimation(Animation.RELATIVE_TO_SELF,
-                            0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.ABSOLUTE, 0.0f,
-                            Animation.ABSOLUTE, 0.0f));
+                    translateAnim = ObjectAnimator.ofFloat(this, "translationX", 0f, 
+                            getMeasuredHeight());
                 }
-                animationSet.setDuration(duration);
+                mOutAnimation.playTogether(translateAnim, outAlphaAnim);
             } else {
-                mOutAnimation.addAnimation(mHandleOutAnimation);
+                mOutAnimation.addListener(new AnimatorListenerAdapter() {
+                    public void onAnimationEnd(Animator animation) {
+                        setVisibility(GONE);
+                    }
+                });
+                mOutAnimation.play(outAlphaAnim);
             }
         }
     }
@@ -267,46 +269,12 @@
     }
 
     private int getTransitionAnimationDuration() {
-        return LauncherApplication.isScreenXLarge() ?
+        return LauncherApplication.isScreenLarge() ?
                 XLARGE_TRANSITION_DURATION : TRANSITION_DURATION;
     }
 
     private int getAnimationDuration() {
-        return LauncherApplication.isScreenXLarge() ?
+        return LauncherApplication.isScreenLarge() ?
                 XLARGE_ANIMATION_DURATION : ANIMATION_DURATION;
     }
-
-    private static class FastTranslateAnimation extends TranslateAnimation {
-        public FastTranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
-                int fromYType, float fromYValue, int toYType, float toYValue) {
-            super(fromXType, fromXValue, toXType, toXValue,
-                    fromYType, fromYValue, toYType, toYValue);
-        }
-
-        @Override
-        public boolean willChangeTransformationMatrix() {
-            return true;
-        }
-
-        @Override
-        public boolean willChangeBounds() {
-            return false;
-        }
-    }
-
-    private static class FastAnimationSet extends AnimationSet {
-        FastAnimationSet() {
-            super(false);
-        }
-
-        @Override
-        public boolean willChangeTransformationMatrix() {
-            return true;
-        }
-
-        @Override
-        public boolean willChangeBounds() {
-            return false;
-        }
-    }
 }
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index cb4509b..5ca1e1c 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -73,10 +73,10 @@
     private boolean mDragging;
 
     /** X coordinate of the down event. */
-    private float mMotionDownX;
+    private int mMotionDownX;
 
     /** Y coordinate of the down event. */
-    private float mMotionDownY;
+    private int mMotionDownY;
 
     /** Info about the screen for clamping. */
     private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -85,10 +85,10 @@
     private View mOriginator;
 
     /** X offset from the upper-left corner of the cell to where we touched.  */
-    private float mTouchOffsetX;
+    private int mTouchOffsetX;
 
     /** Y offset from the upper-left corner of the cell to where we touched.  */
-    private float mTouchOffsetY;
+    private int mTouchOffsetY;
 
     /** the area at the edge of the screen that makes the workspace go left
      *   or right while you're dragging.
@@ -289,13 +289,14 @@
             listener.onDragStart(source, dragInfo, dragAction);
         }
 
-        int registrationX = ((int)mMotionDownX) - screenX;
-        int registrationY = ((int)mMotionDownY) - screenY;
+        final int registrationX = ((int)mMotionDownX) - screenX;
+        final int registrationY = ((int)mMotionDownY) - screenY;
 
         final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
         final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
-        mTouchOffsetX = mMotionDownX - screenX - dragRegionLeft;
-        mTouchOffsetY = mMotionDownY - screenY - dragRegionTop;
+
+        mTouchOffsetX = mMotionDownX - (screenX + dragRegionLeft);
+        mTouchOffsetY = mMotionDownY - (screenY + dragRegionTop);
 
         mDragging = true;
         mDragSource = source;
@@ -314,8 +315,7 @@
         });
 
         if (dragRegion != null) {
-            dragView.setDragRegion(dragRegionLeft, dragRegion.top,
-                    dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
+            dragView.setDragRegion(new Rect(dragRegion));
         }
 
         dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java
index eb53945..c2b710e 100644
--- a/src/com/android/launcher2/DragLayer.java
+++ b/src/com/android/launcher2/DragLayer.java
@@ -16,10 +16,11 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
+import java.util.ArrayList;
 
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -27,6 +28,8 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.launcher.R;
+
 /**
  * A ViewGroup that coordinates dragging across its descendants
  */
@@ -34,6 +37,12 @@
     private DragController mDragController;
     private int[] mTmpXY = new int[2];
 
+    // Variables relating to resizing widgets
+    private final ArrayList<AppWidgetResizeFrame> mResizeFrames =
+            new ArrayList<AppWidgetResizeFrame>();
+    private AppWidgetResizeFrame mCurrentResizeFrame;
+    private int mXDown, mYDown;
+
     /**
      * Used to create a new DragLayer from XML.
      *
@@ -56,31 +65,66 @@
         return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
     }
 
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // If the current CellLayoutChildren has a resize frame, we need to detect if any touch
-        // event has occurred which doesn't result in resizing a widget. In this case, we
-        // dismiss any visible resize frames.
-        final Workspace w = (Workspace) findViewById(R.id.workspace);
-        if (w != null) {
-            final CellLayout currentPage = (CellLayout) w.getChildAt(w.getCurrentPage());
-            final CellLayoutChildren childrenLayout = currentPage.getChildrenLayout();
+    private boolean handleTouchDown(MotionEvent ev) {
+        Rect hitRect = new Rect();
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
 
-            if (childrenLayout.hasResizeFrames() && !childrenLayout.isWidgetBeingResized()) {
-                post(new Runnable() {
-                    public void run() {
-                        if (!childrenLayout.isWidgetBeingResized()) {
-                            childrenLayout.clearAllResizeFrames();
-                        }
-                    }
-                });
+        for (AppWidgetResizeFrame child: mResizeFrames) {
+            child.getHitRect(hitRect);
+            if (hitRect.contains(x, y)) {
+                if (child.beginResizeIfPointInRegion(x - child.getLeft(), y - child.getTop())) {
+                    mCurrentResizeFrame = child;
+                    mXDown = x;
+                    mYDown = y;
+                    requestDisallowInterceptTouchEvent(true);
+                    return true;
+                }
             }
         }
+        return false;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (handleTouchDown(ev)) {
+                return true;
+            }
+        }
+        clearAllResizeFrames();
         return mDragController.onInterceptTouchEvent(ev);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = false;
+        int action = ev.getAction();
+
+        int x = (int) ev.getX();
+        int y = (int) ev.getY();
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+                if (handleTouchDown(ev)) {
+                    return true;
+                }
+            }
+        }
+
+        if (mCurrentResizeFrame != null) {
+            handled = true;
+            switch (action) {
+                case MotionEvent.ACTION_MOVE:
+                    mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown);
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown);
+                    mCurrentResizeFrame = null;
+            }
+        }
+        if (handled) return true;
         return mDragController.onTouchEvent(ev);
     }
 
@@ -103,4 +147,94 @@
         v.getLocationOnScreen(mTmpXY);
         return createDragView(mDragController.getViewBitmap(v), mTmpXY[0], mTmpXY[1]);
     }
+
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+        public int x, y;
+        public boolean customPosition = false;
+
+        /**
+         * {@inheritDoc}
+         */
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public void setWidth(int width) {
+            this.width = width;
+        }
+
+        public int getWidth() {
+            return width;
+        }
+
+        public void setHeight(int height) {
+            this.height = height;
+        }
+
+        public int getHeight() {
+            return height;
+        }
+
+        public void setX(int x) {
+            this.x = x;
+        }
+
+        public int getX() {
+            return x;
+        }
+
+        public void setY(int y) {
+            this.y = y;
+        }
+
+        public int getY() {
+            return y;
+        }
+    }
+
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = getChildAt(i);
+            final FrameLayout.LayoutParams flp = (FrameLayout.LayoutParams) child.getLayoutParams();
+            if (flp instanceof LayoutParams) {
+                final LayoutParams lp = (LayoutParams) flp;
+                if (lp.customPosition) {
+                    child.layout(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+                }
+            }
+        }
+    }
+
+    public void clearAllResizeFrames() {
+        if (mResizeFrames.size() > 0) {
+            for (AppWidgetResizeFrame frame: mResizeFrames) {
+                removeView(frame);
+            }
+            mResizeFrames.clear();
+        }
+    }
+
+    public boolean hasResizeFrames() {
+        return mResizeFrames.size() > 0;
+    }
+
+    public boolean isWidgetBeingResized() {
+        return mCurrentResizeFrame != null;
+    }
+
+    public void addResizeFrame(ItemInfo itemInfo, LauncherAppWidgetHostView widget,
+            CellLayout cellLayout) {
+        AppWidgetResizeFrame resizeFrame = new AppWidgetResizeFrame(getContext(),
+                itemInfo, widget, cellLayout, this);
+
+        LayoutParams lp = new LayoutParams(-1, -1);
+        lp.customPosition = true;
+
+        addView(resizeFrame, lp);
+        mResizeFrames.add(resizeFrame);
+
+        resizeFrame.snapToWidget(false);
+    }
 }
diff --git a/src/com/android/launcher2/DragSource.java b/src/com/android/launcher2/DragSource.java
index 4dbdaf7..649120d 100644
--- a/src/com/android/launcher2/DragSource.java
+++ b/src/com/android/launcher2/DragSource.java
@@ -23,8 +23,6 @@
  *
  */
 public interface DragSource {
-    void setDragController(DragController dragger);
-
     /**
      * Callback from the DragController when it begins drawing the drag view.
      * This allows the DragSource to dim or hide the original view.
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index 45620b9..b02e22b 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -26,6 +26,7 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.Gravity;
 import android.view.View;
@@ -42,10 +43,7 @@
     private int mRegistrationX;
     private int mRegistrationY;
 
-    private int mDragRegionLeft = 0;
-    private int mDragRegionTop = 0;
-    private int mDragRegionWidth;
-    private int mDragRegionHeight;
+    private Rect mDragRegion = null;
 
     ValueAnimator mAnim;
     private float mOffsetX = 0.0f;
@@ -87,8 +85,8 @@
             scale.setScale(scaleFactor, scaleFactor);
         }
 
-        final int offsetX = res.getInteger(R.integer.config_dragViewOffsetX);
-        final int offsetY = res.getInteger(R.integer.config_dragViewOffsetY);
+        final int offsetX = res.getDimensionPixelSize(R.dimen.dragViewOffsetX);
+        final int offsetY = res.getDimensionPixelSize(R.dimen.dragViewOffsetY);
 
         // Animate the view into the correct position
         mAnim = ValueAnimator.ofFloat(0.0f, 1.0f);
@@ -117,7 +115,7 @@
         });
 
         mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
-        setDragRegion(0, 0, width, height);
+        setDragRegion(new Rect(0, 0, width, height));
 
         // The point in our scaled bitmap that the touch events are located
         mRegistrationX = registrationX;
@@ -132,31 +130,32 @@
         return mOffsetY;
     }
 
-    public void setDragRegion(int left, int top, int width, int height) {
-        mDragRegionLeft = left;
-        mDragRegionTop = top;
-        mDragRegionWidth = width;
-        mDragRegionHeight = height;
-    }
-
     public void setOnDrawRunnable(Runnable r) {
         mOnDrawRunnable = r;
     }
 
     public int getDragRegionLeft() {
-        return mDragRegionLeft;
+        return mDragRegion.left;
     }
 
     public int getDragRegionTop() {
-        return mDragRegionTop;
+        return mDragRegion.top;
     }
 
     public int getDragRegionWidth() {
-        return mDragRegionWidth;
+        return mDragRegion.width();
     }
 
     public int getDragRegionHeight() {
-        return mDragRegionHeight;
+        return mDragRegion.height();
+    }
+
+    public void setDragRegion(Rect r) {
+        mDragRegion = r;
+    }
+
+    public Rect getDragRegion() {
+        return mDragRegion;
     }
 
     @Override
diff --git a/src/com/android/launcher2/FocusHelper.java b/src/com/android/launcher2/FocusHelper.java
new file mode 100644
index 0000000..861a70b
--- /dev/null
+++ b/src/com/android/launcher2/FocusHelper.java
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+import android.content.res.Configuration;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+
+import com.android.launcher.R;
+
+/**
+ * A keyboard listener we set on all the button bar buttons.
+ */
+class ButtonBarKeyEventListener implements View.OnKeyListener {
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        return FocusHelper.handleButtonBarButtonKeyEvent(v, keyCode, event);
+    }
+}
+
+/**
+ * A keyboard listener we set on the indicator buttons.
+ */
+class IndicatorKeyEventListener implements View.OnKeyListener {
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        return FocusHelper.handleIndicatorButtonKeyEvent(v, keyCode, event);
+    }
+}
+
+/**
+ * A keyboard listener we set on all the dock buttons.
+ */
+class DockKeyEventListener implements View.OnKeyListener {
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        final Configuration configuration = v.getResources().getConfiguration();
+        return FocusHelper.handleDockButtonKeyEvent(v, keyCode, event, configuration.orientation);
+    }
+}
+
+/**
+ * A keyboard listener we set on the last tab button in AllApps to jump to then
+ * market icon and vice versa.
+ */
+class AllAppsTabKeyEventListener implements View.OnKeyListener {
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        return FocusHelper.handleAllAppsTabKeyEvent(v, keyCode, event);
+    }
+}
+
+public class FocusHelper {
+    /**
+     * Private helper to get the parent TabHost in the view hiearchy.
+     */
+    private static TabHost findTabHostParent(View v) {
+        ViewParent p = v.getParent();
+        while (p != null && !(p instanceof TabHost)) {
+            p = p.getParent();
+        }
+        return (TabHost) p;
+    }
+
+    /**
+     * Handles key events in a AllApps tab between the last tab view and the shop button.
+     */
+    static boolean handleAllAppsTabKeyEvent(View v, int keyCode, KeyEvent e) {
+        final TabHost tabHost = findTabHostParent(v);
+        final ViewGroup contents = (ViewGroup)
+                tabHost.findViewById(com.android.internal.R.id.tabcontent);
+        final View shop = tabHost.findViewById(R.id.market_button);
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the shop button if we aren't on it
+                    if (v != shop) {
+                        shop.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the content view (down is handled by the tab key handler otherwise)
+                    if (v == shop) {
+                        contents.requestFocus();
+                        wasHandled = true;
+                    }
+                }
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Private helper to determine whether a view is visible.
+     */
+    private static boolean isVisible(View v) {
+        return v.getVisibility() == View.VISIBLE;
+    }
+
+    /**
+     * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
+     * To be deprecated.
+     */
+    static boolean handlePagedViewWidgetKeyEvent(PagedViewWidget w, int keyCode, KeyEvent e) {
+        if (!LauncherApplication.isScreenLarge()) return false;
+
+        final PagedViewExtendedLayout parent = (PagedViewExtendedLayout) w.getParent();
+        final ViewGroup container = (ViewGroup) parent.getParent();
+        final TabHost tabHost = findTabHostParent(container);
+        final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+        final int widgetIndex = parent.indexOfChild(w);
+        final int widgetCount = parent.getChildCount();
+        final int pageIndex = container.indexOfChild(parent);
+        final int pageCount = container.getChildCount();
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        PagedViewExtendedLayout newParent = null;
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous widget or the last widget on the previous page
+                    if (widgetIndex > 0) {
+                        parent.getChildAt(widgetIndex - 1).requestFocus();
+                    } else {
+                        if (pageIndex > 0) {
+                            newParent = (PagedViewExtendedLayout)
+                                    container.getChildAt(pageIndex - 1);
+                            newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next widget or the first widget on the next page
+                    if (widgetIndex < (widgetCount - 1)) {
+                        parent.getChildAt(widgetIndex + 1).requestFocus();
+                    } else {
+                        if (pageIndex < (pageCount - 1)) {
+                            newParent = (PagedViewExtendedLayout)
+                                    container.getChildAt(pageIndex + 1);
+                            newParent.getChildAt(0).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select widgets tab on the tab bar
+                    tabs.requestFocus();
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // TODO: Should focus the global search bar
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                if (handleKeyEvent) {
+                    // Simulate a click on the widget
+                    View.OnClickListener clickListener = (View.OnClickListener) container;
+                    clickListener.onClick(w);
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
+                if (handleKeyEvent) {
+                    // Select the first item on the previous page, or the first item on this page
+                    // if there is no previous page
+                    if (pageIndex > 0) {
+                        newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex - 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(0).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_DOWN:
+                if (handleKeyEvent) {
+                    // Select the first item on the next page, or the last item on this page
+                    // if there is no next page
+                    if (pageIndex < (pageCount - 1)) {
+                        newParent = (PagedViewExtendedLayout) container.getChildAt(pageIndex + 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(widgetCount - 1).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_HOME:
+                if (handleKeyEvent) {
+                    // Select the first item on this page
+                    parent.getChildAt(0).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_END:
+                if (handleKeyEvent) {
+                    // Select the last item on this page
+                    parent.getChildAt(widgetCount - 1).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Handles key events in a PageViewExtendedLayout containing PagedViewWidgets.
+     */
+    static boolean handlePagedViewGridLayoutWidgetKeyEvent(PagedViewWidget w, int keyCode,
+            KeyEvent e) {
+
+        final PagedViewGridLayout parent = (PagedViewGridLayout) w.getParent();
+        final ViewGroup container = (ViewGroup) parent.getParent();
+        final TabHost tabHost = findTabHostParent(container);
+        final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+        final int widgetIndex = parent.indexOfChild(w);
+        final int widgetCount = parent.getChildCount();
+        final int pageIndex = container.indexOfChild(parent);
+        final int pageCount = container.getChildCount();
+        final int cellCountX = parent.getCellCountX();
+        final int cellCountY = parent.getCellCountY();
+        final int x = widgetIndex % cellCountX;
+        final int y = widgetIndex / cellCountX;
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        PagedViewGridLayout newParent = null;
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous widget or the last widget on the previous page
+                    if (widgetIndex > 0) {
+                        parent.getChildAt(widgetIndex - 1).requestFocus();
+                    } else {
+                        if (pageIndex > 0) {
+                            newParent = (PagedViewGridLayout)
+                                    container.getChildAt(pageIndex - 1);
+                            newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next widget or the first widget on the next page
+                    if (widgetIndex < (widgetCount - 1)) {
+                        parent.getChildAt(widgetIndex + 1).requestFocus();
+                    } else {
+                        if (pageIndex < (pageCount - 1)) {
+                            newParent = (PagedViewGridLayout)
+                                    container.getChildAt(pageIndex + 1);
+                            newParent.getChildAt(0).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the previous row, otherwise select the tab bar
+                    if (y > 0) {
+                        int newWidgetIndex = ((y - 1) * cellCountX) + x;
+                        parent.getChildAt(newWidgetIndex).requestFocus();
+                    } else {
+                        tabs.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the previous row, otherwise do nothing
+                    if (y < (cellCountY - 1)) {
+                        int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
+                        parent.getChildAt(newWidgetIndex).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                if (handleKeyEvent) {
+                    // Simulate a click on the widget
+                    View.OnClickListener clickListener = (View.OnClickListener) container;
+                    clickListener.onClick(w);
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
+                if (handleKeyEvent) {
+                    // Select the first item on the previous page, or the first item on this page
+                    // if there is no previous page
+                    if (pageIndex > 0) {
+                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex - 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(0).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_DOWN:
+                if (handleKeyEvent) {
+                    // Select the first item on the next page, or the last item on this page
+                    // if there is no next page
+                    if (pageIndex < (pageCount - 1)) {
+                        newParent = (PagedViewGridLayout) container.getChildAt(pageIndex + 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(widgetCount - 1).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_HOME:
+                if (handleKeyEvent) {
+                    // Select the first item on this page
+                    parent.getChildAt(0).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_END:
+                if (handleKeyEvent) {
+                    // Select the last item on this page
+                    parent.getChildAt(widgetCount - 1).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Private helper method to get the PagedViewCellLayoutChildren given a PagedViewCellLayout
+     * index.
+     */
+    private static PagedViewCellLayoutChildren getPagedViewCellLayoutChildrenForIndex(
+            ViewGroup container, int i) {
+        ViewGroup parent = (ViewGroup) container.getChildAt(i);
+        return (PagedViewCellLayoutChildren) parent.getChildAt(0);
+    }
+
+    /**
+     * Handles key events in a PageViewCellLayout containing PagedViewIcons.
+     */
+    static boolean handlePagedViewIconKeyEvent(PagedViewIcon v, int keyCode, KeyEvent e) {
+        final PagedViewCellLayoutChildren parent = (PagedViewCellLayoutChildren) v.getParent();
+        final PagedViewCellLayout parentLayout = (PagedViewCellLayout) parent.getParent();
+        // Note we have an extra parent because of the
+        // PagedViewCellLayout/PagedViewCellLayoutChildren relationship
+        final ViewGroup container = (ViewGroup) parentLayout.getParent();
+        final TabHost tabHost = findTabHostParent(container);
+        final TabWidget tabs = (TabWidget) tabHost.findViewById(com.android.internal.R.id.tabs);
+        final int widgetIndex = parent.indexOfChild(v);
+        final int widgetCount = parent.getChildCount();
+        final int pageIndex = container.indexOfChild(parentLayout);
+        final int pageCount = container.getChildCount();
+        final int cellCountX = parentLayout.getCellCountX();
+        final int cellCountY = parentLayout.getCellCountY();
+        final int x = widgetIndex % cellCountX;
+        final int y = widgetIndex / cellCountX;
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        PagedViewCellLayoutChildren newParent = null;
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous icon or the last icon on the previous page
+                    if (widgetIndex > 0) {
+                        parent.getChildAt(widgetIndex - 1).requestFocus();
+                    } else {
+                        if (pageIndex > 0) {
+                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
+                                    pageIndex - 1);
+                            newParent.getChildAt(newParent.getChildCount() - 1).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next icon or the first icon on the next page
+                    if (widgetIndex < (widgetCount - 1)) {
+                        parent.getChildAt(widgetIndex + 1).requestFocus();
+                    } else {
+                        if (pageIndex < (pageCount - 1)) {
+                            newParent = getPagedViewCellLayoutChildrenForIndex(container,
+                                    pageIndex + 1);
+                            newParent.getChildAt(0).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the previous row, otherwise select the tab bar
+                    if (y > 0) {
+                        int newWidgetIndex = ((y - 1) * cellCountX) + x;
+                        parent.getChildAt(newWidgetIndex).requestFocus();
+                    } else {
+                        tabs.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the previous row, otherwise do nothing
+                    if (y < (cellCountY - 1)) {
+                        int newWidgetIndex = Math.min(widgetCount - 1, ((y + 1) * cellCountX) + x);
+                        parent.getChildAt(newWidgetIndex).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+                if (handleKeyEvent) {
+                    // Simulate a click on the icon
+                    View.OnClickListener clickListener = (View.OnClickListener) container;
+                    clickListener.onClick(v);
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
+                if (handleKeyEvent) {
+                    // Select the first icon on the previous page, or the first icon on this page
+                    // if there is no previous page
+                    if (pageIndex > 0) {
+                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
+                                pageIndex - 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(0).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_DOWN:
+                if (handleKeyEvent) {
+                    // Select the first icon on the next page, or the last icon on this page
+                    // if there is no next page
+                    if (pageIndex < (pageCount - 1)) {
+                        newParent = getPagedViewCellLayoutChildrenForIndex(container,
+                                pageIndex + 1);
+                        newParent.getChildAt(0).requestFocus();
+                    } else {
+                        parent.getChildAt(widgetCount - 1).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_HOME:
+                if (handleKeyEvent) {
+                    // Select the first icon on this page
+                    parent.getChildAt(0).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_END:
+                if (handleKeyEvent) {
+                    // Select the last icon on this page
+                    parent.getChildAt(widgetCount - 1).requestFocus();
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Handles key events in the tab widget.
+     */
+    static boolean handleTabKeyEvent(AccessibleTabView v, int keyCode, KeyEvent e) {
+        if (!LauncherApplication.isScreenLarge()) return false;
+
+        final FocusOnlyTabWidget parent = (FocusOnlyTabWidget) v.getParent();
+        final TabHost tabHost = findTabHostParent(parent);
+        final ViewGroup contents = (ViewGroup)
+                tabHost.findViewById(com.android.internal.R.id.tabcontent);
+        final int tabCount = parent.getTabCount();
+        final int tabIndex = parent.getChildTabIndex(v);
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous tab
+                    if (tabIndex > 0) {
+                        parent.getChildTabViewAt(tabIndex - 1).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next tab, or if the last tab has a focus right id, select that
+                    if (tabIndex < (tabCount - 1)) {
+                        parent.getChildTabViewAt(tabIndex + 1).requestFocus();
+                    } else {
+                        if (v.getNextFocusRightId() != View.NO_ID) {
+                            tabHost.findViewById(v.getNextFocusRightId()).requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                // Do nothing
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the content view
+                    contents.requestFocus();
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Handles key events in the workspace button bar.
+     */
+    static boolean handleButtonBarButtonKeyEvent(View v, int keyCode, KeyEvent e) {
+        if (!LauncherApplication.isScreenLarge()) return false;
+
+        final ViewGroup parent = (ViewGroup) v.getParent();
+        final ViewGroup launcher = (ViewGroup) parent.getParent();
+        final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+        final int buttonIndex = parent.indexOfChild(v);
+        final int buttonCount = parent.getChildCount();
+        final int pageIndex = workspace.getCurrentPage();
+        final int pageCount = workspace.getChildCount();
+        final int firstButtonIndex = parent.indexOfChild(parent.findViewById(R.id.search_button));
+        final int lastButtonIndex = parent.indexOfChild(parent.findViewById(R.id.configure_button));
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous button, otherwise do nothing (since the button bar is
+                    // static)
+                    if (buttonIndex > firstButtonIndex) {
+                        int newButtonIndex = buttonIndex - 1;
+                        while (newButtonIndex >= firstButtonIndex) {
+                            View prev = parent.getChildAt(newButtonIndex);
+                            if (isVisible(prev) && prev.isFocusable()) {
+                                prev.requestFocus();
+                                break;
+                            }
+                            --newButtonIndex;
+                        }
+                    } else {
+                        if (pageIndex > 0) {
+                            // Snap to previous page and clear focus
+                            workspace.snapToPage(pageIndex - 1);
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next button, otherwise do nothing (since the button bar is
+                    // static)
+                    if (buttonIndex < lastButtonIndex) {
+                        int newButtonIndex = buttonIndex + 1;
+                        while (newButtonIndex <= lastButtonIndex) {
+                            View next = parent.getChildAt(newButtonIndex);
+                            if (isVisible(next) && next.isFocusable()) {
+                                next.requestFocus();
+                                break;
+                            }
+                            ++newButtonIndex;
+                        }
+                    } else {
+                        if (pageIndex < (pageCount - 1)) {
+                            // Snap to next page and clear focus
+                            workspace.snapToPage(pageIndex + 1);
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                // Do nothing
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the first bubble text view in the current page of the workspace
+                    final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+                    final CellLayoutChildren children = layout.getChildrenLayout();
+                    final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    } else {
+                        workspace.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Handles key events in the prev/next indicators.
+     */
+    static boolean handleIndicatorButtonKeyEvent(View v, int keyCode, KeyEvent e) {
+        final ViewGroup launcher = (ViewGroup) v.getParent();
+        final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+        final ViewGroup hotseat = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster);
+        final View previousIndicator = launcher.findViewById(R.id.previous_screen);
+        final View nextIndicator = launcher.findViewById(R.id.next_screen);
+        final int pageIndex = workspace.getCurrentPage();
+        final int pageCount = workspace.getChildCount();
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    if (v == previousIndicator) {
+                        if (pageIndex > 0) {
+                            // Snap to previous page and clear focus
+                            workspace.snapToPage(pageIndex - 1);
+                        }
+                    } else if (v == nextIndicator) {
+                        // Select the last button in the hot seat
+                        hotseat.getChildAt(hotseat.getChildCount() - 1).requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    if (v == previousIndicator) {
+                        // Select the first button in the hot seat
+                        hotseat.getChildAt(0).requestFocus();
+                    } else if (v == nextIndicator) {
+                        if (pageIndex < (pageCount - 1)) {
+                            // Snap to next page and clear focus
+                            workspace.snapToPage(pageIndex + 1);
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select the first bubble text view in the current page of the workspace
+                    final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+                    final CellLayoutChildren children = layout.getChildrenLayout();
+                    final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    } else {
+                        workspace.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                // Do nothing
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Handles key events in the workspace dock (bottom of the screen).
+     */
+    static boolean handleDockButtonKeyEvent(View v, int keyCode, KeyEvent e, int orientation) {
+        final ViewGroup parent = (ViewGroup) v.getParent();
+        final ViewGroup launcher = (ViewGroup) parent.getParent();
+        final Workspace workspace = (Workspace) launcher.findViewById(R.id.workspace);
+        final int buttonIndex = parent.indexOfChild(v);
+        final int buttonCount = parent.getChildCount();
+        final int pageIndex = workspace.getCurrentPage();
+        final int pageCount = workspace.getChildCount();
+        final View previousIndicator = launcher.findViewById(R.id.previous_screen);
+        final View nextIndicator = launcher.findViewById(R.id.next_screen);
+
+        // NOTE: currently we don't special case for the phone UI in different
+        // orientations, even though the dock is on the side in landscape mode.  This
+        // is to ensure that accessibility consistency is maintained across rotations.
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+
+                    // Select the previous button, otherwise select the previous page indicator
+                    if (buttonIndex > 0) {
+                        parent.getChildAt(buttonIndex - 1).requestFocus();
+                    } else {
+                        previousIndicator.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next button, otherwise select the next page indicator
+                    if (buttonIndex < (buttonCount - 1)) {
+                        parent.getChildAt(buttonIndex + 1).requestFocus();
+                    } else {
+                        nextIndicator.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select the first bubble text view in the current page of the workspace
+                    final CellLayout layout = (CellLayout) workspace.getChildAt(pageIndex);
+                    final CellLayoutChildren children = layout.getChildrenLayout();
+                    final View newIcon = getBubbleTextViewInDirection(layout, children, -1, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    } else {
+                        workspace.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                // Do nothing
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+
+    /**
+     * Private helper method to get the CellLayoutChildren given a CellLayout index.
+     */
+    private static CellLayoutChildren getCellLayoutChildrenForIndex(ViewGroup container, int i) {
+        ViewGroup parent = (ViewGroup) container.getChildAt(i);
+        return (CellLayoutChildren) parent.getChildAt(0);
+    }
+
+    /**
+     * Private helper method to sort all the CellLayout children in order of their (x,y) spatially
+     * from top left to bottom right.
+     */
+    private static ArrayList<View> getCellLayoutChildrenSortedSpatially(CellLayout layout,
+            ViewGroup parent) {
+        // First we order each the CellLayout children by their x,y coordinates
+        final int cellCountX = layout.getCountX();
+        final int count = parent.getChildCount();
+        ArrayList<View> views = new ArrayList<View>();
+        for (int j = 0; j < count; ++j) {
+            views.add(parent.getChildAt(j));
+        }
+        Collections.sort(views, new Comparator<View>() {
+            @Override
+            public int compare(View lhs, View rhs) {
+                CellLayout.LayoutParams llp = (CellLayout.LayoutParams) lhs.getLayoutParams();
+                CellLayout.LayoutParams rlp = (CellLayout.LayoutParams) rhs.getLayoutParams();
+                int lvIndex = (llp.cellY * cellCountX) + llp.cellX;
+                int rvIndex = (rlp.cellY * cellCountX) + rlp.cellX;
+                return lvIndex - rvIndex;
+            }
+        });
+        return views;
+    }
+    /**
+     * Private helper method to find the index of the next BubbleTextView in the delta direction.
+     * @param delta either -1 or 1 depending on the direction we want to search
+     */
+    private static View findIndexOfBubbleTextView(ArrayList<View> views, int i, int delta) {
+        // Then we find the next BubbleTextView offset by delta from i
+        final int count = views.size();
+        int newI = i + delta;
+        while (0 <= newI && newI < count) {
+            View newV = views.get(newI);
+            if (newV instanceof BubbleTextView) {
+                return newV;
+            }
+            newI += delta;
+        }
+        return null;
+    }
+    private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, int i,
+            int delta) {
+        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+        return findIndexOfBubbleTextView(views, i, delta);
+    }
+    private static View getBubbleTextViewInDirection(CellLayout layout, ViewGroup parent, View v,
+            int delta) {
+        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+        return findIndexOfBubbleTextView(views, views.indexOf(v), delta);
+    }
+    /**
+     * Private helper method to find the next closest BubbleTextView in the delta direction on the
+     * next line.
+     * @param delta either -1 or 1 depending on the line and direction we want to search
+     */
+    private static View getClosestBubbleTextViewOnLine(CellLayout layout, ViewGroup parent, View v,
+            int lineDelta) {
+        final ArrayList<View> views = getCellLayoutChildrenSortedSpatially(layout, parent);
+        final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
+        final int cellCountX = layout.getCountX();
+        final int cellCountY = layout.getCountY();
+        final int row = lp.cellY;
+        final int newRow = row + lineDelta;
+        if (0 <= newRow && newRow < cellCountY) {
+            float closestDistance = Float.MAX_VALUE;
+            int closestIndex = -1;
+            int index = views.indexOf(v);
+            int endIndex = (lineDelta < 0) ? -1 : views.size();
+            while (index != endIndex) {
+                View newV = views.get(index);
+                CellLayout.LayoutParams tmpLp = (CellLayout.LayoutParams) newV.getLayoutParams();
+                boolean satisfiesRow = (lineDelta < 0) ? (tmpLp.cellY < row) : (tmpLp.cellY > row);
+                if (satisfiesRow && newV instanceof BubbleTextView) {
+                    float tmpDistance = (float) Math.sqrt(Math.pow(tmpLp.cellX - lp.cellX, 2) +
+                            Math.pow(tmpLp.cellY - lp.cellY, 2));
+                    if (tmpDistance < closestDistance) {
+                        closestIndex = index;
+                        closestDistance = tmpDistance;
+                    }
+                }
+                if (index <= endIndex) {
+                    ++index;
+                } else {
+                    --index;
+                }
+            }
+            if (closestIndex > -1) {
+                return views.get(closestIndex);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Handles key events in a Workspace containing BubbleTextView.
+     */
+    static boolean handleBubbleTextViewKeyEvent(BubbleTextView v, int keyCode, KeyEvent e) {
+        CellLayoutChildren parent = (CellLayoutChildren) v.getParent();
+        final CellLayout layout = (CellLayout) parent.getParent();
+        final Workspace workspace = (Workspace) layout.getParent();
+        final ViewGroup launcher = (ViewGroup) workspace.getParent();
+        final ViewGroup tabs = (ViewGroup) launcher.findViewById(R.id.all_apps_button_cluster);
+        int iconIndex = parent.indexOfChild(v);
+        int iconCount = parent.getChildCount();
+        int pageIndex = workspace.indexOfChild(layout);
+        int pageCount = workspace.getChildCount();
+
+        final int action = e.getAction();
+        final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
+        boolean wasHandled = false;
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                if (handleKeyEvent) {
+                    // Select the previous icon or the last icon on the previous page if possible
+                    View newIcon = getBubbleTextViewInDirection(layout, parent, v, -1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    } else {
+                        if (pageIndex > 0) {
+                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+                            newIcon = getBubbleTextViewInDirection(layout, parent,
+                                    parent.getChildCount(), -1);
+                            if (newIcon != null) {
+                                newIcon.requestFocus();
+                            } else {
+                                // Snap to the previous page
+                                workspace.snapToPage(pageIndex - 1);
+                            }
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                if (handleKeyEvent) {
+                    // Select the next icon or the first icon on the next page if possible
+                    View newIcon = getBubbleTextViewInDirection(layout, parent, v, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    } else {
+                        if (pageIndex < (pageCount - 1)) {
+                            parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+                            newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+                            if (newIcon != null) {
+                                newIcon.requestFocus();
+                            } else {
+                                // Snap to the next page
+                                workspace.snapToPage(pageIndex + 1);
+                            }
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the previous line, otherwise select the tab bar
+                    View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, -1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                        wasHandled = true;
+                    } else {
+                        tabs.requestFocus();
+                    }
+                }
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (handleKeyEvent) {
+                    // Select the closest icon in the next line, otherwise select the tab bar
+                    View newIcon = getClosestBubbleTextViewOnLine(layout, parent, v, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                        wasHandled = true;
+                    }
+                }
+                break;
+            case KeyEvent.KEYCODE_PAGE_UP:
+                if (handleKeyEvent) {
+                    // Select the first icon on the previous page or the first icon on this page
+                    // if there is no previous page
+                    if (pageIndex > 0) {
+                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex - 1);
+                        View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+                        if (newIcon != null) {
+                            newIcon.requestFocus();
+                        } else {
+                            // Snap to the previous page
+                            workspace.snapToPage(pageIndex - 1);
+                        }
+                    } else {
+                        View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+                        if (newIcon != null) {
+                            newIcon.requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_PAGE_DOWN:
+                if (handleKeyEvent) {
+                    // Select the first icon on the next page or the last icon on this page
+                    // if there is no previous page
+                    if (pageIndex < (pageCount - 1)) {
+                        parent = getCellLayoutChildrenForIndex(workspace, pageIndex + 1);
+                        View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+                        if (newIcon != null) {
+                            newIcon.requestFocus();
+                        } else {
+                            // Snap to the next page
+                            workspace.snapToPage(pageIndex + 1);
+                        }
+                    } else {
+                        View newIcon = getBubbleTextViewInDirection(layout, parent,
+                                parent.getChildCount(), -1);
+                        if (newIcon != null) {
+                            newIcon.requestFocus();
+                        }
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_HOME:
+                if (handleKeyEvent) {
+                    // Select the first icon on this page
+                    View newIcon = getBubbleTextViewInDirection(layout, parent, -1, 1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            case KeyEvent.KEYCODE_MOVE_END:
+                if (handleKeyEvent) {
+                    // Select the last icon on this page
+                    View newIcon = getBubbleTextViewInDirection(layout, parent,
+                            parent.getChildCount(), -1);
+                    if (newIcon != null) {
+                        newIcon.requestFocus();
+                    }
+                }
+                wasHandled = true;
+                break;
+            default: break;
+        }
+        return wasHandled;
+    }
+}
diff --git a/src/com/android/launcher2/FocusOnlyTabWidget.java b/src/com/android/launcher2/FocusOnlyTabWidget.java
new file mode 100644
index 0000000..8e9f58c
--- /dev/null
+++ b/src/com/android/launcher2/FocusOnlyTabWidget.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TabWidget;
+
+public class FocusOnlyTabWidget extends TabWidget {
+    public FocusOnlyTabWidget(Context context) {
+        super(context);
+    }
+
+    public FocusOnlyTabWidget(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public FocusOnlyTabWidget(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public View getSelectedTab() {
+        final int count = getTabCount();
+        for (int i = 0; i < count; ++i) {
+            View v = getChildTabViewAt(i);
+            if (v.isSelected()) {
+                return v;
+            }
+        }
+        return null;
+    }
+
+    public int getChildTabIndex(View v) {
+        final int tabCount = getTabCount();
+        for (int i = 0; i < tabCount; ++i) {
+            if (getChildTabViewAt(i) == v) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public void setCurrentTabToFocusedTab() {
+        View tab = null;
+        int index = -1;
+        final int count = getTabCount();
+        for (int i = 0; i < count; ++i) {
+            View v = getChildTabViewAt(i);
+            if (v.hasFocus()) {
+                tab = v;
+                index = i;
+                break;
+            }
+        }
+        if (index > -1) {
+            super.setCurrentTab(index);
+            super.onFocusChange(tab, true);
+        }
+    }
+    public void superOnFocusChange(View v, boolean hasFocus) {
+        super.onFocusChange(v, hasFocus);
+    }
+
+    @Override
+    public void onFocusChange(android.view.View v, boolean hasFocus) {
+        if (v == this && hasFocus && getTabCount() > 0) {
+            getSelectedTab().requestFocus();
+            return;
+        }
+    }
+}
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 059e73d..3a8a68d 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -16,34 +16,45 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.AbsListView;
 import android.widget.AdapterView;
-import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 
 import com.android.launcher.R;
+import com.android.launcher2.FolderInfo.FolderListener;
+import com.android.launcher2.Workspace.ShrinkState;
 
 /**
  * Represents a set of icons chosen by the user or generated by the system.
  */
 public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener,
-        OnItemClickListener, OnClickListener, View.OnLongClickListener {
+        OnItemClickListener, OnClickListener, View.OnLongClickListener, DropTarget, FolderListener {
 
-    protected AbsListView mContent;
     protected DragController mDragController;
-    
+
     protected Launcher mLauncher;
 
     protected Button mCloseButton;
-    
+
     protected FolderInfo mInfo;
     
     /**
@@ -51,6 +62,20 @@
      */
     protected ShortcutInfo mDragItem;
 
+    private static final String TAG = "Launcher.Folder";
+
+    static final int STATE_NONE = -1;
+    static final int STATE_SMALL = 0;
+    static final int STATE_ANIMATING = 1;
+    static final int STATE_OPEN = 2;
+
+    private int mExpandDuration;
+    protected CellLayout mContent;
+    private final LayoutInflater mInflater;
+    private final IconCache mIconCache;
+    private int mState = STATE_NONE;
+    private int[] mDragItemPosition = new int[2];
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -60,19 +85,19 @@
     public Folder(Context context, AttributeSet attrs) {
         super(context, attrs);
         setAlwaysDrawnWithCacheEnabled(false);
+        mInflater = LayoutInflater.from(context);
+        mIconCache = ((LauncherApplication)context.getApplicationContext()).getIconCache();
+        mExpandDuration = getResources().getInteger(R.integer.config_folderAnimDuration);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mContent = (AbsListView) findViewById(R.id.folder_content);
-        mContent.setOnItemClickListener(this);
-        mContent.setOnItemLongClickListener(this);
-        
         mCloseButton = (Button) findViewById(R.id.folder_close);
         mCloseButton.setOnClickListener(this);
         mCloseButton.setOnLongClickListener(this);
+        mContent = (CellLayout) findViewById(R.id.folder_content);
     }
     
     public void onItemClick(AdapterView parent, View v, int position, long id) {
@@ -85,12 +110,47 @@
     }
 
     public void onClick(View v) {
-        mLauncher.closeFolder(this);
+        Object tag = v.getTag();
+        if (tag instanceof ShortcutInfo) {
+            // refactor this code from Folder
+            ShortcutInfo item = (ShortcutInfo) tag;
+            int[] pos = new int[2];
+            v.getLocationOnScreen(pos);
+            item.intent.setSourceBounds(new Rect(pos[0], pos[1],
+                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
+            mLauncher.startActivitySafely(item.intent, item);
+        } else {
+            mLauncher.closeFolder(this);
+        }
     }
 
     public boolean onLongClick(View v) {
-        mLauncher.closeFolder(this);
-        mLauncher.showRenameDialog(mInfo);
+        Object tag = v.getTag();
+        if (tag instanceof ShortcutInfo) {
+         // refactor this code from Folder
+            ShortcutInfo item = (ShortcutInfo) tag;
+            if (!v.isInTouchMode()) {
+                return false;
+            }
+
+            mLauncher.getWorkspace().onDragStartedWithItem(v);
+            mDragController.startDrag(v, this, item, DragController.DRAG_ACTION_COPY);
+            mDragItemPosition[0] = item.cellX;
+            mDragItemPosition[1] = item.cellY;
+            mLauncher.closeFolder(this);
+            mDragItem = item;
+        } else {
+            mLauncher.closeFolder(this);
+            mLauncher.showRenameDialog(mInfo);
+        }
+        return true;
+    }
+
+    /**
+     * We need to handle touch events to prevent them from falling through to the workspace below.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
         return true;
     }
 
@@ -108,33 +168,13 @@
         return true;
     }
 
-    @Override
     public void setDragController(DragController dragController) {
         mDragController = dragController;
     }
 
-    @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
-    }
-
-    @Override
     public void onDragViewVisible() {
     }
 
-    /**
-     * Sets the adapter used to populate the content area. The adapter must only
-     * contains ShortcutInfo items.
-     *
-     * @param adapter The list of applications to display in the folder.
-     */
-    void setContentAdapter(BaseAdapter adapter) {
-        mContent.setAdapter(adapter);
-    }
-
-    void notifyDataSetChanged() {
-        ((BaseAdapter) mContent.getAdapter()).notifyDataSetChanged();
-    }
-
     void setLauncher(Launcher launcher) {
         mLauncher = launcher;
     }
@@ -146,10 +186,12 @@
         return mInfo;
     }
 
-    // When the folder opens, we need to refresh the GridView's selection by
-    // forcing a layout
     void onOpen() {
+        // When the folder opens, we need to refresh the GridView's selection by
+        // forcing a layout
+        // TODO: find out if this is still necessary
         mContent.requestLayout();
+        requestFocus();
     }
 
     void onClose() {
@@ -160,5 +202,245 @@
     void bind(FolderInfo info) {
         mInfo = info;
         mCloseButton.setText(info.title);
+        ArrayList<ShortcutInfo> children = info.contents;
+        for (int i = 0; i < children.size(); i++) {
+            ShortcutInfo child = (ShortcutInfo) children.get(i);
+            if ((child.cellX == -1 && child.cellY == -1) ||
+                    mContent.isOccupied(child.cellX, child.cellY)) {
+                findAndSetEmptyCells(child);
+            }
+            createAndAddShortcut((ShortcutInfo) children.get(i));
+        }
+        mInfo.addListener(this);
+    }
+
+    /**
+     * Creates a new UserFolder, inflated from R.layout.user_folder.
+     *
+     * @param context The application's context.
+     *
+     * @return A new UserFolder.
+     */
+    static Folder fromXml(Context context) {
+        return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
+    }
+
+    /**
+     * This method is intended to make the UserFolder to be visually identical in size and position
+     * to its associated FolderIcon. This allows for a seamless transition into the expanded state.
+     */
+    private void positionAndSizeAsIcon() {
+        if (!(getParent() instanceof CellLayoutChildren)) return;
+
+        CellLayoutChildren clc = (CellLayoutChildren) getParent();
+        CellLayout cellLayout = (CellLayout) clc.getParent();
+
+        FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY);
+        CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams();
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+        lp.width = iconLp.width;
+        lp.height = iconLp.height;
+        lp.x = iconLp.x;
+        lp.y = iconLp.y;
+
+        mContent.setAlpha(0f);
+        mState = STATE_SMALL;
+    }
+
+    public void animateOpen() {
+        if (mState != STATE_SMALL) {
+            positionAndSizeAsIcon();
+        }
+        if (!(getParent() instanceof CellLayoutChildren)) return;
+
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+        CellLayoutChildren clc = (CellLayoutChildren) getParent();
+        CellLayout cellLayout = (CellLayout) clc.getParent();
+        Rect r = cellLayout.getContentRect(null);
+
+        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", r.width());
+        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", r.height());
+        PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", 0);
+        PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", 0);
+
+        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+        oa.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                requestLayout();
+            }
+        });
+
+        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 1.0f);
+        ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
+
+        AnimatorSet set = new AnimatorSet();
+        set.playTogether(oa, oaContentAlpha);
+        set.setDuration(mExpandDuration);
+        set.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mState = STATE_ANIMATING;
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mState = STATE_SMALL;
+            }
+        });
+        set.start();
+    }
+
+    public void animateClosed() {
+        if (!(getParent() instanceof CellLayoutChildren)) return;
+
+        CellLayoutChildren clc = (CellLayoutChildren) getParent();
+        final CellLayout cellLayout = (CellLayout) clc.getParent();
+
+        FolderIcon fi = (FolderIcon) cellLayout.getChildAt(mInfo.cellX, mInfo.cellY);
+        CellLayout.LayoutParams iconLp = (CellLayout.LayoutParams) fi.getLayoutParams();
+        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) getLayoutParams();
+
+        PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", iconLp.width);
+        PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", iconLp.height);
+        PropertyValuesHolder x = PropertyValuesHolder.ofInt("x",iconLp.x);
+        PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", iconLp.y);
+
+        ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp, width, height, x, y);
+        oa.addUpdateListener(new AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                requestLayout();
+            }
+        });
+
+        PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);
+        ObjectAnimator oaContentAlpha = ObjectAnimator.ofPropertyValuesHolder(mContent, alpha);
+
+        AnimatorSet set = new AnimatorSet();
+        set.playTogether(oa, oaContentAlpha);
+        set.setDuration(mExpandDuration);
+
+        set.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                cellLayout.removeViewWithoutMarkingCells(Folder.this);
+                mState = STATE_OPEN;
+            }
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mState = STATE_ANIMATING;
+            }
+        });
+        set.start();
+    }
+
+    void notifyDataSetChanged() {
+        // recreate all the children if the data set changes under us. We may want to do this more
+        // intelligently (ie just removing the views that should no longer exist)
+        mContent.removeAllViewsInLayout();
+        bind(mInfo);
+    }
+
+    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+        final ItemInfo item = (ItemInfo) dragInfo;
+        final int itemType = item.itemType;
+        return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+                    itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
+                && item.container != mInfo.id;
+    }
+
+    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+        ShortcutInfo item;
+        if (dragInfo instanceof ApplicationInfo) {
+            // Came from all apps -- make a copy
+            item = ((ApplicationInfo)dragInfo).makeShortcut();
+            item.spanX = 1;
+            item.spanY = 1;
+        } else {
+            item = (ShortcutInfo)dragInfo;
+        }
+        findAndSetEmptyCells(item);
+        mInfo.add(item);
+        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+    }
+
+    protected boolean findAndSetEmptyCells(ShortcutInfo item) {
+        int[] emptyCell = new int[2];
+        if (mContent.findCellForSpan(emptyCell, item.spanX, item.spanY)) {
+            item.cellX = emptyCell[0];
+            item.cellY = emptyCell[1];
+            LauncherModel.addOrMoveItemInDatabase(
+                    mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    protected void createAndAddShortcut(ShortcutInfo item) {
+        final TextView textView =
+            (TextView) mInflater.inflate(R.layout.application_boxed, this, false);
+        textView.setCompoundDrawablesWithIntrinsicBounds(null,
+                new FastBitmapDrawable(item.getIcon(mIconCache)), null, null);
+        textView.setText(item.title);
+        textView.setTag(item);
+
+        textView.setOnClickListener(this);
+        textView.setOnLongClickListener(this);
+
+        CellLayout.LayoutParams lp =
+            new CellLayout.LayoutParams(item.cellX, item.cellY, item.spanX, item.spanY);
+        boolean insert = false;
+        mContent.addViewToCellLayout(textView, insert ? 0 : -1, (int)item.id, lp, true);
+    }
+
+    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+    }
+
+    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+    }
+
+    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+    }
+
+    public void onDropCompleted(View target, Object dragInfo, boolean success) {
+        if (success) {
+            mInfo.remove(mDragItem);
+        }
+    }
+
+    public boolean isDropEnabled() {
+        return true;
+    }
+
+    public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
+            DragView dragView, Object dragInfo) {
+        return null;
+    }
+
+    public void onAdd(ShortcutInfo item) {
+        if ((item.cellX == -1 && item.cellY == -1) ||
+                mContent.isOccupied(item.cellX, item.cellY)) {
+            findAndSetEmptyCells(item);
+        }
+        createAndAddShortcut(item);
+    }
+
+    public int getItemCount() {
+        return mContent.getChildrenLayout().getChildCount();
+    }
+
+    public View getItemAt(int index) {
+        return mContent.getChildrenLayout().getChildAt(index);
+    }
+
+    public void onRemove(ShortcutInfo item) {
+        View v = mContent.getChildAt(mDragItemPosition[0], mDragItemPosition[1]);
+        mContent.removeView(v);
     }
 }
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index dd83c78..b770cd6 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -18,21 +18,27 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
 
 import com.android.launcher.R;
+import com.android.launcher2.FolderInfo.FolderListener;
 
 /**
  * An icon that can appear on in the workspace representing an {@link UserFolder}.
  */
-public class FolderIcon extends BubbleTextView implements DropTarget {
-    private UserFolderInfo mInfo;
+public class FolderIcon extends FrameLayout implements DropTarget, FolderListener {
     private Launcher mLauncher;
-    private Drawable mCloseIcon;
-    private Drawable mOpenIcon;
+    Folder mFolder;
+    FolderInfo mInfo;
+
+    private static final int NUM_ITEMS_IN_PREVIEW = 4;
+    private static final float ICON_ANGLE = 15f;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -43,25 +49,33 @@
     }
 
     public boolean isDropEnabled() {
-        return !((Workspace)getParent().getParent()).isSmall();
+        final ViewGroup cellLayoutChildren = (ViewGroup) getParent();
+        final ViewGroup cellLayout = (ViewGroup) cellLayoutChildren.getParent();
+        final Workspace workspace = (Workspace) cellLayout.getParent();
+        return !workspace.isSmall();
     }
 
     static FolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
-            UserFolderInfo folderInfo, IconCache iconCache) {
+            FolderInfo folderInfo, IconCache iconCache) {
 
         FolderIcon icon = (FolderIcon) LayoutInflater.from(launcher).inflate(resId, group, false);
 
         final Resources resources = launcher.getResources();
-        Drawable d = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder);
-        icon.mCloseIcon = d;
-        icon.mOpenIcon = iconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder_open);
-        icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null);
-        icon.setText(folderInfo.title);
+        Drawable d = iconCache.getFullResIcon(resources, R.drawable.folder_bg);
+        icon.setBackgroundDrawable(d);
         icon.setTag(folderInfo);
         icon.setOnClickListener(launcher);
         icon.mInfo = folderInfo;
         icon.mLauncher = launcher;
-        
+
+        Folder folder = Folder.fromXml(launcher);
+        folder.setDragController(launcher.getDragController());
+        folder.setLauncher(launcher);
+        folder.bind(folderInfo);
+        icon.mFolder = folder;
+
+        folderInfo.addListener(icon);
+
         return icon;
     }
 
@@ -74,6 +88,11 @@
                 && item.container != mInfo.id;
     }
 
+    public void addItem(ShortcutInfo item) {
+        mInfo.add(item);
+        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, item.cellX, item.cellY);
+    }
+
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
         ShortcutInfo item;
@@ -83,15 +102,13 @@
         } else {
             item = (ShortcutInfo)dragInfo;
         }
-        mInfo.add(item);
-        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
+        item.cellX = -1;
+        item.cellY = -1;
+        addItem(item);
     }
 
     public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        if (acceptDrop(source, x, y, xOffset, yOffset, dragView, dragInfo)) {
-            setCompoundDrawablesWithIntrinsicBounds(null, mOpenIcon, null, null);
-        }
     }
 
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
@@ -100,7 +117,6 @@
 
     public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        setCompoundDrawablesWithIntrinsicBounds(null, mCloseIcon, null, null);
     }
 
     @Override
@@ -108,4 +124,49 @@
             DragView dragView, Object dragInfo) {
         return null;
     }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mFolder == null) return;
+        if (mFolder.getItemCount() == 0) return;
+
+        canvas.save();
+        TextView v = (TextView) mFolder.getItemAt(0);
+        Drawable d = v.getCompoundDrawables()[1];
+
+        canvas.translate( (getMeasuredWidth() - d.getIntrinsicWidth()) / 2,
+                (getMeasuredHeight() - d.getIntrinsicHeight()) / 2);
+
+        canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
+        canvas.rotate(ICON_ANGLE);
+
+        canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
+
+        for (int i = Math.max(0, mFolder.getItemCount() - NUM_ITEMS_IN_PREVIEW);
+                i < mFolder.getItemCount(); i++) {
+            v = (TextView) mFolder.getItemAt(i);
+            d = v.getCompoundDrawables()[1];
+
+            if (d != null) {
+                d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+                d.draw(canvas);
+            }
+
+            canvas.translate(d.getIntrinsicWidth() / 2, d.getIntrinsicHeight() / 2);
+            canvas.rotate(-ICON_ANGLE);
+            canvas.translate(-d.getIntrinsicWidth() / 2, -d.getIntrinsicHeight() / 2);
+        }
+
+        canvas.restore();
+    }
+
+    public void onAdd(ShortcutInfo item) {
+        invalidate();
+        requestLayout();
+    }
+
+    public void onRemove(ShortcutInfo item) {
+        invalidate();
+        requestLayout();
+    }
 }
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
index 8732690..12ed27c 100644
--- a/src/com/android/launcher2/FolderInfo.java
+++ b/src/com/android/launcher2/FolderInfo.java
@@ -16,12 +16,15 @@
 
 package com.android.launcher2;
 
+import java.util.ArrayList;
+
+import android.content.ContentValues;
 
 /**
  * Represents a folder containing shortcuts or apps.
  */
 class FolderInfo extends ItemInfo {
-    
+
     /**
      * Whether this folder has been opened
      */
@@ -31,4 +34,60 @@
      * The folder name.
      */
     CharSequence title;
+
+    /**
+     * The apps and shortcuts
+     */
+    ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
+
+    ArrayList<FolderListener> listeners = new ArrayList<FolderListener>();
+
+    FolderInfo() {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
+    }
+
+    /**
+     * Add an app or shortcut
+     *
+     * @param item
+     */
+    public void add(ShortcutInfo item) {
+        contents.add(item);
+        for (int i = 0; i < listeners.size(); i++) {
+            listeners.get(i).onAdd(item);
+        }
+    }
+
+    /**
+     * Remove an app or shortcut. Does not change the DB.
+     *
+     * @param item
+     */
+    public void remove(ShortcutInfo item) {
+        contents.remove(item);
+        for (int i = 0; i < listeners.size(); i++) {
+            listeners.get(i).onRemove(item);
+        }
+    }
+
+    @Override
+    void onAddToDatabase(ContentValues values) {
+        super.onAddToDatabase(values);
+        values.put(LauncherSettings.Favorites.TITLE, title.toString());
+    }
+
+    void addListener(FolderListener listener) {
+        listeners.add(listener);
+    }
+
+    void removeListener(FolderListener listener) {
+        if (listeners.contains(listener)) {
+            listeners.remove(listener);
+        }
+    }
+
+    interface FolderListener {
+        public void onAdd(ShortcutInfo item);
+        public void onRemove(ShortcutInfo item);
+    }
 }
diff --git a/src/com/android/launcher2/HolographicPagedViewIcon.java b/src/com/android/launcher2/HolographicPagedViewIcon.java
index 5e18169..7123e2a 100644
--- a/src/com/android/launcher2/HolographicPagedViewIcon.java
+++ b/src/com/android/launcher2/HolographicPagedViewIcon.java
@@ -41,7 +41,6 @@
     @Override
     protected void onDraw(Canvas canvas) {
         Bitmap overlay = mOriginalIcon.getHolographicOutline();
-
         if (overlay != null) {
             final int offset = getScrollX();
             final int compoundPaddingLeft = getCompoundPaddingLeft();
diff --git a/src/com/android/launcher2/IconCache.java b/src/com/android/launcher2/IconCache.java
index 0c26bf0..7e37afe 100644
--- a/src/com/android/launcher2/IconCache.java
+++ b/src/com/android/launcher2/IconCache.java
@@ -54,7 +54,7 @@
         mContext = context;
         mPackageManager = context.getPackageManager();
         mBubble = new Utilities.BubbleText(context);
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             mIconDpi = DisplayMetrics.DENSITY_HIGH;
         } else {
             mIconDpi = context.getResources().getDisplayMetrics().densityDpi;
diff --git a/src/com/android/launcher2/IconDropTarget.java b/src/com/android/launcher2/IconDropTarget.java
index fb5d0f0..4d018e6 100644
--- a/src/com/android/launcher2/IconDropTarget.java
+++ b/src/com/android/launcher2/IconDropTarget.java
@@ -126,7 +126,7 @@
     @Override
     public void getHitRect(Rect outRect) {
         super.getHitRect(outRect);
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             outRect.top -= mDragPadding[0];
             outRect.right += mDragPadding[1];
             outRect.bottom += mDragPadding[2];
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index b361214..3bb3b07 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -38,7 +38,7 @@
     /**
      * One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
      * {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
-     * {@link LauncherSettings.Favorites#ITEM_TYPE_USER_FOLDER}, or
+     * {@link LauncherSettings.Favorites#ITEM_TYPE_FOLDER}, or
      * {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}.
      */
     int itemType;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index b7f04f7..2fe1c7d 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -17,9 +17,13 @@
 
 package com.android.launcher2;
 
-import com.android.common.Search;
-import com.android.launcher.R;
-import com.android.launcher2.Workspace.ShrinkState;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -63,10 +67,8 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.provider.LiveFolders;
 import android.provider.Settings;
 import android.speech.RecognizerIntent;
 import android.text.Selection;
@@ -99,14 +101,9 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
+import com.android.common.Search;
+import com.android.launcher.R;
+import com.android.launcher2.Workspace.ShrinkState;
 
 /**
  * Default launcher application.
@@ -132,11 +129,9 @@
     private static final int MENU_SETTINGS = MENU_NOTIFICATIONS + 1;
 
     private static final int REQUEST_CREATE_SHORTCUT = 1;
-    private static final int REQUEST_CREATE_LIVE_FOLDER = 4;
     private static final int REQUEST_CREATE_APPWIDGET = 5;
     private static final int REQUEST_PICK_APPLICATION = 6;
     private static final int REQUEST_PICK_SHORTCUT = 7;
-    private static final int REQUEST_PICK_LIVE_FOLDER = 8;
     private static final int REQUEST_PICK_APPWIDGET = 9;
     private static final int REQUEST_PICK_WALLPAPER = 10;
 
@@ -155,7 +150,7 @@
     // Type: int
     private static final String RUNTIME_STATE = "launcher.state";
     // Type: long
-    private static final String RUNTIME_STATE_USER_FOLDERS = "launcher.user_folder";
+    private static final String RUNTIME_STATE_FOLDERS = "launcher.folder";
     // Type: int
     private static final String RUNTIME_STATE_PENDING_ADD_SCREEN = "launcher.add_screen";
     // Type: int
@@ -170,7 +165,7 @@
     private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
 
     /** The different states that Launcher can be in. */
-    private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE,
+    private enum State { WORKSPACE, APPS_CUSTOMIZE, ALL_APPS, CUSTOMIZE,
         CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
     private State mState = State.WORKSPACE;
     private AnimatorSet mStateAnimation;
@@ -203,10 +198,12 @@
     private DeleteZone mDeleteZone;
     private HandleView mHandleView;
     private AllAppsView mAllAppsGrid;
+    private AppsCustomizeTabHost mAppsCustomizeTabHost;
+    private AppsCustomizePagedView mAppsCustomizeContent;
     private CustomizeTrayTabHost mHomeCustomizationDrawer;
     private boolean mAutoAdvanceRunning = false;
 
-    private View mButtonCluster;
+    private ViewGroup mButtonCluster;
     private View mAllAppsButton;
     private View mDivider;
     private View mConfigureButton;
@@ -315,7 +312,6 @@
             // share the same customization workspace across all the tabs
             mCustomizePagedView = (CustomizePagedView) findViewById(
                     R.id.customization_drawer_tab_contents);
-
         }
         setupViews();
 
@@ -330,6 +326,9 @@
         if (mCustomizePagedView != null) {
             mCustomizePagedView.update();
         }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.onPackagesUpdated();
+        }
 
         if (PROFILE_STARTUP) {
             android.os.Debug.stopMethodTracing();
@@ -347,7 +346,7 @@
         registerReceiver(mCloseSystemDialogsReceiver, filter);
 
         // If we have a saved version of these external icons, we load them up immediately
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             if (sGlobalSearchIcon == null || sVoiceSearchIcon == null || sAppMarketIcon == null) {
                 updateIconsAffectedByPackageManagerChanges();
             }
@@ -363,21 +362,6 @@
         }
     }
 
-    @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        super.dispatchPopulateAccessibilityEvent(event);
-
-        // we want to take over text population so it is context dependent
-        event.getText().clear();
-        if (mState == State.ALL_APPS) {
-            event.getText().add(getString(R.string.all_apps_button_label));
-        } else if (mState == State.WORKSPACE) {
-            event.getText().add(getString(R.string.all_apps_home_button_label));
-        }
-
-        return true;
-    }
-
     private void checkForLocaleChange() {
         if (sLocaleConfiguration == null) {
             new AsyncTask<Void, Void, LocaleConfiguration>() {
@@ -648,12 +632,6 @@
             case REQUEST_CREATE_SHORTCUT:
                 completeAddShortcut(args.intent, args.screen, args.cellX, args.cellY);
                 break;
-            case REQUEST_PICK_LIVE_FOLDER:
-                addLiveFolder(args.intent);
-                break;
-            case REQUEST_CREATE_LIVE_FOLDER:
-                completeAddLiveFolder(args.intent, args.screen, args.cellX, args.cellY);
-                break;
             case REQUEST_PICK_APPWIDGET:
                 addAppWidgetFromPick(args.intent);
                 break;
@@ -738,7 +716,12 @@
     public Object onRetainNonConfigurationInstance() {
         // Flag the loader to stop early before switching
         mModel.stopLoader();
-        mAllAppsGrid.surrender();
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.surrender();
+        }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.surrender();
+        }
         return Boolean.TRUE;
     }
 
@@ -771,8 +754,10 @@
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        boolean handled = super.onKeyDown(keyCode, event);
-        if (!handled && acceptFilter() && keyCode != KeyEvent.KEYCODE_ENTER) {
+        final int uniChar = event.getUnicodeChar();
+        final boolean handled = super.onKeyDown(keyCode, event);
+        final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);
+        if (!handled && acceptFilter() && isKeyNotWhitespace) {
             boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,
                     keyCode, event);
             if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {
@@ -832,7 +817,7 @@
 
         State state = intToState(savedState.getInt(RUNTIME_STATE, State.WORKSPACE.ordinal()));
 
-        if (state == State.ALL_APPS) {
+        if (state == State.ALL_APPS || state == State.APPS_CUSTOMIZE) {
             showAllApps(false);
         } else if (state == State.CUSTOMIZE) {
             showCustomizationDrawer(false);
@@ -885,6 +870,20 @@
             // Note: currently we do not restore the page for the customization tray because unlike
             // AllApps, the page content can change drastically
         }
+
+        // Restore the AppsCustomize tab
+        if (mAppsCustomizeTabHost != null) {
+            String curTab = savedState.getString("apps_customize_currentTab");
+            if (curTab != null) {
+             // We set this directly so that there is no delay before the tab is set
+                mAppsCustomizeContent.setContentType(
+                        mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
+                mAppsCustomizeTabHost.setCurrentTabByTag(curTab);
+            }
+
+            // Note: currently we do not restore the page for the AppsCustomize pane because the
+            // change in layout can drastically affect the saved page index
+        }
     }
 
     /**
@@ -896,18 +895,17 @@
         DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer);
         dragLayer.setDragController(dragController);
 
-        mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view);
-        mAllAppsGrid.setLauncher(this);
-        mAllAppsGrid.setDragController(dragController);
-        ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window.
-        // Manage focusability manually since this thing is always visible (in non-xlarge)
-        ((View) mAllAppsGrid).setFocusable(false);
-
-        if (LauncherApplication.isScreenXLarge()) {
-            // They need to be INVISIBLE initially so that they will be measured in the layout.
-            // Otherwise the animations are messed up when we show them for the first time.
-            ((View) mAllAppsGrid).setVisibility(View.INVISIBLE);
-            mHomeCustomizationDrawer.setVisibility(View.INVISIBLE);
+        if (LauncherApplication.isScreenLarge()) {
+            mAllAppsGrid = (AllAppsView) dragLayer.findViewById(R.id.all_apps_view);
+            mAllAppsGrid.setup(this, dragController);
+            // We don't want a hole punched in our window.
+            ((View) mAllAppsGrid).setWillNotDraw(false);
+        } else {
+            mAppsCustomizeTabHost = (AppsCustomizeTabHost)
+                    findViewById(R.id.apps_customize_pane);
+            mAppsCustomizeContent = (AppsCustomizePagedView)
+                    mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
+            mAppsCustomizeContent.setup(this, dragController);
         }
 
         mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace);
@@ -923,7 +921,6 @@
             // we don't use handle view in xlarge mode
             mHandleView = (HandleView)handleView;
             mHandleView.setLauncher(this);
-            mHandleView.setOnClickListener(this);
             mHandleView.setOnLongClickListener(this);
         }
 
@@ -938,8 +935,11 @@
              hotseatRight.setContentDescription(mHotseatLabels[1]);
              hotseatRight.setImageDrawable(mHotseatIcons[1]);
 
+             View.OnKeyListener listener = new IndicatorKeyEventListener();
              mPreviousView = (ImageView) dragLayer.findViewById(R.id.previous_screen);
+             mPreviousView.setOnKeyListener(listener);
              mNextView = (ImageView) dragLayer.findViewById(R.id.next_screen);
+             mNextView.setOnKeyListener(listener);
 
              Drawable previous = mPreviousView.getDrawable();
              Drawable next = mNextView.getDrawable();
@@ -960,10 +960,10 @@
         deleteZone.setDragController(dragController);
 
         final View allAppsButton = findViewById(R.id.all_apps_button);
-        final View divider = findViewById(R.id.divider);
+        final View divider = findViewById(R.id.all_apps_divider);
         final View configureButton = findViewById(R.id.configure_button);
 
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             deleteZone.setOverlappingViews(new View[] { allAppsButton, divider, configureButton });
         } else {
             deleteZone.setOverlappingView(findViewById(R.id.all_apps_button_cluster));
@@ -985,15 +985,17 @@
             allAppsInfoTarget.setLauncher(this);
             dragController.addDragListener(allAppsInfoTarget);
             allAppsInfoTarget.setDragAndDropEnabled(false);
-            View marketButton = findViewById(R.id.market_button);
-            if (marketButton != null) {
+        }
+        View marketButton = findViewById(R.id.market_button);
+        if (marketButton != null) {
+            if (allAppsInfoTarget != null) {
                 allAppsInfoTarget.setOverlappingView(marketButton);
-                marketButton.setOnClickListener(new OnClickListener() {
-                    public void onClick(View v) {
-                        onClickAppMarketButton(v);
-                    }
-                });
             }
+            marketButton.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    onClickAppMarketButton(v);
+                }
+            });
         }
 
         dragController.setDragScoller(workspace);
@@ -1009,10 +1011,22 @@
         if (allAppsDeleteZone != null) {
             dragController.addDropTarget(allAppsDeleteZone);
         }
-        mButtonCluster = findViewById(R.id.all_apps_button_cluster);
+        mButtonCluster = (ViewGroup) findViewById(R.id.all_apps_button_cluster);
+        View.OnKeyListener listener = null;
+        if (LauncherApplication.isScreenLarge()) {
+            // For tablets, AllApps lives in the button bar at the top
+            listener = new ButtonBarKeyEventListener();
+        } else {
+            // For phones, AppsCustomize lives in the "dock" at the bottom
+            listener = new DockKeyEventListener();
+        }
+        int buttonCount = mButtonCluster.getChildCount();
+        for (int i = 0; i < buttonCount; ++i) {
+            mButtonCluster.getChildAt(i).setOnKeyListener(listener);
+        }
 
         mAllAppsButton = findViewById(R.id.all_apps_button);
-        mDivider = findViewById(R.id.divider);
+        mDivider = findViewById(R.id.all_apps_divider);
         mConfigureButton = findViewById(R.id.configure_button);
 
         // We had previously set these click handlers in XML, but the first time we launched
@@ -1043,14 +1057,14 @@
 
     @SuppressWarnings({"UnusedDeclaration"})
     public void previousScreen(View v) {
-        if (mState != State.ALL_APPS) {
+        if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
             mWorkspace.scrollLeft();
         }
     }
 
     @SuppressWarnings({"UnusedDeclaration"})
     public void nextScreen(View v) {
-        if (mState != State.ALL_APPS) {
+        if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
             mWorkspace.scrollRight();
         }
     }
@@ -1253,6 +1267,14 @@
             if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 mUserPresent = false;
                 updateRunning();
+
+                // Reset AllApps to it's initial state
+                if (mAllAppsGrid != null) {
+                    mAllAppsGrid.reset();
+                }
+                if (mAppsCustomizeContent != null) {
+                    mAppsCustomizeContent.reset();
+                }
             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                 mUserPresent = true;
                 updateRunning();
@@ -1407,11 +1429,7 @@
                         != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
 
             // In all these cases, only animate if we're already on home
-
-            if (LauncherApplication.isScreenXLarge()) {
-                mWorkspace.unshrink(alreadyOnHome);
-            }
-
+            mWorkspace.unshrink(alreadyOnHome);
             mWorkspace.exitWidgetResizeMode();
             if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive()) {
                 mWorkspace.moveToDefaultScreen(true);
@@ -1424,6 +1442,14 @@
                         INPUT_METHOD_SERVICE);
                 imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
             }
+
+            // Reset AllApps to it's initial state
+            if (mAllAppsGrid != null) {
+                mAllAppsGrid.reset();
+            }
+            if (mAppsCustomizeContent != null) {
+                mAppsCustomizeContent.reset();
+            }
         }
     }
 
@@ -1445,7 +1471,7 @@
                 final FolderInfo info = folders.get(i).getInfo();
                 ids[i] = info.id;
             }
-            outState.putLongArray(RUNTIME_STATE_USER_FOLDERS, ids);
+            outState.putLongArray(RUNTIME_STATE_FOLDERS, ids);
         } else {
             super.onSaveInstanceState(outState);
         }
@@ -1472,7 +1498,6 @@
                 outState.putInt("allapps_currentPage", mAllAppsPagedView.getCurrentPage());
             }
         }
-
         // Save the current customization drawer tab
         if (mHomeCustomizationDrawer != null) {
             String currentTabTag = mHomeCustomizationDrawer.getCurrentTabTag();
@@ -1480,6 +1505,13 @@
                 outState.putString("customize_currentTab", currentTabTag);
             }
         }
+        // Save the current AppsCustomize tab
+        if (mAppsCustomizeTabHost != null) {
+            String currentTabTag = mAppsCustomizeTabHost.getCurrentTabTag();
+            if (currentTabTag != null) {
+                outState.putString("apps_customize_currentTab", currentTabTag);
+            }
+        }
     }
 
     @Override
@@ -1521,6 +1553,10 @@
         ValueAnimator.clearAllAnimations();
     }
 
+    public DragController getDragController() {
+        return mDragController;
+    }
+
     @Override
     public void startActivityForResult(Intent intent, int requestCode) {
         if (requestCode >= 0) mWaitingForResult = true;
@@ -1588,22 +1624,28 @@
     public boolean onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
-        // If all apps is animating, don't show the menu, because we don't know
-        // which one to show.
-        if (mAllAppsGrid.isAnimating()) {
-            return false;
+        if (mAllAppsGrid != null) {
+            // If all apps is animating, don't show the menu, because we don't know
+            // which one to show.
+            if (mAllAppsGrid.isAnimating()) {
+                return false;
+            }
+
+            // Only show the add and wallpaper options when we're not in all apps.
+            boolean visible = !mAllAppsGrid.isVisible();
+            menu.setGroupVisible(MENU_GROUP_ADD, visible);
+            menu.setGroupVisible(MENU_GROUP_WALLPAPER, visible);
+
+            // Disable add if the workspace is full.
+            if (visible) {
+                CellLayout layout = (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
+                menu.setGroupEnabled(MENU_GROUP_ADD, layout.existsEmptyCell());
+            }
         }
 
-        // Only show the add and wallpaper options when we're not in all apps.
-        boolean visible = !mAllAppsGrid.isVisible();
-        menu.setGroupVisible(MENU_GROUP_ADD, visible);
-        menu.setGroupVisible(MENU_GROUP_WALLPAPER, visible);
-
-        // Disable add if the workspace is full.
-        if (visible) {
-            CellLayout layout = (CellLayout) mWorkspace.getChildAt(mWorkspace.getCurrentPage());
-            menu.setGroupEnabled(MENU_GROUP_ADD, layout.existsEmptyCell());
-        }
+        // TODO-APPS_CUSTOMIZE: Remove this for the phone UI at some point, along with all the menu
+        // related code?
+        if (mAppsCustomizeContent != null && mAppsCustomizeContent.isAnimating()) return false;
 
         return true;
     }
@@ -1653,7 +1695,7 @@
     }
 
     private void addItems() {
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             // Animate the widget chooser up from the bottom of the screen
             if (mState != State.CUSTOMIZE) {
                 showCustomizationDrawer(true);
@@ -1770,38 +1812,15 @@
         startActivityForResult(intent, REQUEST_PICK_WALLPAPER);
     }
 
-    void addLiveFolderFromDrop(ComponentName componentName, int screen, int[] position) {
-        resetAddInfo();
-        mAddScreen = screen;
-        mAddDropPosition = position;
-
-        Intent createFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
-        createFolderIntent.setComponent(componentName);
-
-        addLiveFolder(createFolderIntent);
-    }
-
-    void addLiveFolder(Intent intent) { // YYY add screen intersect etc. parameters here
-        // Handle case where user selected "Folder"
-        String folderName = getResources().getString(R.string.group_folder);
-        String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-
-        if (folderName != null && folderName.equals(shortcutName)) {
-            addFolder(mAddScreen, mAddIntersectCellX, mAddIntersectCellY);
-        } else {
-            startActivityForResultSafely(intent, REQUEST_CREATE_LIVE_FOLDER);
-        }
-    }
-
-    void addFolder(int screen, int intersectCellX, int intersectCellY) {
-        UserFolderInfo folderInfo = new UserFolderInfo();
+    FolderIcon addFolder(int screen, int intersectCellX, int intersectCellY) {
+        FolderInfo folderInfo = new FolderInfo();
         folderInfo.title = getText(R.string.folder_name);
 
         final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
         final int[] cellXY = mTmpAddItemCellCoordinates;
         if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
             showOutOfSpaceMessage();
-            return;
+            return null;
         }
 
         // Update the model
@@ -1815,73 +1834,13 @@
                 (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()),
                 folderInfo, mIconCache);
         mWorkspace.addInScreen(newFolder, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
+        return newFolder;
     }
 
     void removeFolder(FolderInfo folder) {
         sFolders.remove(folder.id);
     }
 
-    private void completeAddLiveFolder(
-            Intent data, int screen, int intersectCellX, int intersectCellY) {
-        final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
-        final int[] cellXY = mTmpAddItemCellCoordinates;
-        if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
-            showOutOfSpaceMessage();
-            return;
-        }
-
-        final LiveFolderInfo info = addLiveFolder(this, data, screen, cellXY[0], cellXY[1], false);
-
-        if (!mRestoring) {
-            final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this,
-                (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentPage()), info);
-            mWorkspace.addInScreen(view, screen, cellXY[0], cellXY[1], 1, 1, isWorkspaceLocked());
-        }
-    }
-
-    static LiveFolderInfo addLiveFolder(Context context, Intent data,
-            int screen, int cellX, int cellY, boolean notify) {
-
-        Intent baseIntent = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT);
-        String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME);
-
-        Drawable icon = null;
-        Intent.ShortcutIconResource iconResource = null;
-
-        Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON);
-        if (extra != null && extra instanceof Intent.ShortcutIconResource) {
-            try {
-                iconResource = (Intent.ShortcutIconResource) extra;
-                final PackageManager packageManager = context.getPackageManager();
-                Resources resources = packageManager.getResourcesForApplication(
-                        iconResource.packageName);
-                final int id = resources.getIdentifier(iconResource.resourceName, null, null);
-                icon = resources.getDrawable(id);
-            } catch (Exception e) {
-                Log.w(TAG, "Could not load live folder icon: " + extra);
-            }
-        }
-
-        if (icon == null) {
-            icon = context.getResources().getDrawable(R.drawable.ic_launcher_folder);
-        }
-
-        final LiveFolderInfo info = new LiveFolderInfo();
-        info.icon = Utilities.createIconBitmap(icon, context);
-        info.title = name;
-        info.iconResource = iconResource;
-        info.uri = data.getData();
-        info.baseIntent = baseIntent;
-        info.displayMode = data.getIntExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
-                LiveFolders.DISPLAY_MODE_GRID);
-
-        LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                screen, cellX, cellY, notify);
-        sFolders.put(info.id, info);
-
-        return info;
-    }
-
     private void showNotifications() {
         final StatusBarManager statusBar = (StatusBarManager) getSystemService(STATUS_BAR_SERVICE);
         if (statusBar != null) {
@@ -1943,7 +1902,7 @@
 
     @Override
     public void onBackPressed() {
-        if (mState == State.ALL_APPS || mState == State.CUSTOMIZE) {
+        if (mState == State.ALL_APPS || mState == State.CUSTOMIZE || mState == State.APPS_CUSTOMIZE) {
             showWorkspace(true);
         } else if (mWorkspace.getOpenFolder() != null) {
             closeFolder();
@@ -1967,15 +1926,14 @@
 
     void closeFolder(Folder folder) {
         folder.getInfo().opened = false;
+
         ViewGroup parent = (ViewGroup) folder.getParent().getParent();
         if (parent != null) {
             CellLayout cl = (CellLayout) parent;
-            cl.removeViewWithoutMarkingCells(folder);
-            if (folder instanceof DropTarget) {
-                // Live folders aren't DropTargets.
-                mDragController.removeDropTarget((DropTarget)folder);
-            }
+            mDragController.removeDropTarget((DropTarget)folder);
         }
+
+        folder.animateClosed();
         folder.onClose();
     }
 
@@ -2020,7 +1978,10 @@
                 mWaitingForResume.setStayPressed(true);
             }
         } else if (tag instanceof FolderInfo) {
-            handleFolderClick((FolderInfo) tag);
+            if (v instanceof FolderIcon) {
+                FolderIcon fi = (FolderIcon) v;
+                handleFolderClick(fi);
+            }
         } else if (v == mHandleView) {
             if (mState == State.ALL_APPS) {
                 showWorkspace(true);
@@ -2142,15 +2103,16 @@
         }
     }
 
-    private void handleFolderClick(FolderInfo folderInfo) {
-        if (!folderInfo.opened) {
+    private void handleFolderClick(FolderIcon folderIcon) {
+        final FolderInfo info = folderIcon.mInfo;
+        if (!info.opened) {
             // Close any open folder
             closeFolder();
             // Open the requested folder
-            openFolder(folderInfo);
+            openFolder(folderIcon);
         } else {
             // Find the open folder...
-            Folder openFolder = mWorkspace.getFolderForTag(folderInfo);
+            Folder openFolder = mWorkspace.getFolderForTag(info);
             int folderScreen;
             if (openFolder != null) {
                 folderScreen = mWorkspace.getPageForView(openFolder);
@@ -2160,7 +2122,7 @@
                     // Close any folder open on the current screen
                     closeFolder();
                     // Pull the folder onto this screen
-                    openFolder(folderInfo);
+                    openFolder(folderIcon);
                 }
             }
         }
@@ -2173,26 +2135,15 @@
      *
      * @param folderInfo The FolderInfo describing the folder to open.
      */
-    public void openFolder(FolderInfo folderInfo) {
-        Folder openFolder;
+    public void openFolder(FolderIcon folderIcon) {
+        Folder folder = folderIcon.mFolder;
+        FolderInfo info = folder.mInfo;
 
-        if (folderInfo instanceof UserFolderInfo) {
-            openFolder = UserFolder.fromXml(this);
-        } else if (folderInfo instanceof LiveFolderInfo) {
-            openFolder = com.android.launcher2.LiveFolder.fromXml(this, folderInfo);
-        } else {
-            return;
-        }
+        info.opened = true;
 
-        openFolder.setDragController(mDragController);
-        openFolder.setLauncher(this);
-
-        openFolder.bind(folderInfo);
-        folderInfo.opened = true;
-
-        mWorkspace.addInFullScreen(openFolder, folderInfo.screen);
-
-        openFolder.onOpen();
+        mWorkspace.addInFullScreen(folder, info.screen);
+        folder.animateOpen();
+        folder.onOpen();
     }
 
     public boolean onLongClick(View v) {
@@ -2202,21 +2153,21 @@
 
         switch (v.getId()) {
             case R.id.previous_screen:
-                if (mState != State.ALL_APPS) {
+                if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
                 }
                 return true;
             case R.id.next_screen:
-                if (mState != State.ALL_APPS) {
+                if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
                 }
                 return true;
             case R.id.all_apps_button:
-                if (mState != State.ALL_APPS) {
+                if (mState != State.ALL_APPS && mState != State.APPS_CUSTOMIZE) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
@@ -2247,10 +2198,10 @@
                 mWorkspace.setAllowLongPress(false);
                 mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                         HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-                if (LauncherApplication.isScreenXLarge()) {
+                if (LauncherApplication.isScreenLarge()) {
                     addItems();
                 } else {
-                    showAddDialog(longClickCellInfo.cellX, longClickCellInfo.cellY);
+                    startWallpaper();
                 }
             } else {
                 if (!(itemUnderLongClick instanceof Folder)) {
@@ -2277,11 +2228,12 @@
                     for (int i = 0; i < count; i++) {
                         ((ImageView) group.getChildAt(i)).setImageDrawable(null);
                     }
-                    ArrayList<Bitmap> bitmaps = (ArrayList<Bitmap>) v.getTag(R.id.icon);
+                    ArrayList<Bitmap> bitmaps =
+                        (ArrayList<Bitmap>) v.getTag(R.id.all_apps_button_cluster);
                     for (Bitmap bitmap : bitmaps) bitmap.recycle();
 
                     v.setTag(R.id.workspace, null);
-                    v.setTag(R.id.icon, null);
+                    v.setTag(R.id.all_apps_button_cluster, null);
                     window.setOnDismissListener(null);
                 }
             });
@@ -2373,7 +2325,7 @@
 
         anchor.setTag(p);
         anchor.setTag(R.id.workspace, preview);
-        anchor.setTag(R.id.icon, bitmaps);
+        anchor.setTag(R.id.all_apps_button_cluster, bitmaps);
     }
 
     class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener {
@@ -2532,7 +2484,9 @@
                     final FolderIcon folderIcon = (FolderIcon)
                             mWorkspace.getViewForTag(mFolderInfo);
                     if (folderIcon != null) {
-                        folderIcon.setText(name);
+                        // TODO: At some point we'll probably want some version of setting
+                        // the text for a folder icon.
+                        //folderIcon.setText(name);
                         getWorkspace().requestLayout();
                     } else {
                         lockAllApps();
@@ -2553,32 +2507,25 @@
 
     // Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
     public boolean isAllAppsVisible() {
-        return mState == State.ALL_APPS;
+        return (mState == State.ALL_APPS) || (mState == State.APPS_CUSTOMIZE);
     }
 
     // AllAppsView.Watcher
     public void zoomed(float zoom) {
         // In XLarge view, we zoom down the workspace below all apps so it's still visible
-        if (zoom == 1.0f && !LauncherApplication.isScreenXLarge()) {
+        if (zoom == 1.0f && !LauncherApplication.isScreenLarge()) {
             mWorkspace.setVisibility(View.GONE);
         }
     }
     
     private void showAndEnableToolbarButton(View button) {
         button.setVisibility(View.VISIBLE);
-        button.setFocusable(true);
-        button.setClickable(true);
     }
 
     private void hideToolbarButton(View button) {
-        button.setAlpha(0.0f);
         // We can't set it to GONE, otherwise the RelativeLayout gets screwed up
         button.setVisibility(View.INVISIBLE);
-    }
-
-    private void disableToolbarButton(View button) {
-        button.setFocusable(false);
-        button.setClickable(false);
+        button.setAlpha(0.0f);
     }
 
     /**
@@ -2609,7 +2556,6 @@
                 @Override
                 public void onAnimationStart(Animator animation) {
                     if (showing) showAndEnableToolbarButton(view);
-                    if (hiding) disableToolbarButton(view);
                 }
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -2622,7 +2568,6 @@
                 showAndEnableToolbarButton(view);
                 view.setAlpha(1f);
             } else {
-                disableToolbarButton(view);
                 hideToolbarButton(view);
             }
         }
@@ -2640,15 +2585,18 @@
         switch (newState) {
         case WORKSPACE:
             hideOrShowToolbarButton(true, mButtonCluster, showSeq);
-            mDeleteZone.setOverlappingViews(
-                    new View[] { mAllAppsButton, mDivider, mConfigureButton });
             mDeleteZone.setDragAndDropEnabled(true);
-            mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
+            if (LauncherApplication.isScreenLarge()) {
+                mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_workspace));
+            }
             break;
         case ALL_APPS:
+        case APPS_CUSTOMIZE:
             hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
             mDeleteZone.setDragAndDropEnabled(false);
-            mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
+            if (LauncherApplication.isScreenLarge()) {
+                mDeleteZone.setText(getResources().getString(R.string.delete_zone_label_all_apps));
+            }
             break;
         case CUSTOMIZE:
             hideOrShowToolbarButton(false, mButtonCluster, hideSeq);
@@ -2670,7 +2618,7 @@
         // Set pivotY so that at the starting zoom factor, the view is partially
         // visible. Modifying initialHeightFactor changes how much of the view is
         // initially showing, and hence the perceived angle from which the view enters.
-        if (state == State.ALL_APPS) {
+        if (state == State.ALL_APPS || state == State.APPS_CUSTOMIZE) {
             final float initialHeightFactor = 0.175f;
             view.setPivotY((1 - initialHeightFactor) * height);
         } else {
@@ -2685,27 +2633,45 @@
      * of the screen.
      * @param toState The state to zoom out to. Must be ALL_APPS or CUSTOMIZE.
      */
-    private void cameraZoomOut(State toState, boolean animated) {
+    private void cameraZoomOut(State toState, boolean animated, boolean springLoaded) {
         final Resources res = getResources();
-        final boolean toAllApps = (toState == State.ALL_APPS);
+        final boolean toAllApps = (toState == State.ALL_APPS)
+                || (toState == State.APPS_CUSTOMIZE);
 
-        final int duration = toAllApps ?
-                res.getInteger(R.integer.config_allAppsZoomInTime) :
-                res.getInteger(R.integer.config_customizeZoomInTime);
-        final int fadeDuration = toAllApps ?
-                res.getInteger(R.integer.config_allAppsFadeInTime) :
-                res.getInteger(R.integer.config_customizeFadeInTime);
+        final int duration = (toAllApps ?
+                res.getInteger(R.integer.config_appsCustomizeZoomInTime) :
+                res.getInteger(R.integer.config_customizeZoomInTime));
+        final int fadeDuration = (toAllApps ?
+                res.getInteger(R.integer.config_appsCustomizeFadeInTime) :
+                res.getInteger(R.integer.config_customizeFadeInTime));
 
         final float scale = toAllApps ?
-                (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+                (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor) :
                 (float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
 
-        final View toView = toAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+        View tmpView;
+        if (toAllApps) {
+            tmpView = (LauncherApplication.isScreenLarge())
+                    ? (View) mAllAppsGrid : mAppsCustomizeTabHost;
+        } else {
+            tmpView = mHomeCustomizationDrawer;
+        }
+        final View toView = tmpView;
 
         setPivotsForZoom(toView, toState, scale);
 
         if (toAllApps) {
-            mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+            if (!springLoaded) {
+                mWorkspace.shrink(ShrinkState.BOTTOM_HIDDEN, animated);
+
+                if (LauncherApplication.isScreenLarge()) {
+                    // Everytime we launch into AllApps, we reset the successful drop flag which
+                    // controls when it should hide/show the mini workspaces
+                    mAllAppsPagedView.resetSuccessfulDropFlag();
+                }
+            } else {
+                mWorkspace.shrink(ShrinkState.BOTTOM_VISIBLE, animated);
+            }
         } else {
             mWorkspace.shrink(ShrinkState.TOP, animated);
         }
@@ -2713,10 +2679,8 @@
         if (animated) {
             final ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
             scaleAnim.setInterpolator(new Workspace.ZoomOutInterpolator());
-            scaleAnim.addUpdateListener(new AnimatorUpdateListener() {
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    final float b = (Float) animation.getAnimatedValue();
-                    final float a = 1f - b;
+            scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                public void onAnimationUpdate(float a, float b) {
                     ((View) toView.getParent()).fastInvalidate();
                     toView.setFastScaleX(a * scale + b * 1f);
                     toView.setFastScaleY(a * scale + b * 1f);
@@ -2724,13 +2688,12 @@
             });
 
             if (toAllApps) {
+                toView.setVisibility(View.VISIBLE);
                 toView.setFastAlpha(0f);
                 ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(fadeDuration);
                 alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-                alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        final float b = (Float) animation.getAnimatedValue();
-                        final float a = 1f - b;
+                alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                    public void onAnimationUpdate(float a, float b) {
                         // don't need to invalidate because we do so above
                         toView.setFastAlpha(a * 0f + b * 1f);
                     }
@@ -2748,6 +2711,7 @@
                     toView.setTranslationX(0.0f);
                     toView.setTranslationY(0.0f);
                     toView.setVisibility(View.VISIBLE);
+                    toView.bringToFront();
                     if (!toAllApps) {
                         toView.setFastAlpha(1.0f);
                     }
@@ -2787,6 +2751,7 @@
             toView.setScaleX(1.0f);
             toView.setScaleY(1.0f);
             toView.setVisibility(View.VISIBLE);
+            toView.bringToFront();
             if (toView instanceof LauncherTransitionable) {
                 ((LauncherTransitionable) toView).onLauncherTransitionStart(null);
                 ((LauncherTransitionable) toView).onLauncherTransitionEnd(null);
@@ -2801,33 +2766,38 @@
      * @param fromState The current state (must be ALL_APPS or CUSTOMIZE).
      * @param animated If true, the transition will be animated.
      */
-    private void cameraZoomIn(State fromState, boolean animated) {
-        cameraZoomIn(fromState, animated, false);
-    }
-
     private void cameraZoomIn(State fromState, boolean animated, boolean springLoaded) {
         Resources res = getResources();
-        final boolean fromAllApps = (fromState == State.ALL_APPS);
+        final boolean fromAllApps = (fromState == State.ALL_APPS)
+                || (fromState == State.APPS_CUSTOMIZE);
 
         int duration = fromAllApps ?
-            res.getInteger(R.integer.config_allAppsZoomOutTime) :
+            res.getInteger(R.integer.config_appsCustomizeZoomOutTime) :
             res.getInteger(R.integer.config_customizeZoomOutTime);
 
         final float scaleFactor = fromAllApps ?
-            (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor) :
+            (float) res.getInteger(R.integer.config_appsCustomizeZoomScaleFactor) :
             (float) res.getInteger(R.integer.config_customizeZoomScaleFactor);
 
-        final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+        View tmpView;
+        if (fromAllApps) {
+            tmpView = (LauncherApplication.isScreenLarge())
+                    ? (View) mAllAppsGrid : mAppsCustomizeTabHost;
+        } else {
+            tmpView = mHomeCustomizationDrawer;
+        }
+        final View fromView = tmpView;
 
-        mCustomizePagedView.endChoiceMode();
-        mAllAppsPagedView.endChoiceMode();
+        if (LauncherApplication.isScreenLarge()) {
+            mCustomizePagedView.endChoiceMode();
+            mAllAppsPagedView.endChoiceMode();
+        }
 
         setPivotsForZoom(fromView, fromState, scaleFactor);
 
         if (!springLoaded) {
             mWorkspace.unshrink(animated);
         }
-
         if (animated) {
             if (mStateAnimation != null) mStateAnimation.cancel();
             mStateAnimation = new AnimatorSet();
@@ -2837,22 +2807,18 @@
 
             ValueAnimator scaleAnim = ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
             scaleAnim.setInterpolator(new Workspace.ZoomInInterpolator());
-            scaleAnim.addUpdateListener(new AnimatorUpdateListener() {
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    final float b = (Float) animation.getAnimatedValue();
-                    final float a = 1f - b;
+            scaleAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                public void onAnimationUpdate(float a, float b) {
                     ((View)fromView.getParent()).fastInvalidate();
                     fromView.setFastScaleX(a * oldScaleX + b * scaleFactor);
                     fromView.setFastScaleY(a * oldScaleY + b * scaleFactor);
                 }
             });
             final ValueAnimator alphaAnim = ValueAnimator.ofFloat(0f, 1f);
-            alphaAnim.setDuration(res.getInteger(R.integer.config_allAppsFadeOutTime));
+            alphaAnim.setDuration(res.getInteger(R.integer.config_appsCustomizeFadeOutTime));
             alphaAnim.setInterpolator(new DecelerateInterpolator(1.5f));
-            alphaAnim.addUpdateListener(new AnimatorUpdateListener() {
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    final float b = (Float) animation.getAnimatedValue();
-                    final float a = 1f - b;
+            alphaAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                public void onAnimationUpdate(float a, float b) {
                     // don't need to invalidate because we do so above
                     fromView.setFastAlpha(a * 1f + b * 0f);
                 }
@@ -2895,34 +2861,6 @@
         }
     }
 
-    void showAllApps(boolean animated) {
-        if (mState != State.WORKSPACE) {
-            return;
-        }
-
-        if (LauncherApplication.isScreenXLarge()) {
-            cameraZoomOut(State.ALL_APPS, animated);
-        } else {
-            mAllAppsGrid.zoom(1.0f, animated);
-        }
-
-        ((View) mAllAppsGrid).setFocusable(true);
-        ((View) mAllAppsGrid).requestFocus();
-
-        // TODO: fade these two too
-        mDeleteZone.setVisibility(View.GONE);
-
-        // Change the state *after* we've called all the transition code
-        mState = State.ALL_APPS;
-
-        // Pause the auto-advance of widgets until we are out of AllApps
-        mUserPresent = false;
-        updateRunning();
-
-        // send an accessibility event to announce the context change
-        getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-    }
-
     void showWorkspace(boolean animated) {
         showWorkspace(animated, null);
     }
@@ -2935,7 +2873,7 @@
         } else {
             mWorkspace.unshrink(animated);
         }
-        if (mState == State.ALL_APPS) {
+        if (mState == State.ALL_APPS || mState == State.APPS_CUSTOMIZE) {
             closeAllApps(animated);
         } else if (mState == State.CUSTOMIZE) {
             hideCustomizationDrawer(animated);
@@ -2954,12 +2892,16 @@
 
     void enterSpringLoadedDragMode(CellLayout layout) {
         mWorkspace.enterSpringLoadedDragMode(layout);
-        if (mState == State.ALL_APPS) {
-            cameraZoomIn(State.ALL_APPS, true, true);
+        if (mState == State.ALL_APPS || mState == State.APPS_CUSTOMIZE) {
             mState = State.ALL_APPS_SPRING_LOADED;
+            if (LauncherApplication.isScreenLarge()) {
+                cameraZoomIn(State.ALL_APPS, true, true);
+            } else {
+                cameraZoomIn(State.APPS_CUSTOMIZE, true, true);
+            }
         } else if (mState == State.CUSTOMIZE) {
-            cameraZoomIn(State.CUSTOMIZE, true, true);
             mState = State.CUSTOMIZE_SPRING_LOADED;
+            cameraZoomIn(State.CUSTOMIZE, true, true);
         }/* else {
             // we're already in spring loaded mode; don't do anything
         }*/
@@ -2968,17 +2910,50 @@
     void exitSpringLoadedDragMode() {
         if (mState == State.ALL_APPS_SPRING_LOADED) {
             mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
-            cameraZoomOut(State.ALL_APPS, true);
-            mState = State.ALL_APPS;
+            if (LauncherApplication.isScreenLarge()) {
+                cameraZoomOut(State.ALL_APPS, true, true);
+                mState = State.ALL_APPS;
+            } else {
+                cameraZoomOut(State.APPS_CUSTOMIZE, true, true);
+                mState = State.APPS_CUSTOMIZE;
+            }
         } else if (mState == State.CUSTOMIZE_SPRING_LOADED) {
             mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.TOP);
-            cameraZoomOut(State.CUSTOMIZE, true);
+            cameraZoomOut(State.CUSTOMIZE, true, true);
             mState = State.CUSTOMIZE;
         }/* else {
             // we're not in spring loaded mode; don't do anything
         }*/
     }
 
+    void showAllApps(boolean animated) {
+        if (mState != State.WORKSPACE) return;
+        if (LauncherApplication.isScreenLarge()) {
+            cameraZoomOut(State.ALL_APPS, animated, false);
+            ((View) mAllAppsGrid).requestFocus();
+
+            // TODO: fade these two too
+            mDeleteZone.setVisibility(View.GONE);
+
+            // Change the state *after* we've called all the transition code
+            mState = State.ALL_APPS;
+        } else {
+            View appsCustomizePane = findViewById(R.id.apps_customize_pane);
+            cameraZoomOut(State.APPS_CUSTOMIZE, animated, false);
+            appsCustomizePane.requestFocus();
+
+            // Change the state *after* we've called all the transition code
+            mState = State.APPS_CUSTOMIZE;
+        }
+
+        // Pause the auto-advance of widgets until we are out of AllApps
+        mUserPresent = false;
+        updateRunning();
+
+        // Send an accessibility event to announce the context change
+        getWindow().getDecorView().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+    }
+
     /**
      * Things to test when changing this code.
      *   - Home from workspace
@@ -3019,15 +2994,22 @@
      *          - From another workspace
      */
     void closeAllApps(boolean animated) {
-        if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
-            mWorkspace.setVisibility(View.VISIBLE);
-            if (LauncherApplication.isScreenXLarge()) {
-                cameraZoomIn(State.ALL_APPS, animated);
-            } else {
-                mAllAppsGrid.zoom(0.0f, animated);
+        if (LauncherApplication.isScreenLarge()) {
+            if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
+                mWorkspace.setVisibility(View.VISIBLE);
+                cameraZoomIn(State.ALL_APPS, animated, false);
+
+                // Set focus to the AllApps button
+                findViewById(R.id.all_apps_button).requestFocus();
             }
-            ((View)mAllAppsGrid).setFocusable(false);
-            mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
+        } else {
+            if (mState == State.APPS_CUSTOMIZE || mState == State.ALL_APPS_SPRING_LOADED) {
+                mWorkspace.setVisibility(View.VISIBLE);
+                cameraZoomIn(State.APPS_CUSTOMIZE, animated, false);
+
+                // Set focus to the AllApps button
+                findViewById(R.id.all_apps_button).requestFocus();
+            }
         }
     }
 
@@ -3045,7 +3027,7 @@
             return;
         }
 
-        cameraZoomOut(State.CUSTOMIZE, animated);
+        cameraZoomOut(State.CUSTOMIZE, animated, false);
 
         // Change the state *after* we've called all the transition code
         mState = State.CUSTOMIZE;
@@ -3058,7 +3040,10 @@
     // Hide the customization drawer (only exists in x-large configuration)
     void hideCustomizationDrawer(boolean animated) {
         if (mState == State.CUSTOMIZE || mState == State.CUSTOMIZE_SPRING_LOADED) {
-            cameraZoomIn(State.CUSTOMIZE, animated);
+            cameraZoomIn(State.CUSTOMIZE, animated, false);
+
+            // Set focus to the customize button
+            findViewById(R.id.configure_button).requestFocus();
         }
     }
 
@@ -3140,15 +3125,21 @@
     }
 
     private void updateGlobalSearchIcon() {
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
+            final View searchButton = findViewById(R.id.search_button);
+            final View searchDivider = findViewById(R.id.search_divider);
+
             final SearchManager searchManager =
                     (SearchManager) getSystemService(Context.SEARCH_SERVICE);
             ComponentName activityName = searchManager.getGlobalSearchActivity();
             if (activityName != null) {
                 sGlobalSearchIcon = updateButtonWithIconFromExternalActivity(
                         R.id.search_button, activityName, R.drawable.ic_generic_search);
+                searchButton.setVisibility(View.VISIBLE);
+                searchDivider.setVisibility(View.VISIBLE);
             } else {
-                findViewById(R.id.search_button).setVisibility(View.GONE);
+                searchButton.setVisibility(View.GONE);
+                searchDivider.setVisibility(View.GONE);
             }
         }
     }
@@ -3158,14 +3149,20 @@
     }
 
     private void updateVoiceSearchIcon() {
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
+            final View searchDivider = findViewById(R.id.search_divider);
+            final View voiceButton = findViewById(R.id.voice_button);
+
             Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
             ComponentName activityName = intent.resolveActivity(getPackageManager());
             if (activityName != null) {
                 sVoiceSearchIcon = updateButtonWithIconFromExternalActivity(
                         R.id.voice_button, activityName, R.drawable.ic_voice_search);
+                searchDivider.setVisibility(View.VISIBLE);
+                voiceButton.setVisibility(View.VISIBLE);
             } else {
-                findViewById(R.id.voice_button).setVisibility(View.GONE);
+                searchDivider.setVisibility(View.GONE);
+                voiceButton.setVisibility(View.GONE);
             }
         }
     }
@@ -3178,16 +3175,21 @@
      * Sets the app market icon (shown when all apps is visible on x-large screens)
      */
     private void updateAppMarketIcon() {
-        if (LauncherApplication.isScreenXLarge()) {
-            Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET);
-            // Find the app market activity by resolving an intent.
-            // (If multiple app markets are installed, it will return the ResolverActivity.)
-            ComponentName activityName = intent.resolveActivity(getPackageManager());
-            if (activityName != null) {
-                mAppMarketIntent = intent;
-                sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
-                        R.id.market_button, activityName, R.drawable.app_market_generic);
-            }
+        final View marketButton = findViewById(R.id.market_button);
+        Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_MARKET);
+        // Find the app market activity by resolving an intent.
+        // (If multiple app markets are installed, it will return the ResolverActivity.)
+        ComponentName activityName = intent.resolveActivity(getPackageManager());
+        if (activityName != null) {
+            mAppMarketIntent = intent;
+            sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
+                    R.id.market_button, activityName, R.drawable.app_market_generic);
+            marketButton.setVisibility(View.VISIBLE);
+        } else {
+            // We should hide and disable the view so that we don't try and restore the visibility
+            // of it when we swap between drag & normal states from IconDropTarget subclasses.
+            marketButton.setVisibility(View.GONE);
+            marketButton.setEnabled(false);
         }
     }
 
@@ -3261,31 +3263,6 @@
                     break;
                 }
 
-                case AddAdapter.ITEM_LIVE_FOLDER: {
-                    // Insert extra item to handle inserting folder
-                    Bundle bundle = new Bundle();
-
-                    ArrayList<String> shortcutNames = new ArrayList<String>();
-                    shortcutNames.add(res.getString(R.string.group_folder));
-                    bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
-
-                    ArrayList<ShortcutIconResource> shortcutIcons =
-                            new ArrayList<ShortcutIconResource>();
-                    shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
-                            R.drawable.ic_launcher_folder));
-                    bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
-
-                    Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
-                    pickIntent.putExtra(Intent.EXTRA_INTENT,
-                            new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER));
-                    pickIntent.putExtra(Intent.EXTRA_TITLE,
-                            getText(R.string.title_select_live_folder));
-                    pickIntent.putExtras(bundle);
-
-                    startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
-                    break;
-                }
-
                 case AddAdapter.ITEM_WALLPAPER: {
                     startWallpaper();
                     break;
@@ -3376,6 +3353,8 @@
      */
     public void startBinding() {
         final Workspace workspace = mWorkspace;
+
+        mWorkspace.clearDropTargets();
         int count = workspace.getChildCount();
         for (int i = 0; i < count; i++) {
             // Use removeAllViewsInLayout() to avoid an extra requestLayout() and invalidate().
@@ -3421,21 +3400,13 @@
                     workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1,
                             false);
                     break;
-                case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                     final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this,
                             (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
-                            (UserFolderInfo) item, mIconCache);
+                            (FolderInfo) item, mIconCache);
                     workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1,
                             false);
                     break;
-                case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
-                    final FolderIcon newLiveFolder = LiveFolderIcon.fromXml(
-                            R.layout.live_folder_icon, this,
-                            (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
-                            (LiveFolderInfo) item);
-                    workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1,
-                            false);
-                    break;
             }
         }
 
@@ -3504,12 +3475,14 @@
                 mWorkspace.getChildAt(mWorkspace.getCurrentPage()).requestFocus();
             }
 
-            final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS);
-            if (userFolders != null) {
-                for (long folderId : userFolders) {
+            final long[] folders = mSavedState.getLongArray(RUNTIME_STATE_FOLDERS);
+            if (folders != null) {
+                for (long folderId : folders) {
                     final FolderInfo info = sFolders.get(folderId);
-                    if (info != null) {
-                        openFolder(info);
+                    final FolderIcon folderIcon = (FolderIcon)
+                        mWorkspace.getViewForTag(info);
+                    if (folderIcon != null) {
+                        openFolder(folderIcon);
                     }
                 }
                 final Folder openFolder = mWorkspace.getOpenFolder();
@@ -3528,7 +3501,7 @@
 
         // Workaround a bug that occurs when rotating the device while the customization mode is
         // open, we trigger a new layout on all the CellLayout children.
-        if (LauncherApplication.isScreenXLarge() && (mState == State.CUSTOMIZE)) {
+        if (LauncherApplication.isScreenLarge() && (mState == State.CUSTOMIZE)) {
             final int childCount = mWorkspace.getChildCount();
             for (int i = 0; i < childCount; ++i) {
                 mWorkspace.getChildAt(i).requestLayout();
@@ -3561,7 +3534,12 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void bindAllApplications(ArrayList<ApplicationInfo> apps) {
-        mAllAppsGrid.setApps(apps);
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.setApps(apps);
+        }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.setApps(apps);
+        }
         if (mCustomizePagedView != null) {
             mCustomizePagedView.setApps(apps);
         }
@@ -3576,7 +3554,12 @@
     public void bindAppsAdded(ArrayList<ApplicationInfo> apps) {
         setLoadOnResume();
         removeDialog(DIALOG_CREATE_SHORTCUT);
-        mAllAppsGrid.addApps(apps);
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.addApps(apps);
+        }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.addApps(apps);
+        }
         if (mCustomizePagedView != null) {
             mCustomizePagedView.addApps(apps);
         }
@@ -3597,6 +3580,9 @@
         if (mAllAppsGrid != null) {
             mAllAppsGrid.updateApps(apps);
         }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.updateApps(apps);
+        }
         if (mCustomizePagedView != null) {
             mCustomizePagedView.updateApps(apps);
         }
@@ -3613,7 +3599,12 @@
         if (permanent) {
             mWorkspace.removeItems(apps);
         }
-        mAllAppsGrid.removeApps(apps);
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.removeApps(apps);
+        }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.removeApps(apps);
+        }
         if (mCustomizePagedView != null) {
             mCustomizePagedView.removeApps(apps);
         }
@@ -3628,6 +3619,9 @@
         if (mCustomizePagedView != null) {
             mCustomizePagedView.update();
         }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.onPackagesUpdated();
+        }
     }
 
     private int mapConfigurationOriActivityInfoOri(int configOri) {
@@ -3686,7 +3680,12 @@
         Log.d(TAG, "mDesktopItems.size=" + mDesktopItems.size());
         Log.d(TAG, "sFolders.size=" + sFolders.size());
         mModel.dumpState();
-        mAllAppsGrid.dumpState();
+        if (mAllAppsGrid != null) {
+            mAllAppsGrid.dumpState();
+        }
+        if (mAppsCustomizeContent != null) {
+            mAppsCustomizeContent.dumpState();
+        }
         Log.d(TAG, "END launcher2 dump state");
     }
 }
diff --git a/src/com/android/launcher2/LauncherAnimatorUpdateListener.java b/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
new file mode 100644
index 0000000..dd82113
--- /dev/null
+++ b/src/com/android/launcher2/LauncherAnimatorUpdateListener.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+
+abstract class LauncherAnimatorUpdateListener implements AnimatorUpdateListener {
+    public void onAnimationUpdate(ValueAnimator animation) {
+        final float b = (Float) animation.getAnimatedValue();
+        final float a = 1f - b;
+        onAnimationUpdate(a, b);
+    }
+
+    abstract void onAnimationUpdate(float a, float b);
+}
\ No newline at end of file
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index 7f60cac..0dd1d83 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -22,6 +22,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
+import android.view.ViewGroup;
 
 import com.android.launcher.R;
 
@@ -122,4 +123,9 @@
         }
         super.onVisibilityChanged(changedView, visibility);
     }
+
+    @Override
+    public int getDescendantFocusability() {
+        return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+    }
 }
diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java
index ed007dd..67573e0 100644
--- a/src/com/android/launcher2/LauncherApplication.java
+++ b/src/com/android/launcher2/LauncherApplication.java
@@ -23,23 +23,22 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.os.Handler;
-import dalvik.system.VMRuntime;
 
 public class LauncherApplication extends Application {
     public LauncherModel mModel;
     public IconCache mIconCache;
-    private static boolean sIsScreenXLarge;
+    private static boolean sIsScreenLarge;
     private static float sScreenDensity;
     private static final boolean ENABLE_ROTATION = false;
 
     @Override
     public void onCreate() {
-        VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024);
-
         super.onCreate();
 
         // set sIsScreenXLarge and sScreenDensity *before* creating icon cache
-        sIsScreenXLarge = (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+        final int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+        sIsScreenLarge = screenSize == Configuration.SCREENLAYOUT_SIZE_LARGE ||
+            screenSize == Configuration.SCREENLAYOUT_SIZE_XLARGE;
         sScreenDensity = getResources().getDisplayMetrics().density;
 
         mIconCache = new IconCache(this);
@@ -100,11 +99,11 @@
     }
 
     public static boolean isInPlaceRotationEnabled() {
-        return sIsScreenXLarge && ENABLE_ROTATION;
+        return sIsScreenLarge && ENABLE_ROTATION;
     }
 
-    public static boolean isScreenXLarge() {
-        return sIsScreenXLarge;
+    public static boolean isScreenLarge() {
+        return sIsScreenLarge;
     }
 
     public static float getScreenDensity() {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index c098749..d5505c5 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -37,7 +37,6 @@
 import android.content.Intent.ShortcutIconResource;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -91,9 +90,6 @@
 
     private AllAppsList mAllAppsList; // only access in worker thread
     private IconCache mIconCache;
-    final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
-    final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
-    final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
 
     private Bitmap mDefaultIcon;
 
@@ -271,8 +267,7 @@
         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
                 "_id=? and (itemType=? or itemType=?)",
                 new String[] { String.valueOf(id),
-                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER),
-                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null);
+                        String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);
 
         try {
             if (c.moveToFirst()) {
@@ -285,11 +280,8 @@
 
                 FolderInfo folderInfo = null;
                 switch (c.getInt(itemTypeIndex)) {
-                    case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
-                        folderInfo = findOrMakeUserFolder(folderList, id);
-                        break;
-                    case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
-                        folderInfo = findOrMakeLiveFolder(folderList, id);
+                    case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+                        folderInfo = findOrMakeFolder(folderList, id);
                         break;
                 }
 
@@ -391,7 +383,7 @@
     /**
      * Remove the contents of the specified folder from the database
      */
-    static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) {
+    static void deleteFolderContentsFromDatabase(Context context, FolderInfo info) {
         final ContentResolver cr = context.getContentResolver();
 
         cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
@@ -522,9 +514,6 @@
                 mLoaderTask.stopLocked();
             }
         }
-        mItems.clear();
-        mAppWidgets.clear();
-        mFolders.clear();
     }
 
     /**
@@ -540,6 +529,10 @@
         private boolean mStopped;
         private boolean mLoadAndBindStepFinished;
 
+        final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>();
+        final ArrayList<LauncherAppWidgetInfo> mAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
+        final HashMap<Long, FolderInfo> mFolders = new HashMap<Long, FolderInfo>();
+
         LoaderTask(Context context, boolean isLaunching) {
             mContext = context;
             mIsLaunching = isLaunching;
@@ -659,22 +652,6 @@
                     mLoaderTask = null;
                 }
             }
-
-            // Trigger a gc to try to clean up after the stuff is done, since the
-            // renderscript allocations aren't charged to the java heap.
-            if (mStopped) {
-                mHandler.post(new Runnable() {
-                        public void run() {
-                            System.gc();
-                        }
-                    });
-            } else {
-                mHandler.postIdle(new Runnable() {
-                        public void run() {
-                            System.gc();
-                        }
-                    });
-            }
         }
 
         public void stopLocked() {
@@ -843,8 +820,8 @@
                                     break;
                                 default:
                                     // Item is in a user folder
-                                    UserFolderInfo folderInfo =
-                                            findOrMakeUserFolder(mFolders, container);
+                                    FolderInfo folderInfo =
+                                            findOrMakeFolder(mFolders, container);
                                     folderInfo.add(info);
                                     break;
                                 }
@@ -864,9 +841,9 @@
                             }
                             break;
 
-                        case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                             id = c.getLong(idIndex);
-                            UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id);
+                            FolderInfo folderInfo = findOrMakeFolder(mFolders, id);
 
                             folderInfo.title = c.getString(titleIndex);
                             folderInfo.id = id;
@@ -889,57 +866,6 @@
                             mFolders.put(folderInfo.id, folderInfo);
                             break;
 
-                        case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
-                            id = c.getLong(idIndex);
-                            Uri uri = Uri.parse(c.getString(uriIndex));
-
-                            // Make sure the live folder exists
-                            final ProviderInfo providerInfo =
-                                    context.getPackageManager().resolveContentProvider(
-                                            uri.getAuthority(), 0);
-
-                            if (providerInfo == null && !isSafeMode) {
-                                itemsToRemove.add(id);
-                            } else {
-                                LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id);
-                                intentDescription = c.getString(intentIndex);
-                                intent = null;
-                                if (intentDescription != null) {
-                                    try {
-                                        intent = Intent.parseUri(intentDescription, 0);
-                                    } catch (URISyntaxException e) {
-                                        // Ignore, a live folder might not have a base intent
-                                    }
-                                }
-
-                                liveFolderInfo.title = c.getString(titleIndex);
-                                liveFolderInfo.id = id;
-                                liveFolderInfo.uri = uri;
-                                container = c.getInt(containerIndex);
-                                liveFolderInfo.container = container;
-                                liveFolderInfo.screen = c.getInt(screenIndex);
-                                liveFolderInfo.cellX = c.getInt(cellXIndex);
-                                liveFolderInfo.cellY = c.getInt(cellYIndex);
-                                liveFolderInfo.baseIntent = intent;
-                                liveFolderInfo.displayMode = c.getInt(displayModeIndex);
-
-                                // check & update map of what's occupied
-                                if (!checkItemPlacement(occupied, liveFolderInfo)) {
-                                    break;
-                                }
-
-                                loadLiveFolderIcon(context, c, iconTypeIndex, iconPackageIndex,
-                                        iconResourceIndex, liveFolderInfo);
-
-                                switch (container) {
-                                    case LauncherSettings.Favorites.CONTAINER_DESKTOP:
-                                        mItems.add(liveFolderInfo);
-                                        break;
-                                }
-                                mFolders.put(liveFolderInfo.id, liveFolderInfo);
-                            }
-                            break;
-
                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                             // Read all Launcher-specific widget details
                             int appWidgetId = c.getInt(appWidgetIdIndex);
@@ -1294,6 +1220,7 @@
             Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
             Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
             Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
+            Log.d(TAG, "mItems size=" + mItems.size());
         }
     }
 
@@ -1623,13 +1550,11 @@
         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
 
         Bitmap icon = null;
-        boolean filtered = false;
         boolean customIcon = false;
         ShortcutIconResource iconResource = null;
 
         if (bitmap != null && bitmap instanceof Bitmap) {
             icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);
-            filtered = true;
             customIcon = true;
         } else {
             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
@@ -1668,38 +1593,6 @@
         return info;
     }
 
-    private void loadLiveFolderIcon(Context context, Cursor c, int iconTypeIndex,
-            int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) {
-
-        int iconType = c.getInt(iconTypeIndex);
-        switch (iconType) {
-        case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
-            String packageName = c.getString(iconPackageIndex);
-            String resourceName = c.getString(iconResourceIndex);
-            PackageManager packageManager = context.getPackageManager();
-            try {
-                Resources appResources = packageManager.getResourcesForApplication(packageName);
-                final int id = appResources.getIdentifier(resourceName, null, null);
-                liveFolderInfo.icon = Utilities.createIconBitmap(
-                        mIconCache.getFullResIcon(appResources, id), context);
-            } catch (Exception e) {
-                Resources resources = context.getResources();
-                liveFolderInfo.icon = Utilities.createIconBitmap(
-                        mIconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder),
-                        context);
-            }
-            liveFolderInfo.iconResource = new Intent.ShortcutIconResource();
-            liveFolderInfo.iconResource.packageName = packageName;
-            liveFolderInfo.iconResource.resourceName = resourceName;
-            break;
-        default:
-            Resources resources = context.getResources();
-            liveFolderInfo.icon = Utilities.createIconBitmap(
-                    mIconCache.getFullResIcon(resources, R.drawable.ic_launcher_folder),
-                    context);
-        }
-    }
-
     void updateSavedIcon(Context context, ShortcutInfo info, Cursor c, int iconIndex) {
         // If apps can't be on SD, don't even bother.
         if (!mAppsCanBeOnExternalStorage) {
@@ -1735,44 +1628,18 @@
     }
 
     /**
-     * Return an existing UserFolderInfo object if we have encountered this ID previously,
+     * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    private static UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) {
+    private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
         // See if a placeholder was created for us already
         FolderInfo folderInfo = folders.get(id);
-        if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) {
+        if (folderInfo == null) {
             // No placeholder -- create a new instance
-            folderInfo = new UserFolderInfo();
+            folderInfo = new FolderInfo();
             folders.put(id, folderInfo);
         }
-        return (UserFolderInfo) folderInfo;
-    }
-
-    /**
-     * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a
-     * new one.
-     */
-    private static LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) {
-        // See if a placeholder was created for us already
-        FolderInfo folderInfo = folders.get(id);
-        if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) {
-            // No placeholder -- create a new instance
-            folderInfo = new LiveFolderInfo();
-            folders.put(id, folderInfo);
-        }
-        return (LiveFolderInfo) folderInfo;
-    }
-
-    private static String getLabel(PackageManager manager, ActivityInfo activityInfo) {
-        String label = activityInfo.loadLabel(manager).toString();
-        if (label == null) {
-            label = manager.getApplicationLabel(activityInfo.applicationInfo).toString();
-            if (label == null) {
-                label = activityInfo.name;
-            }
-        }
-        return label;
+        return folderInfo;
     }
 
     private static final Collator sCollator = Collator.getInstance();
@@ -1790,6 +1657,48 @@
             return 0;
         }
     };
+    public static final Comparator<AppWidgetProviderInfo> WIDGET_NAME_COMPARATOR
+            = new Comparator<AppWidgetProviderInfo>() {
+        public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
+            return sCollator.compare(a.label.toString(), b.label.toString());
+        }
+    };
+    public static class ShortcutNameComparator implements Comparator<ResolveInfo> {
+        private PackageManager mPackageManager;
+        private HashMap<Object, String> mLabelCache;
+        ShortcutNameComparator(PackageManager pm) {
+            mPackageManager = pm;
+            mLabelCache = new HashMap<Object, String>();
+        }
+        public final int compare(ResolveInfo a, ResolveInfo b) {
+            String labelA, labelB;
+            if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
+            else labelA = a.loadLabel(mPackageManager).toString();
+            if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
+            else labelB = b.loadLabel(mPackageManager).toString();
+            return sCollator.compare(labelA, labelB);
+        }
+    };
+    public static class WidgetAndShortcutNameComparator implements Comparator<Object> {
+        private PackageManager mPackageManager;
+        private HashMap<Object, String> mLabelCache;
+        WidgetAndShortcutNameComparator(PackageManager pm) {
+            mPackageManager = pm;
+            mLabelCache = new HashMap<Object, String>();
+        }
+        public final int compare(Object a, Object b) {
+            String labelA, labelB;
+            if (mLabelCache.containsKey(a)) labelA = mLabelCache.get(a);
+            else labelA = (a instanceof AppWidgetProviderInfo) ?
+                    ((AppWidgetProviderInfo) a).label :
+                    ((ResolveInfo) a).loadLabel(mPackageManager).toString();
+            if (mLabelCache.containsKey(b)) labelB = mLabelCache.get(b);
+            else labelB = (b instanceof AppWidgetProviderInfo) ?
+                    ((AppWidgetProviderInfo) b).label :
+                    ((ResolveInfo) b).loadLabel(mPackageManager).toString();
+            return sCollator.compare(labelA, labelB);
+        }
+    };
 
     public void dumpState() {
         Log.d(TAG, "mCallbacks=" + mCallbacks);
@@ -1797,7 +1706,6 @@
         ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
         ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
         ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
-        Log.d(TAG, "mItems size=" + mItems.size());
         if (mLoaderTask != null) {
             mLoaderTask.dumpState();
         } else {
diff --git a/src/com/android/launcher2/LauncherSettings.java b/src/com/android/launcher2/LauncherSettings.java
index 9c685ce..c378405 100644
--- a/src/com/android/launcher2/LauncherSettings.java
+++ b/src/com/android/launcher2/LauncherSettings.java
@@ -16,8 +16,8 @@
 
 package com.android.launcher2;
 
-import android.provider.BaseColumns;
 import android.net.Uri;
+import android.provider.BaseColumns;
 
 /**
  * Settings related utilities.
@@ -169,11 +169,15 @@
         /**
          * The favorite is a user created folder
          */
-        static final int ITEM_TYPE_USER_FOLDER = 2;
+        static final int ITEM_TYPE_FOLDER = 2;
 
         /**
-         * The favorite is a live folder
-         */
+        * The favorite is a live folder
+        *
+        * Note: live folders can no longer be added to Launcher, and any live folders which
+        * exist within the launcher database will be ignored when loading.  That said, these
+        * entries in the database may still exist, and are not automatically stripped.
+        */
         static final int ITEM_TYPE_LIVE_FOLDER = 3;
 
         /**
diff --git a/src/com/android/launcher2/LiveFolder.java b/src/com/android/launcher2/LiveFolder.java
deleted file mode 100644
index 07a295f..0000000
--- a/src/com/android/launcher2/LiveFolder.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.Intent;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AdapterView;
-import android.net.Uri;
-import android.provider.LiveFolders;
-import android.os.AsyncTask;
-import android.database.Cursor;
-
-import java.lang.ref.WeakReference;
-
-import com.android.launcher.R;
-
-public class LiveFolder extends Folder {
-    private AsyncTask<LiveFolderInfo,Void,Cursor> mLoadingTask;
-
-    public LiveFolder(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    static LiveFolder fromXml(Context context, FolderInfo folderInfo) {
-        final int layout = isDisplayModeList(folderInfo) ?
-                R.layout.live_folder_list : R.layout.live_folder_grid;
-        return (LiveFolder) LayoutInflater.from(context).inflate(layout, null);
-    }
-
-    private static boolean isDisplayModeList(FolderInfo folderInfo) {
-        return ((LiveFolderInfo) folderInfo).displayMode ==
-                LiveFolders.DISPLAY_MODE_LIST;
-    }
-
-    @Override
-    public void onItemClick(AdapterView parent, View v, int position, long id) {
-        LiveFolderAdapter.ViewHolder holder = (LiveFolderAdapter.ViewHolder) v.getTag();
-
-        if (holder.useBaseIntent) {
-            final Intent baseIntent = ((LiveFolderInfo) mInfo).baseIntent;
-            if (baseIntent != null) {
-                final Intent intent = new Intent(baseIntent);
-                Uri uri = baseIntent.getData();
-                uri = uri.buildUpon().appendPath(Long.toString(holder.id)).build();
-                intent.setData(uri);
-                mLauncher.startActivitySafely(intent, "(position=" + position + ", id=" + id + ")");
-            }
-        } else if (holder.intent != null) {
-            mLauncher.startActivitySafely(holder.intent,
-                    "(position=" + position + ", id=" + id + ")");
-        }
-    }
-
-    @Override
-    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-        return false;
-    }
-
-    void bind(FolderInfo info) {
-        super.bind(info);
-        if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
-            mLoadingTask.cancel(true);
-        }
-        mLoadingTask = new FolderLoadingTask(this).execute((LiveFolderInfo) info);
-    }
-
-    @Override
-    void onOpen() {
-        super.onOpen();
-        requestFocus();
-    }
-
-    @Override
-    void onClose() {
-        super.onClose();
-        if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
-            mLoadingTask.cancel(true);
-        }
-
-        // The adapter can be null if onClose() is called before FolderLoadingTask
-        // is done querying the provider
-        final LiveFolderAdapter adapter = (LiveFolderAdapter) mContent.getAdapter();
-        if (adapter != null) {
-            adapter.cleanup();
-        }
-    }
-
-    static class FolderLoadingTask extends AsyncTask<LiveFolderInfo, Void, Cursor> {
-        private final WeakReference<LiveFolder> mFolder;
-        private LiveFolderInfo mInfo;
-
-        FolderLoadingTask(LiveFolder folder) {
-            mFolder = new WeakReference<LiveFolder>(folder);
-        }
-
-        protected Cursor doInBackground(LiveFolderInfo... params) {
-            final LiveFolder folder = mFolder.get();
-            if (folder != null) {
-                mInfo = params[0];
-                return LiveFolderAdapter.query(folder.mLauncher, mInfo);
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Cursor cursor) {
-            if (!isCancelled()) {
-                if (cursor != null) {
-                    final LiveFolder folder = mFolder.get();
-                    if (folder != null) {
-                        final Launcher launcher = folder.mLauncher;
-                        folder.setContentAdapter(new LiveFolderAdapter(launcher, mInfo, cursor));
-                    }
-                }
-            } else if (cursor != null) {
-                cursor.close();
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher2/LiveFolderAdapter.java b/src/com/android/launcher2/LiveFolderAdapter.java
deleted file mode 100644
index fb9c6a3..0000000
--- a/src/com/android/launcher2/LiveFolderAdapter.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.widget.CursorAdapter;
-import android.widget.TextView;
-import android.widget.ImageView;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.content.pm.PackageManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.database.Cursor;
-import android.provider.LiveFolders;
-import android.graphics.drawable.Drawable;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.lang.ref.SoftReference;
-
-import com.android.launcher.R;
-
-class LiveFolderAdapter extends CursorAdapter {
-    private boolean mIsList;
-    private LayoutInflater mInflater;
-
-    private final HashMap<String, Drawable> mIcons = new HashMap<String, Drawable>();
-    private final HashMap<Long, SoftReference<Drawable>> mCustomIcons =
-            new HashMap<Long, SoftReference<Drawable>>();
-    private final Launcher mLauncher;
-
-    LiveFolderAdapter(Launcher launcher, LiveFolderInfo info, Cursor cursor) {
-        super(launcher, cursor, true);
-        mIsList = info.displayMode == LiveFolders.DISPLAY_MODE_LIST;
-        mInflater = LayoutInflater.from(launcher);
-        mLauncher = launcher;
-
-        mLauncher.startManagingCursor(getCursor());
-    }
-
-    static Cursor query(Context context, LiveFolderInfo info) {
-        return context.getContentResolver().query(info.uri, null, null,
-                null, LiveFolders.NAME + " ASC");
-    }
-
-    public View newView(Context context, Cursor cursor, ViewGroup parent) {
-        View view;
-        final ViewHolder holder = new ViewHolder();
-
-        if (!mIsList) {
-            view = mInflater.inflate(R.layout.application_boxed, parent, false);
-        } else {
-            view = mInflater.inflate(R.layout.application_list, parent, false);
-            holder.description = (TextView) view.findViewById(R.id.description);
-            holder.icon = (ImageView) view.findViewById(R.id.icon);
-        }
-
-        holder.name = (TextView) view.findViewById(R.id.name);
-
-        holder.idIndex = cursor.getColumnIndexOrThrow(LiveFolders._ID);
-        holder.nameIndex = cursor.getColumnIndexOrThrow(LiveFolders.NAME);
-        holder.descriptionIndex = cursor.getColumnIndex(LiveFolders.DESCRIPTION);
-        holder.intentIndex = cursor.getColumnIndex(LiveFolders.INTENT);
-        holder.iconBitmapIndex = cursor.getColumnIndex(LiveFolders.ICON_BITMAP);
-        holder.iconResourceIndex = cursor.getColumnIndex(LiveFolders.ICON_RESOURCE);
-        holder.iconPackageIndex = cursor.getColumnIndex(LiveFolders.ICON_PACKAGE);
-
-        view.setTag(holder);
-
-        return view;
-    }
-
-    public void bindView(View view, Context context, Cursor cursor) {
-        final ViewHolder holder = (ViewHolder) view.getTag();
-
-        holder.id = cursor.getLong(holder.idIndex);
-        final Drawable icon = loadIcon(context, cursor, holder);
-
-        holder.name.setText(cursor.getString(holder.nameIndex));
-
-        if (!mIsList) {
-            holder.name.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null);
-        } else {
-            final boolean hasIcon = icon != null;
-            holder.icon.setVisibility(hasIcon ? View.VISIBLE : View.GONE);
-            if (hasIcon) holder.icon.setImageDrawable(icon);
-
-            if (holder.descriptionIndex != -1) {
-                final String description = cursor.getString(holder.descriptionIndex);
-                if (description != null) {
-                    holder.description.setText(description);
-                    holder.description.setVisibility(View.VISIBLE);
-                } else {
-                    holder.description.setVisibility(View.GONE);                    
-                }
-            } else {
-                holder.description.setVisibility(View.GONE);                
-            }
-        }
-
-        if (holder.intentIndex != -1) {
-            try {
-                holder.intent = Intent.parseUri(cursor.getString(holder.intentIndex), 0);
-            } catch (URISyntaxException e) {
-                // Ignore
-            }
-        } else {
-            holder.useBaseIntent = true;
-        }
-    }
-
-    private Drawable loadIcon(Context context, Cursor cursor, ViewHolder holder) {
-        Drawable icon = null;
-        byte[] data = null;
-
-        if (holder.iconBitmapIndex != -1) {
-            data = cursor.getBlob(holder.iconBitmapIndex);
-        }
-
-        if (data != null) {
-            final SoftReference<Drawable> reference = mCustomIcons.get(holder.id);
-            if (reference != null) {
-                icon = reference.get();
-            }
-
-            if (icon == null) {
-                final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
-                final Bitmap resampled = Utilities.resampleIconBitmap(bitmap, mContext);
-                if (bitmap != resampled) {
-                    // If we got back a different object, we don't need the old one any more.
-                    bitmap.recycle();
-                }
-                icon = new FastBitmapDrawable(resampled);
-                mCustomIcons.put(holder.id, new SoftReference<Drawable>(icon));
-            }
-        } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) {
-            final String resource = cursor.getString(holder.iconResourceIndex);
-            icon = mIcons.get(resource);
-            if (icon == null) {
-                try {
-                    final PackageManager packageManager = context.getPackageManager();
-                    Resources resources = packageManager.getResourcesForApplication(
-                            cursor.getString(holder.iconPackageIndex));
-                    final int id = resources.getIdentifier(resource,
-                            null, null);
-                    icon = new FastBitmapDrawable(
-                            Utilities.createIconBitmap(resources.getDrawable(id), mContext));
-                    mIcons.put(resource, icon);
-                } catch (Exception e) {
-                    // Ignore
-                }
-            }
-        }
-
-        return icon;
-    }
-
-    void cleanup() {
-        for (Drawable icon : mIcons.values()) {
-            icon.setCallback(null);
-        }
-        mIcons.clear();
-
-        for (SoftReference<Drawable> icon : mCustomIcons.values()) {
-            final Drawable drawable = icon.get();
-            if (drawable != null) {
-                drawable.setCallback(null);
-            }
-        }
-        mCustomIcons.clear();
-
-        final Cursor cursor = getCursor();
-        if (cursor != null) {
-            try {
-                cursor.close();
-            } finally {
-                mLauncher.stopManagingCursor(cursor);
-            }
-        }
-    }
-
-    static class ViewHolder {
-        TextView name;
-        TextView description;
-        ImageView icon;
-
-        Intent intent;
-        long id;
-        boolean useBaseIntent;
-
-        int idIndex;
-        int nameIndex;
-        int descriptionIndex = -1;
-        int intentIndex = -1;
-        int iconBitmapIndex = -1;
-        int iconResourceIndex = -1;
-        int iconPackageIndex = -1;
-    }
-}
diff --git a/src/com/android/launcher2/LiveFolderIcon.java b/src/com/android/launcher2/LiveFolderIcon.java
deleted file mode 100644
index 5b73a59..0000000
--- a/src/com/android/launcher2/LiveFolderIcon.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.graphics.Bitmap;
-
-import com.android.launcher.R;
-
-public class LiveFolderIcon extends FolderIcon {
-    public LiveFolderIcon(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public LiveFolderIcon(Context context) {
-        super(context);
-    }
-
-    static LiveFolderIcon fromXml(int resId, Launcher launcher, ViewGroup group,
-            LiveFolderInfo folderInfo) {
-
-        LiveFolderIcon icon = (LiveFolderIcon)
-                LayoutInflater.from(launcher).inflate(resId, group, false);
-
-        final Resources resources = launcher.getResources();
-        Bitmap b = folderInfo.icon;
-        if (b == null) {
-            b = Utilities.createIconBitmap(resources.getDrawable(R.drawable.ic_launcher_folder),
-                    launcher);
-        }
-        icon.setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(b), null, null);
-        icon.setText(folderInfo.title);
-        icon.setTag(folderInfo);
-        icon.setOnClickListener(launcher);
-        
-        return icon;
-    }
-
-    @Override
-    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-        return false;
-    }
-
-    @Override
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    @Override
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    @Override
-    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    @Override
-    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-}
diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java
deleted file mode 100644
index 74b0217..0000000
--- a/src/com/android/launcher2/LiveFolderInfo.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ContentValues;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.net.Uri;
-
-class LiveFolderInfo extends FolderInfo {
-
-    /**
-     * The base intent, if it exists.
-     */
-    Intent baseIntent;
-
-    /**
-     * The live folder's content uri.
-     */
-    Uri uri;
-
-    /**
-     * The live folder's display type.
-     */
-    int displayMode;
-
-    /**
-     * The live folder icon.
-     */
-    Bitmap icon;
-
-    /**
-     * Reference to the live folder icon as an application's resource.
-     */
-    Intent.ShortcutIconResource iconResource;
-
-    LiveFolderInfo() {
-        itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER;
-    }
-
-    @Override
-    void onAddToDatabase(ContentValues values) {
-        super.onAddToDatabase(values);
-        values.put(LauncherSettings.Favorites.TITLE, title.toString());
-        values.put(LauncherSettings.Favorites.URI, uri.toString());
-        if (baseIntent != null) {
-            values.put(LauncherSettings.Favorites.INTENT, baseIntent.toUri(0));
-        }
-        values.put(LauncherSettings.Favorites.ICON_TYPE, LauncherSettings.Favorites.ICON_TYPE_RESOURCE);
-        values.put(LauncherSettings.Favorites.DISPLAY_MODE, displayMode);
-        if (iconResource != null) {
-            values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName);
-            values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName);
-        }
-    }
-}
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index e7ecb99..1180106 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -29,6 +29,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.ActionMode;
 import android.view.InputDevice;
 import android.view.KeyEvent;
@@ -50,6 +51,7 @@
  */
 public abstract class PagedView extends ViewGroup {
     private static final String TAG = "PagedView";
+    private static final boolean DEBUG = false;
     protected static final int INVALID_PAGE = -1;
 
     // the min drag distance for a fling to register, to prevent random page shifts
@@ -110,6 +112,7 @@
     protected int mPageLayoutPaddingRight;
     protected int mPageLayoutWidthGap;
     protected int mPageLayoutHeightGap;
+    protected int mPageLayoutMaxHeight;
     protected int mCellCountX;
     protected int mCellCountY;
     protected boolean mCenterPagesVertically;
@@ -189,6 +192,8 @@
                 R.styleable.PagedView_pageLayoutWidthGap, -1);
         mPageLayoutHeightGap = a.getDimensionPixelSize(
                 R.styleable.PagedView_pageLayoutHeightGap, -1);
+        mPageLayoutMaxHeight = a.getDimensionPixelSize(
+                R.styleable.PagedView_pageLayoutMaxHeight, -1);
         a.recycle();
 
         setHapticFeedbackEnabled(false);
@@ -289,6 +294,10 @@
         mIsPageMoving = false;
     }
 
+    protected boolean isPageMoving() {
+        return mIsPageMoving;
+    }
+
     // a method that subclasses can override to add behavior
     protected void onPageBeginMoving() {
     }
@@ -384,8 +393,13 @@
 
         final int verticalPadding = mPaddingTop + mPaddingBottom;
 
+        if (mPageLayoutMaxHeight != -1) {
+            heightSize = Math.min(mPageLayoutMaxHeight, heightSize);
+        }
+
         // The children are given the same width and height as the workspace
         // unless they were set to WRAP_CONTENT
+        if (DEBUG) Log.d(TAG, "PagedView.onMeasure(): " + widthSize + ", " + heightSize);
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             // disallowing padding in paged view (just pass 0)
@@ -413,6 +427,8 @@
 
             child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
             maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
+            if (DEBUG) Log.d(TAG, "\tmeasure-child" + i + ": " + child.getMeasuredWidth() + ", "
+                    + child.getMeasuredHeight());
         }
 
         if (heightMode == MeasureSpec.AT_MOST) {
@@ -467,6 +483,7 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (DEBUG) Log.d(TAG, "PagedView.onLayout()");
         if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
             setHorizontalScrollBarEnabled(false);
             int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
@@ -480,6 +497,8 @@
         final int childCount = getChildCount();
         int childLeft = 0;
         if (childCount > 0) {
+            if (DEBUG) Log.d(TAG, "getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+                    + getChildWidth(0));
             childLeft = getRelativeChildOffset(0);
         }
 
@@ -493,6 +512,7 @@
                     childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
                 }
 
+                if (DEBUG) Log.d(TAG, "\tlayout-child" + i + ": " + childLeft + ", " + childTop);
                 child.layout(childLeft, childTop,
                         childLeft + child.getMeasuredWidth(), childTop + childHeight);
                 childLeft += childWidth + mPageSpacing;
@@ -511,7 +531,8 @@
     protected void updateAdjacentPagesAlpha() {
         if (mFadeInAdjacentScreens) {
             if (mDirtyPageAlpha || (mTouchState == TOUCH_STATE_SCROLLING) || !mScroller.isFinished()) {
-                int halfScreenSize = getMeasuredWidth() / 2;
+                int screenWidth = getMeasuredWidth();
+                int halfScreenSize = screenWidth / 2;
                 int screenCenter = mScrollX + halfScreenSize;
                 final int childCount = getChildCount();
                 for (int i = 0; i < childCount; ++i) {
@@ -524,7 +545,7 @@
                     // we should just assume full page width (and calculate the offset according to
                     // that).
                     if (childWidth <= 0) {
-                        childWidth = getMeasuredWidth();
+                        childWidth = screenWidth;
                         childCenter = (i * childWidth) + (childWidth / 2);
                     }
 
@@ -982,6 +1003,7 @@
                     mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                     if (!mDeferScrollUpdate) {
                         scrollBy((int) deltaX, 0);
+                        if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
                     } else {
                         invalidate();
                     }
@@ -1155,7 +1177,7 @@
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
         int page = indexOfChild(child);
-        if (page >= 0 && !isInTouchMode()) {
+        if (page >= 0 && page != getCurrentPage() && !isInTouchMode()) {
             snapToPage(page);
         }
     }
@@ -1177,9 +1199,16 @@
     protected void setMinimumWidthOverride(int minimumWidth) {
         mMinimumWidth = minimumWidth;
     }
+    protected void resetMinimumWidthOverride() {
+        mMinimumWidth = 0;
+    }
 
     protected int getChildWidth(int index) {
-        return Math.max(mMinimumWidth, getChildAt(index).getMeasuredWidth());
+        // This functions are called enough times that it actually makes a difference in the
+        // profiler -- so just inline the max() here
+        final int measuredWidth = getChildAt(index).getMeasuredWidth();
+        final int minWidth = mMinimumWidth;
+        return (minWidth > measuredWidth) ? minWidth : measuredWidth;
     }
 
     protected int getRelativeChildOffset(int index) {
@@ -1198,7 +1227,12 @@
     }
 
     protected int getScaledMeasuredWidth(View child) {
-        return (int) (Math.max(mMinimumWidth, child.getMeasuredWidth()) * mLayoutScale + 0.5f);
+        // This functions are called enough times that it actually makes a difference in the
+        // profiler -- so just inline the max() here
+        final int measuredWidth = child.getMeasuredWidth();
+        final int minWidth = mMinimumWidth;
+        final int maxWidth = (minWidth > measuredWidth) ? minWidth : measuredWidth;
+        return (int) (maxWidth * mLayoutScale + 0.5f);
     }
 
     int getPageNearestToCenterOfScreen() {
@@ -1248,6 +1282,9 @@
         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
         int halfScreenSize = getMeasuredWidth() / 2;
 
+        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+        if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
+                + getMeasuredWidth() + ", " + getChildWidth(whichPage));
         final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         int delta = newX - mUnboundedScrollX;
         int duration = 0;
@@ -1285,6 +1322,9 @@
     protected void snapToPage(int whichPage, int duration) {
         whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1));
 
+        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
+        if (DEBUG) Log.d(TAG, "snapToPage.getRelativeChildOffset(): " + getMeasuredWidth() + ", "
+                + getChildWidth(whichPage));
         int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
         final int sX = mUnboundedScrollX;
         final int delta = newX - sX;
@@ -1396,6 +1436,8 @@
             if (page < count) {
                 int lowerPageBound = getAssociatedLowerPageBound(page);
                 int upperPageBound = getAssociatedUpperPageBound(page);
+                if (DEBUG) Log.d(TAG, "loadAssociatedPages: " + lowerPageBound + "/"
+                        + upperPageBound);
                 for (int i = 0; i < count; ++i) {
                     Page layout = (Page) getChildAt(i);
                     final int childCount = layout.getPageChildCount();
diff --git a/src/com/android/launcher2/PagedViewCellLayout.java b/src/com/android/launcher2/PagedViewCellLayout.java
index 53657e5..54bdec4 100644
--- a/src/com/android/launcher2/PagedViewCellLayout.java
+++ b/src/com/android/launcher2/PagedViewCellLayout.java
@@ -17,12 +17,15 @@
 package com.android.launcher2;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 
+import com.android.launcher.R;
+
 /**
  * An abstraction of the original CellLayout which supports laying out items
  * which span multiple cells into a grid-like layout.  Also supports dimming
@@ -37,7 +40,6 @@
     private int mCellHeight;
     private int mWidthGap;
     private int mHeightGap;
-    private static int sDefaultCellDimensions = 96;
     protected PagedViewCellLayoutChildren mChildren;
     private PagedViewCellLayoutChildren mHolographicChildren;
     private boolean mAllowHardwareLayerCreation = false;
@@ -57,7 +59,9 @@
         setAlwaysDrawnWithCacheEnabled(false);
 
         // setup default cell parameters
-        mCellWidth = mCellHeight = sDefaultCellDimensions;
+        Resources resources = context.getResources();
+        mCellWidth = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_width);
+        mCellHeight = resources.getDimensionPixelSize(R.dimen.apps_customize_cell_height);
         mCellCountX = LauncherModel.getCellCountX();
         mCellCountY = LauncherModel.getCellCountY();
         mWidthGap = mHeightGap = -1;
@@ -125,7 +129,7 @@
     }
 
     public boolean addViewToCellLayout(View child, int index, int childId,
-            PagedViewCellLayout.LayoutParams params) {
+            PagedViewCellLayout.LayoutParams params, boolean createHolographicOutlines) {
         final PagedViewCellLayout.LayoutParams lp = params;
 
         // Generate an id for each view, this assumes we have at most 256x256 cells
@@ -145,7 +149,10 @@
                 if (mAllowHardwareLayerCreation) {
                     pagedViewIcon.disableCache();
                 }
-                mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
+                if (createHolographicOutlines) {
+                    mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(),
+                            index, lp);
+                }
             }
             return true;
         }
@@ -180,6 +187,14 @@
         return mChildren.indexOfChild(v);
     }
 
+    public int getCellCountX() {
+        return mCellCountX;
+    }
+
+    public int getCellCountY() {
+        return mCellCountY;
+    }
+
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // TODO: currently ignoring padding
 
@@ -244,12 +259,23 @@
     }
 
     int getContentWidth() {
-        // Return the distance from the left edge of the content of the leftmost icon to
-        // the right edge of the content of the rightmost icon
+        if (LauncherApplication.isScreenLarge()) {
+            // Return the distance from the left edge of the content of the leftmost icon to
+            // the right edge of the content of the rightmost icon
 
-        // icons are centered within cells, find out how much offset that accounts for
-        int iconHorizontalOffset = (mCellWidth - Utilities.getIconContentSize());
-        return mCellCountX * mCellWidth + (mCellCountX - 1) * mWidthGap - iconHorizontalOffset;
+            // icons are centered within cells, find out how much padding that accounts for
+            return getWidthBeforeFirstLayout() - (mCellWidth - Utilities.getIconContentSize());
+        } else {
+            return getWidthBeforeFirstLayout() + mPaddingLeft + mPaddingRight;
+        }
+    }
+
+    int getContentHeight() {
+        return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
+    }
+
+    int getWidthBeforeFirstLayout() {
+        return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
     }
 
     @Override
@@ -257,7 +283,12 @@
         int count = getChildCount();
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
-            child.layout(0, 0, r - l, b - t);
+            if (LauncherApplication.isScreenLarge()) {
+                child.layout(0, 0, r - l, b - t);
+            } else {
+                child.layout(mPaddingLeft, mPaddingTop, getMeasuredWidth() - mPaddingRight,
+                        getMeasuredHeight() - mPaddingBottom);
+            }
         }
     }
 
@@ -446,8 +477,13 @@
             height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
                     topMargin - bottomMargin;
 
-            x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
-            y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+            if (LauncherApplication.isScreenLarge()) {
+                x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
+                y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
+            } else {
+                x = myCellX * (cellWidth + widthGap) + leftMargin;
+                y = myCellY * (cellHeight + heightGap) + topMargin;
+            }
         }
 
         public Object getTag() {
diff --git a/src/com/android/launcher2/PagedViewExtendedLayout.java b/src/com/android/launcher2/PagedViewExtendedLayout.java
index e54d261..94890d8 100644
--- a/src/com/android/launcher2/PagedViewExtendedLayout.java
+++ b/src/com/android/launcher2/PagedViewExtendedLayout.java
@@ -23,10 +23,11 @@
 import android.widget.LinearLayout;
 
 /**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ * The linear layout used strictly for the widget/wallpaper tab of the customization tray.
+ * To be deprecated.
  */
 public class PagedViewExtendedLayout extends LinearLayout implements Page {
-    static final String TAG = "PagedViewWidgetLayout";
+    static final String TAG = "PagedViewExtendedLayout";
 
     public PagedViewExtendedLayout(Context context) {
         this(context, null);
@@ -40,6 +41,22 @@
         super(context, attrs, defStyle);
     }
 
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (LauncherApplication.isScreenLarge()) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        } else {
+            // PagedView currently has issues with different-sized pages since it calculates the
+            // offset of each page to scroll to before it updates the actual size of each page
+            // (which canchange depending on the content if the contains aren't a fixed size).
+            // We work around this by having a minimum size on each widget page).
+            int widthSpecSize = Math.max(getSuggestedMinimumWidth(),
+                    MeasureSpec.getSize(widthMeasureSpec));
+            int widthSpecMode = MeasureSpec.AT_MOST;
+            super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode),
+                    heightMeasureSpec);
+        }
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // We eat up the touch events here, since the PagedView (which uses the same swiping
@@ -94,4 +111,11 @@
     public int indexOfChildOnPage(View v) {
         return indexOfChild(v);
     }
+
+    public static class LayoutParams extends LinearLayout.LayoutParams {
+        public LayoutParams() {
+            super(LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.MATCH_PARENT);
+        }
+    }
 }
diff --git a/src/com/android/launcher2/PagedViewGridLayout.java b/src/com/android/launcher2/PagedViewGridLayout.java
new file mode 100644
index 0000000..cedf71c
--- /dev/null
+++ b/src/com/android/launcher2/PagedViewGridLayout.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher2;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+/**
+ * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
+ */
+public class PagedViewGridLayout extends FrameLayout implements Page {
+    static final String TAG = "PagedViewGridLayout";
+
+    private int mCellCountX;
+    private int mCellCountY;
+
+    public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
+        super(context, null, 0);
+        mCellCountX = cellCountX;
+        mCellCountY = cellCountY;
+    }
+
+    int getCellCountX() {
+        return mCellCountX;
+    }
+    int getCellCountY() {
+        return mCellCountY;
+    }
+
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // PagedView currently has issues with different-sized pages since it calculates the
+        // offset of each page to scroll to before it updates the actual size of each page
+        // (which can change depending on the content if the contents aren't a fixed size).
+        // We work around this by having a minimum size on each widget page).
+        int widthSpecSize = Math.max(getSuggestedMinimumWidth(),
+                MeasureSpec.getSize(widthMeasureSpec));
+        int widthSpecMode = MeasureSpec.AT_MOST;
+        super.onMeasure(MeasureSpec.makeMeasureSpec(widthSpecSize, widthSpecMode),
+                heightMeasureSpec);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // We eat up the touch events here, since the PagedView (which uses the same swiping
+        // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
+        // the user is scrolling between pages.  This means that if the pages themselves don't
+        // handle touch events, it gets forwarded up to PagedView itself, and it's own
+        // onTouchEvent() handling will prevent further intercept touch events from being called
+        // (it's the same view in that case).  This is not ideal, but to prevent more changes,
+        // we just always mark the touch event as handled.
+        return super.onTouchEvent(event) || true;
+    }
+
+    @Override
+    protected boolean onSetAlpha(int alpha) {
+        return true;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        setChildrenAlpha(alpha);
+        super.setAlpha(alpha);
+    }
+
+    private void setChildrenAlpha(float alpha) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            getChildAt(i).setAlpha(alpha);
+        }
+    }
+
+    @Override
+    public void removeAllViewsOnPage() {
+        removeAllViews();
+    }
+
+    @Override
+    public void removeViewOnPageAt(int index) {
+        removeViewAt(index);
+    }
+
+    @Override
+    public int getPageChildCount() {
+        return getChildCount();
+    }
+
+    @Override
+    public View getChildOnPageAt(int i) {
+        return getChildAt(i);
+    }
+
+    @Override
+    public int indexOfChildOnPage(View v) {
+        return indexOfChild(v);
+    }
+
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+    }
+}
diff --git a/src/com/android/launcher2/PagedViewIcon.java b/src/com/android/launcher2/PagedViewIcon.java
index bde6559..e23f1c6 100644
--- a/src/com/android/launcher2/PagedViewIcon.java
+++ b/src/com/android/launcher2/PagedViewIcon.java
@@ -16,9 +16,8 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-
 import android.animation.ObjectAnimator;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -31,9 +30,11 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
 import android.widget.Checkable;
-import android.widget.TextView;
 
+import com.android.launcher.R;
 
 
 /**
@@ -121,15 +122,15 @@
 
         // Set up fade in/out constants
         final Resources r = context.getResources();
-        final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+        final int alpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha);
         if (alpha > 0) {
-            mCheckedAlpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha) / 256.0f;
-            mCheckedFadeInDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeInTime);
-            mCheckedFadeOutDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeOutTime);
+            mCheckedAlpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha) / 256.0f;
+            mCheckedFadeInDuration =
+                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeInDuration);
+            mCheckedFadeOutDuration =
+                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeOutDuration);
         }
 
-        setFocusable(true);
-        setBackgroundDrawable(null);
         mHolographicOutlineView = new HolographicPagedViewIcon(context, this);
     }
 
@@ -171,8 +172,8 @@
 
     public void applyFromResolveInfo(ResolveInfo info, PackageManager packageManager,
             PagedViewIconCache cache, IconCache modelIconCache, boolean createHolographicOutlines) {
-        mIcon = Utilities.createIconBitmap(
-                modelIconCache.getFullResIcon(info, packageManager), mContext);
+        ComponentName cn = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
+        mIcon = modelIconCache.getIcon(cn, info);
         setCompoundDrawablesWithIntrinsicBounds(null, new FastBitmapDrawable(mIcon), null, null);
         setText(info.loadLabel(packageManager));
         setTag(info);
@@ -217,7 +218,8 @@
 
         // draw any blended overlays
         if (mCheckedOutline == null) {
-            if (mHolographicOutline != null && mHolographicAlpha > 0) {
+            if (canvas.isHardwareAccelerated() && mHolographicOutline != null
+                    && mHolographicAlpha > 0) {
                 mPaint.setAlpha(mHolographicAlpha);
                 overlay = mHolographicOutline;
             }
@@ -245,6 +247,18 @@
     }
 
     @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+                || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return FocusHelper.handlePagedViewIconKeyEvent(this, keyCode, event)
+                || super.onKeyUp(keyCode, event);
+    }
+
+    @Override
     public boolean isChecked() {
         return mIsChecked;
     }
diff --git a/src/com/android/launcher2/PagedViewWidget.java b/src/com/android/launcher2/PagedViewWidget.java
index 72f928b..2ffa398 100644
--- a/src/com/android/launcher2/PagedViewWidget.java
+++ b/src/com/android/launcher2/PagedViewWidget.java
@@ -36,6 +36,7 @@
 import android.os.HandlerThread;
 import android.os.Message;
 import android.util.AttributeSet;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.Checkable;
@@ -63,6 +64,7 @@
 
     private PagedViewIconCache.Key mIconCacheKey;
     private PagedViewIconCache mIconCache;
+    private String mDimensionsFormatString;
 
     private int mAlpha = 255;
     private int mHolographicAlpha;
@@ -153,14 +155,16 @@
 
         // Set up fade in/out constants
         final Resources r = context.getResources();
-        final int alpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha);
+        final int alpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha);
         if (alpha > 0) {
-            mCheckedAlpha = r.getInteger(R.integer.icon_allAppsCustomizeFadeAlpha) / 256.0f;
-            mCheckedFadeInDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeInTime);
-            mCheckedFadeOutDuration = r.getInteger(R.integer.icon_allAppsCustomizeFadeOutTime);
+            mCheckedAlpha = r.getInteger(R.integer.config_dragAppsCustomizeIconFadeAlpha) / 256.0f;
+            mCheckedFadeInDuration =
+                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeInDuration);
+            mCheckedFadeOutDuration =
+                r.getInteger(R.integer.config_dragAppsCustomizeIconFadeOutDuration);
         }
+        mDimensionsFormatString = r.getString(R.string.widget_dims_format);
 
-        setFocusable(true);
         setWillNotDraw(false);
         setClipToPadding(false);
     }
@@ -178,14 +182,16 @@
             FastBitmapDrawable preview, int maxWidth, int[] cellSpan,
             PagedViewIconCache cache, boolean createHolographicOutline) {
         final ImageView image = (ImageView) findViewById(R.id.widget_preview);
-        image.setMaxWidth(maxWidth);
+        if (maxWidth > -1) {
+            image.setMaxWidth(maxWidth);
+        }
         image.setImageDrawable(preview);
         mPreviewImageView = image;
         final TextView name = (TextView) findViewById(R.id.widget_name);
         name.setText(info.label);
         name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
         final TextView dims = (TextView) findViewById(R.id.widget_dims);
-        dims.setText(mContext.getString(R.string.widget_dims_format, cellSpan[0], cellSpan[1]));
+        dims.setText(String.format(mDimensionsFormatString, cellSpan[0], cellSpan[1]));
         dims.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
 
         if (createHolographicOutline) {
@@ -196,6 +202,28 @@
         }
     }
 
+    public void applyFromResolveInfo(PackageManager pm, ResolveInfo info,
+            FastBitmapDrawable preview, PagedViewIconCache cache, boolean createHolographicOutline){
+        final ImageView image = (ImageView) findViewById(R.id.widget_preview);
+        image.setImageDrawable(preview);
+        mPreviewImageView = image;
+        final TextView name = (TextView) findViewById(R.id.widget_name);
+        name.setText(info.loadLabel(pm));
+        name.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        final TextView dims = (TextView) findViewById(R.id.widget_dims);
+        if (dims != null) {
+            dims.setText(String.format(mDimensionsFormatString, 1, 1));
+            dims.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+        }
+
+        if (createHolographicOutline) {
+            mIconCache = cache;
+            mIconCacheKey = new PagedViewIconCache.Key(info);
+            mHolographicOutline = mIconCache.getOutline(mIconCacheKey);
+            mPreview = preview;
+        }
+    }
+
     public void applyFromWallpaperInfo(ResolveInfo info, PackageManager packageManager,
             FastBitmapDrawable preview, int maxWidth, PagedViewIconCache cache,
             boolean createHolographicOutline) {
@@ -228,6 +256,28 @@
     }
 
     @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (LauncherApplication.isScreenLarge()) {
+            return FocusHelper.handlePagedViewWidgetKeyEvent(this, keyCode, event)
+                    || super.onKeyDown(keyCode, event);
+        } else {
+            return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+                    || super.onKeyDown(keyCode, event);
+        }
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (LauncherApplication.isScreenLarge()) {
+            return FocusHelper.handlePagedViewWidgetKeyEvent(this, keyCode, event)
+                    || super.onKeyUp(keyCode, event);
+        } else {
+            return FocusHelper.handlePagedViewGridLayoutWidgetKeyEvent(this, keyCode, event)
+                    || super.onKeyUp(keyCode, event);
+        }
+    }
+
+    @Override
     protected void onDraw(Canvas canvas) {
         if (mAlpha > 0) {
             super.onDraw(canvas);
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 72f2d51..c0f80ae 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -148,12 +148,6 @@
         return "ShortcutInfo(title=" + title.toString() + ")";
     }
 
-    @Override
-    void unbind() {
-        super.unbind();
-    }
-
-
     public static void dumpShortcutInfoList(String tag, String label,
             ArrayList<ShortcutInfo> list) {
         Log.d(tag, label + " size=" + list.size());
diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java
index 93c500a..de73c3e 100644
--- a/src/com/android/launcher2/ShortcutsAdapter.java
+++ b/src/com/android/launcher2/ShortcutsAdapter.java
@@ -30,7 +30,7 @@
 /**
  * GridView adapter to show the list of applications and shortcuts
  */
-public class ShortcutsAdapter  extends ArrayAdapter<ShortcutInfo> {
+public class ShortcutsAdapter extends ArrayAdapter<ShortcutInfo> {
     private final LayoutInflater mInflater;
     private final IconCache mIconCache;
 
diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java
deleted file mode 100644
index 251b3f9..0000000
--- a/src/com/android/launcher2/UserFolder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.android.launcher2;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.launcher.R;
-
-/**
- * Folder which contains applications or shortcuts chosen by the user.
- *
- */
-public class UserFolder extends Folder implements DropTarget {
-    private static final String TAG = "Launcher.UserFolder";
-
-    public UserFolder(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-    
-    /**
-     * Creates a new UserFolder, inflated from R.layout.user_folder.
-     *
-     * @param context The application's context.
-     *
-     * @return A new UserFolder.
-     */
-    static UserFolder fromXml(Context context) {
-        return (UserFolder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
-    }
-
-    public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-        final ItemInfo item = (ItemInfo) dragInfo;
-        final int itemType = item.itemType;
-        return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                    itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT)
-                && item.container != mInfo.id;
-    }
-
-    public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-        ShortcutInfo item;
-        if (dragInfo instanceof ApplicationInfo) {
-            // Came from all apps -- make a copy
-            item = ((ApplicationInfo)dragInfo).makeShortcut();
-        } else {
-            item = (ShortcutInfo)dragInfo;
-        }
-        ((ShortcutsAdapter)mContent.getAdapter()).add(item);
-        LauncherModel.addOrMoveItemInDatabase(mLauncher, item, mInfo.id, 0, 0, 0);
-    }
-
-    public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-    }
-
-    @Override
-    public void onDropCompleted(View target, Object dragInfo, boolean success) {
-        if (success) {
-            ShortcutsAdapter adapter = (ShortcutsAdapter)mContent.getAdapter();
-            adapter.remove(mDragItem);
-        }
-    }
-
-    public boolean isDropEnabled() {
-        return true;
-    }
-
-    void bind(FolderInfo info) {
-        super.bind(info);
-        setContentAdapter(new ShortcutsAdapter(mContext, ((UserFolderInfo) info).contents));
-    }
-
-    // When the folder opens, we need to refresh the GridView's selection by
-    // forcing a layout
-    @Override
-    void onOpen() {
-        super.onOpen();
-        requestFocus();
-    }
-
-    @Override
-    public DropTarget getDropTargetDelegate(DragSource source, int x, int y, int xOffset, int yOffset,
-            DragView dragView, Object dragInfo) {
-        return null;
-    }
-}
diff --git a/src/com/android/launcher2/UserFolderInfo.java b/src/com/android/launcher2/UserFolderInfo.java
deleted file mode 100644
index 0b8841c..0000000
--- a/src/com/android/launcher2/UserFolderInfo.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher2;
-
-import android.content.ContentValues;
-
-import java.util.ArrayList;
-
-/**
- * Represents a folder containing shortcuts or apps.
- */
-class UserFolderInfo extends FolderInfo {
-    /**
-     * The apps and shortcuts 
-     */
-    ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
-    
-    UserFolderInfo() {
-        itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER;
-    }
-    
-    /**
-     * Add an app or shortcut
-     * 
-     * @param item
-     */
-    public void add(ShortcutInfo item) {
-        contents.add(item);
-    }
-    
-    /**
-     * Remove an app or shortcut. Does not change the DB.
-     * 
-     * @param item
-     */
-    public void remove(ShortcutInfo item) {
-        contents.remove(item);
-    }
-    
-    @Override
-    void onAddToDatabase(ContentValues values) { 
-        super.onAddToDatabase(values);
-        values.put(LauncherSettings.Favorites.TITLE, title.toString());
-    }
-}
diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java
index 8ab22eb..ba25893 100644
--- a/src/com/android/launcher2/Utilities.java
+++ b/src/com/android/launcher2/Utilities.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher2;
 
+import java.util.Random;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -241,7 +243,7 @@
         final float density = metrics.density;
 
         sIconWidth = sIconHeight = (int) resources.getDimension(R.dimen.app_icon_size);
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             sIconContentSize = (int) resources.getDimension(R.dimen.app_icon_content_size);
         }
         sIconTextureWidth = sIconTextureHeight = sIconWidth + 2;
@@ -389,4 +391,8 @@
         }
         return n;
     }
+
+    static int generateRandomId() {
+        return new Random(System.currentTimeMillis()).nextInt(1 << 24);
+    }
 }
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index e7865d2..1373996 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -16,8 +16,9 @@
 
 package com.android.launcher2;
 
-import com.android.launcher.R;
-import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -37,7 +38,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -49,7 +49,6 @@
 import android.graphics.RectF;
 import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
-import android.net.Uri;
 import android.os.IBinder;
 import android.os.Parcelable;
 import android.util.AttributeSet;
@@ -66,9 +65,8 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
+import com.android.launcher.R;
+import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
 
 /**
  * The workspace is a wide area with a wallpaper and a finite number of pages.
@@ -131,6 +129,7 @@
     private int mDefaultPage;
 
     private boolean mIsDragInProcess = false;
+    private boolean mIsDraggingOverIcon = false;
 
     /**
      * CellInfo for the cell that is currently being dragged
@@ -155,7 +154,7 @@
     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
     private int[] mTempCell = new int[2];
     private int[] mTempEstimate = new int[2];
-    private float[] mTempOriginXY = new float[2];
+    private float[] mDragViewVisualCenter = new float[2];
     private float[] mTempDragCoordinates = new float[2];
     private float[] mTempTouchCoordinates = new float[2];
     private float[] mTempCellLayoutCenterCoordinates = new float[2];
@@ -213,6 +212,7 @@
     WallpaperOffsetInterpolator mWallpaperOffset;
     boolean mUpdateWallpaperOffsetImmediately = false;
     boolean mSyncWallpaperOffsetWithScroll = true;
+    private Runnable mDelayedResizeRunnable;
 
     // info about the last drag
     private DragView mLastDragView;
@@ -249,7 +249,7 @@
         super(context, attrs, defStyle);
         mContentIsRefreshable = false;
 
-        if (!LauncherApplication.isScreenXLarge()) {
+        if (!LauncherApplication.isScreenLarge()) {
             mFadeInAdjacentScreens = false;
         }
 
@@ -333,65 +333,48 @@
 
     @Override
     protected int getScrollMode() {
-        if (LauncherApplication.isScreenXLarge()) {
+        if (LauncherApplication.isScreenLarge()) {
             return SmoothPagedView.X_LARGE_MODE;
         } else {
             return SmoothPagedView.DEFAULT_MODE;
         }
     }
 
-    @Override
-    public void addView(View child, int index, LayoutParams params) {
+    private void onAddView(View child) {
         if (!(child instanceof CellLayout)) {
             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
         }
         ((CellLayout) child).setOnInterceptTouchListener(this);
         child.setOnClickListener(this);
         child.setClickable(true);
+    }
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        onAddView(child);
         super.addView(child, index, params);
     }
 
     @Override
     public void addView(View child) {
-        if (!(child instanceof CellLayout)) {
-            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
-        }
-        ((CellLayout) child).setOnInterceptTouchListener(this);
-        child.setOnClickListener(this);
-        child.setClickable(true);
+        onAddView(child);
         super.addView(child);
     }
 
     @Override
     public void addView(View child, int index) {
-        if (!(child instanceof CellLayout)) {
-            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
-        }
-        ((CellLayout) child).setOnInterceptTouchListener(this);
-        child.setOnClickListener(this);
-        child.setClickable(true);
+        onAddView(child);
         super.addView(child, index);
     }
 
     @Override
     public void addView(View child, int width, int height) {
-        if (!(child instanceof CellLayout)) {
-            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
-        }
-        ((CellLayout) child).setOnInterceptTouchListener(this);
-        child.setOnClickListener(this);
-        child.setClickable(true);
+        onAddView(child);
         super.addView(child, width, height);
     }
 
     @Override
     public void addView(View child, LayoutParams params) {
-        if (!(child instanceof CellLayout)) {
-            throw new IllegalArgumentException("A Workspace can only have CellLayout children.");
-        }
-        ((CellLayout) child).setOnInterceptTouchListener(this);
-        child.setOnClickListener(this);
-        child.setClickable(true);
+        onAddView(child);
         super.addView(child, params);
     }
 
@@ -485,6 +468,10 @@
             lp.cellVSpan = spanY;
         }
 
+        if (spanX < 0 && spanY < 0) {
+            lp.isLockedToGrid = false;
+        }
+
         // Get the canonical child id to uniquely represent this view in this screen
         int childId = LauncherModel.getCellLayoutChildId(-1, screen, x, y, spanX, spanY);
         boolean markCellsAsOccupied = !(child instanceof Folder);
@@ -645,6 +632,11 @@
         }
         mOverScrollMaxBackgroundAlpha = 0.0f;
         mOverScrollPageIndex = -1;
+
+        if (mDelayedResizeRunnable != null) {
+            mDelayedResizeRunnable.run();
+            mDelayedResizeRunnable = null;
+        }
     }
 
     @Override
@@ -769,7 +761,8 @@
         return offset;
     }
     private void syncWallpaperOffsetWithScroll() {
-        if (LauncherApplication.isScreenXLarge()) {
+        final boolean enableWallpaperEffects = isHardwareAccelerated();
+        if (enableWallpaperEffects) {
             mWallpaperOffset.setFinalX(wallpaperOffsetForCurrentScroll());
         }
     }
@@ -1067,6 +1060,11 @@
 
     @Override
     protected void screenScrolled(int screenCenter) {
+        // If the screen is not xlarge, then don't rotate the CellLayouts
+        // NOTE: If we don't update the side pages alpha, then we should not hide the side pages.
+        //       see unshrink().
+        if (!LauncherApplication.isScreenLarge()) return;
+
         final int halfScreenSize = getMeasuredWidth() / 2;
 
         for (int i = 0; i < getChildCount(); i++) {
@@ -1244,6 +1242,14 @@
     }
 
     @Override
+    public int getDescendantFocusability() {
+        if (mIsSmall) {
+            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
+        }
+        return super.getDescendantFocusability();
+    }
+
+    @Override
     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
         if (!mLauncher.isAllAppsVisible()) {
             final Folder openFolder = getOpenFolder();
@@ -1255,19 +1261,6 @@
         }
     }
 
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            // (In XLarge mode, the workspace is shrunken below all apps, and responds to taps
-            // ie when you click on a mini-screen, it zooms back to that screen)
-            if (!LauncherApplication.isScreenXLarge() && mLauncher.isAllAppsVisible()) {
-                return false;
-            }
-        }
-
-        return super.dispatchTouchEvent(ev);
-    }
-
     void enableChildrenCache(int fromPage, int toPage) {
         if (fromPage > toPage) {
             final int temp = fromPage;
@@ -1297,27 +1290,32 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        AllAppsPagedView allApps = (AllAppsPagedView)
-                mLauncher.findViewById(R.id.all_apps_paged_view);
-
-        if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN
-                && allApps != null) {
-            if (ev.getAction() == MotionEvent.ACTION_UP &&
-                    allApps.getTouchState() == TOUCH_STATE_REST) {
-
-                // Cancel any scrolling that is in progress.
-                if (!mScroller.isFinished()) {
-                    mScroller.abortAnimation();
-                }
-                setCurrentPage(mCurrentPage);
-
-                if (mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
-                    mLauncher.showWorkspace(true);
-                }
-                allApps.onTouchEvent(ev);
-                return true;
+        if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+            PagedView appsPane;
+            if (LauncherApplication.isScreenLarge()) {
+                appsPane = (PagedView) mLauncher.findViewById(R.id.all_apps_paged_view);
             } else {
-                return allApps.onTouchEvent(ev);
+                appsPane = (PagedView) mLauncher.findViewById(R.id.apps_customize_pane_content);
+            }
+
+            if (appsPane != null) {
+                if (ev.getAction() == MotionEvent.ACTION_UP &&
+                        appsPane.getTouchState() == TOUCH_STATE_REST) {
+
+                    // Cancel any scrolling that is in progress.
+                    if (!mScroller.isFinished()) {
+                        mScroller.abortAnimation();
+                    }
+                    setCurrentPage(mCurrentPage);
+
+                    if (mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
+                        mLauncher.showWorkspace(true);
+                    }
+                    appsPane.onTouchEvent(ev);
+                    return true;
+                } else {
+                    return appsPane.onTouchEvent(ev);
+                }
             }
         }
         return super.onTouchEvent(ev);
@@ -1392,14 +1390,6 @@
 
     // we use this to shrink the workspace for the all apps view and the customize view
     public void shrink(ShrinkState shrinkState, boolean animated) {
-        // In the launcher interaction model, we're never in the state where we're shrunken and
-        // visible in the bottom of the screen, and then want to fade to being invisible.
-        // After spring loaded mode ends, this method was getting called twice, the first time
-        // with BOTTOM_VISIBLE (what we want) and a second time with BOTTOM_INVISIBLE (not
-        // what we want). As a temporary solution, we just change the second call to BOTTOM_VISIBLE
-        if (mIsSmall && mShrinkState == ShrinkState.BOTTOM_VISIBLE) {
-            shrinkState = ShrinkState.BOTTOM_VISIBLE;
-        }
         if (mFirstLayout) {
             // (mFirstLayout == "first layout has not happened yet")
             // if we get a call to shrink() as part of our initialization (for example, if
@@ -1471,7 +1461,7 @@
 
         int duration;
         if (shrinkState == ShrinkState.BOTTOM_HIDDEN || shrinkState == ShrinkState.BOTTOM_VISIBLE) {
-            duration = res.getInteger(R.integer.config_allAppsWorkspaceShrinkTime);
+            duration = res.getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
         } else {
             duration = res.getInteger(R.integer.config_customizeWorkspaceShrinkTime);
         }
@@ -1556,30 +1546,35 @@
         float offsetFromCenter = (wallpaperTravelHeight / (float) mWallpaperHeight) / 2f;
         boolean isLandscape = display.getWidth() > display.getHeight();
 
-        switch (shrinkState) {
-            // animating in
-            case TOP:
-                // customize
-                wallpaperOffset = 0.5f + offsetFromCenter;
-                mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.46f : 0.44f);
-                break;
-            case MIDDLE:
-            case SPRING_LOADED:
-                wallpaperOffset = 0.5f;
-                mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
-                break;
-            case BOTTOM_HIDDEN:
-            case BOTTOM_VISIBLE:
-                // allapps
-                wallpaperOffset = 0.5f - offsetFromCenter;
-                mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
-                break;
+        final boolean enableWallpaperEffects = isHardwareAccelerated();
+        if (enableWallpaperEffects) {
+            switch (shrinkState) {
+                // animating in
+                case TOP:
+                    // customize
+                    wallpaperOffset = 0.5f + offsetFromCenter;
+                    mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.46f : 0.44f);
+                    break;
+                case MIDDLE:
+                case SPRING_LOADED:
+                    wallpaperOffset = 0.5f;
+                    mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
+                    break;
+                case BOTTOM_HIDDEN:
+                case BOTTOM_VISIBLE:
+                    // allapps
+                    wallpaperOffset = 0.5f - offsetFromCenter;
+                    mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.34f : 0.32f);
+                    break;
+            }
         }
 
         setLayoutScale(1.0f);
         if (animated) {
-            mWallpaperOffset.setHorizontalCatchupConstant(0.46f);
-            mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+            if (enableWallpaperEffects) {
+                mWallpaperOffset.setHorizontalCatchupConstant(0.46f);
+                mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+            }
 
             mSyncWallpaperOffsetWithScroll = false;
 
@@ -1591,19 +1586,19 @@
             final float oldVerticalWallpaperOffset = getVerticalWallpaperOffset();
             final float newHorizontalWallpaperOffset = 0.5f;
             final float newVerticalWallpaperOffset = wallpaperOffset;
-            animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    final float b = (Float) animation.getAnimatedValue();
-                    final float a = 1f - b;
+            animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                public void onAnimationUpdate(float a, float b) {
                     if (b == 0f) {
                         // an optimization, and required for correct behavior.
                         return;
                     }
                     fastInvalidate();
-                    setHorizontalWallpaperOffset(
+                    if (enableWallpaperEffects) {
+                        setHorizontalWallpaperOffset(
                             a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
-                    setVerticalWallpaperOffset(
+                        setVerticalWallpaperOffset(
                             a * oldVerticalWallpaperOffset + b * newVerticalWallpaperOffset);
+                    }
                     for (int i = 0; i < screenCount; i++) {
                         final CellLayout cl = (CellLayout) getChildAt(i);
                         cl.fastInvalidate();
@@ -1621,7 +1616,7 @@
             mAnimator.playTogether(animWithInterpolator);
             mAnimator.addListener(mShrinkAnimationListener);
             mAnimator.start();
-        } else {
+        } else if (enableWallpaperEffects) {
             setVerticalWallpaperOffset(wallpaperOffset);
             setHorizontalWallpaperOffset(0.5f);
             updateWallpaperOffsetImmediately();
@@ -1708,39 +1703,57 @@
         for (int i = 0; i < screenCount; i++) {
             CellLayout cl = (CellLayout) getChildAt(i);
             cl.setIsDragOccuring(isDragHappening);
-            switch (state) {
-                case TOP:
-                    cl.setIsDefaultDropTarget(i == mCurrentPage);
-                case BOTTOM_HIDDEN:
-                case BOTTOM_VISIBLE:
-                case SPRING_LOADED:
-                    if (state != ShrinkState.TOP) {
-                        cl.setIsDefaultDropTarget(false);
-                    }
-                    if (!isDragHappening) {
-                        // even if a drag isn't happening, we don't want to show a screen as
-                        // accepting drops if it doesn't have at least one free cell
-                        spanX = 1;
-                        spanY = 1;
-                    }
-                    // the page accepts drops if we can find at least one empty spot
-                    cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
-                    break;
-                default:
-                     throw new RuntimeException("Unhandled ShrinkState " + state);
+            if (state == null) {
+                // If we are not in a shrunken state, mark all cell layouts as droppable (if they
+                // have the space)
+                cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
+            } else {
+                switch (state) {
+                    case TOP:
+                        cl.setIsDefaultDropTarget(i == mCurrentPage);
+                    case BOTTOM_HIDDEN:
+                    case BOTTOM_VISIBLE:
+                    case SPRING_LOADED:
+                        if (state != ShrinkState.TOP) {
+                            cl.setIsDefaultDropTarget(false);
+                        }
+                        if (!isDragHappening) {
+                            // even if a drag isn't happening, we don't want to show a screen as
+                            // accepting drops if it doesn't have at least one free cell
+                            spanX = 1;
+                            spanY = 1;
+                        }
+                        // the page accepts drops if we can find at least one empty spot
+                        cl.setAcceptsDrops(cl.findCellForSpan(null, spanX, spanY));
+                        break;
+                    default:
+                         throw new RuntimeException("Unhandled ShrinkState " + state);
+                }
             }
         }
     }
 
     /*
-     *
-     * We call these methods (onDragStartedWithItemSpans/onDragStartedWithItemMinSize) whenever we
-     * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
-     *
-     * These methods mark the appropriate pages as accepting drops (which alters their visual
-     * appearance).
-     *
-     */
+    *
+    * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
+    * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
+    *
+    * These methods mark the appropriate pages as accepting drops (which alters their visual
+    * appearance).
+    *
+    */
+    public void onDragStartedWithItem(View v) {
+        mIsDragInProcess = true;
+
+        final Canvas canvas = new Canvas();
+
+        // We need to add extra padding to the bitmap to make room for the glow effect
+        final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
+
+        // The outline is used to visualize where the item will land if dropped
+        mDragOutline = createDragOutline(v, canvas, bitmapPadding);
+    }
+
     public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
         mIsDragInProcess = true;
 
@@ -1750,9 +1763,11 @@
         final int bitmapPadding = HolographicOutlineHelper.MAX_OUTER_BLUR_RADIUS;
 
         CellLayout cl = (CellLayout) getChildAt(0);
-        int[] desiredSize = cl.cellSpansToSize(spanX, spanY);
+
+        int[] size = cl.cellSpansToSize(spanX, spanY);
+
         // The outline is used to visualize where the item will land if dropped
-        mDragOutline = createDragOutline(b, canvas, bitmapPadding, desiredSize[0], desiredSize[1]);
+        mDragOutline = createDragOutline(b, canvas, bitmapPadding, size[0], size[1]);
 
         updateWhichPagesAcceptDropsDuringDrag(mShrinkState, spanX, spanY);
     }
@@ -1800,8 +1815,8 @@
     }
 
     public void exitWidgetResizeMode() {
-        final CellLayout currentLayout = (CellLayout) getChildAt(getCurrentPage());
-        currentLayout.getChildrenLayout().clearAllResizeFrames();
+        DragLayer dragLayer = (DragLayer) mLauncher.findViewById(R.id.drag_layer);
+        dragLayer.clearAllResizeFrames();
     }
 
     void unshrink(boolean animated) {
@@ -1847,20 +1862,34 @@
 
             for (int i = 0; i < screenCount; i++) {
                 final CellLayout cl = (CellLayout)getChildAt(i);
-                float finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+                float finalAlphaValue = 0f;
+                float rotation = 0f;
+                if (LauncherApplication.isScreenLarge()) {
+                    finalAlphaValue = (i == mCurrentPage) ? 1.0f : 0.0f;
+
+                    if (i < mCurrentPage) {
+                        rotation = WORKSPACE_ROTATION;
+                    } else if (i > mCurrentPage) {
+                        rotation = -WORKSPACE_ROTATION;
+                    }
+                } else {
+                    // Don't hide the side panes on the phone if we don't also update the side pages
+                    // alpha.  See screenScrolled().
+                    finalAlphaValue = 1f;
+                }
                 float finalAlphaMultiplierValue =
                         ((i == mCurrentPage) && (mShrinkState != ShrinkState.SPRING_LOADED)) ?
                         0.0f : 1.0f;
-                float rotation = 0.0f;
 
-                if (i < mCurrentPage) {
-                    rotation = WORKSPACE_ROTATION;
-                } else if (i > mCurrentPage) {
-                    rotation = -WORKSPACE_ROTATION;
+                float translation = 0f;
+
+                // If the screen is not xlarge, then don't rotate the CellLayouts
+                // NOTE: If we don't update the side pages alpha, then we should not hide the side
+                //       pages. see unshrink().
+                if (LauncherApplication.isScreenLarge()) {
+                    translation = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
                 }
 
-                float translation = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
-
                 oldAlphas[i] = cl.getAlpha();
                 newAlphas[i] = finalAlphaValue;
                 if (animated) {
@@ -1893,56 +1922,62 @@
             }
             Display display = mLauncher.getWindowManager().getDefaultDisplay();
             boolean isLandscape = display.getWidth() > display.getHeight();
-            switch (mShrinkState) {
-                // animating out
-                case TOP:
-                    // customize
-                    if (animated) {
-                        mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.62f);
-                        mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.62f);
-                        mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
-                    }
-                    break;
-                case MIDDLE:
-                case SPRING_LOADED:
-                    if (animated) {
-                        mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.49f : 0.46f);
-                        mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.49f : 0.46f);
-                        mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
-                    }
-                    break;
-                case BOTTOM_HIDDEN:
-                case BOTTOM_VISIBLE:
-                    // all apps
-                    if (animated) {
-                        mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.65f);
-                        mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.65f);
-                        mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
-                    }
-                    break;
+            final boolean enableWallpaperEffects = isHardwareAccelerated();
+            if (enableWallpaperEffects) {
+                switch (mShrinkState) {
+                    // animating out
+                    case TOP:
+                        // customize
+                        if (animated) {
+                            mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.62f);
+                            mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.62f);
+                            mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+                        }
+                        break;
+                    case MIDDLE:
+                    case SPRING_LOADED:
+                        if (animated) {
+                            mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.49f : 0.46f);
+                            mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.49f : 0.46f);
+                            mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+                        }
+                        break;
+                    case BOTTOM_HIDDEN:
+                    case BOTTOM_VISIBLE:
+                        // all apps
+                        if (animated) {
+                            mWallpaperOffset.setHorizontalCatchupConstant(isLandscape ? 0.65f : 0.65f);
+                            mWallpaperOffset.setVerticalCatchupConstant(isLandscape ? 0.65f : 0.65f);
+                            mWallpaperOffset.setOverrideHorizontalCatchupConstant(true);
+                        }
+                        break;
+                }
             }
             if (animated) {
                 ValueAnimator animWithInterpolator =
                     ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
                 animWithInterpolator.setInterpolator(mZoomInInterpolator);
 
-                final float oldHorizontalWallpaperOffset = getHorizontalWallpaperOffset();
-                final float oldVerticalWallpaperOffset = getVerticalWallpaperOffset();
-                final float newHorizontalWallpaperOffset = wallpaperOffsetForCurrentScroll();
-                final float newVerticalWallpaperOffset = 0.5f;
-                animWithInterpolator.addUpdateListener(new AnimatorUpdateListener() {
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        final float b = (Float) animation.getAnimatedValue();
-                        final float a = 1f - b;
+                final float oldHorizontalWallpaperOffset = enableWallpaperEffects ?
+                        getHorizontalWallpaperOffset() : 0;
+                final float oldVerticalWallpaperOffset = enableWallpaperEffects ?
+                        getVerticalWallpaperOffset() : 0;
+                final float newHorizontalWallpaperOffset = enableWallpaperEffects ?
+                        wallpaperOffsetForCurrentScroll() : 0;
+                final float newVerticalWallpaperOffset = enableWallpaperEffects ? 0.5f : 0;
+                animWithInterpolator.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                    public void onAnimationUpdate(float a, float b) {
                         if (b == 0f) {
                             // an optimization, but not required
                             return;
                         }
                         fastInvalidate();
-                        setHorizontalWallpaperOffset(
-                                a * oldHorizontalWallpaperOffset + b * newHorizontalWallpaperOffset);
-                        setVerticalWallpaperOffset(
-                                a * oldVerticalWallpaperOffset + b * newVerticalWallpaperOffset);
+                        if (enableWallpaperEffects) {
+                            setHorizontalWallpaperOffset(a * oldHorizontalWallpaperOffset
+                                    + b * newHorizontalWallpaperOffset);
+                            setVerticalWallpaperOffset(a * oldVerticalWallpaperOffset
+                                    + b * newVerticalWallpaperOffset);
+                        }
                         for (int i = 0; i < screenCount; i++) {
                             final CellLayout cl = (CellLayout) getChildAt(i);
                             cl.fastInvalidate();
@@ -1964,11 +1999,9 @@
                 ValueAnimator rotationAnim =
                     ValueAnimator.ofFloat(0f, 1f).setDuration(duration);
                 rotationAnim.setInterpolator(new DecelerateInterpolator(2.0f));
-                rotationAnim.addUpdateListener(new AnimatorUpdateListener() {
-                    public void onAnimationUpdate(ValueAnimator animation) {
+                rotationAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+                    public void onAnimationUpdate(float a, float b) {
                         // don't invalidate workspace because we did it above
-                        final float b = (Float) animation.getAnimatedValue();
-                        final float a = 1f - b;
                         if (b == 0f) {
                             // an optimization, but not required
                             return;
@@ -1986,9 +2019,11 @@
                 mAnimator.addListener(mUnshrinkAnimationListener);
                 mAnimator.start();
             } else {
-                setHorizontalWallpaperOffset(wallpaperOffsetForCurrentScroll());
-                setVerticalWallpaperOffset(0.5f);
-                updateWallpaperOffsetImmediately();
+                if (enableWallpaperEffects) {
+                    setHorizontalWallpaperOffset(wallpaperOffsetForCurrentScroll());
+                    setVerticalWallpaperOffset(0.5f);
+                    updateWallpaperOffsetImmediately();
+                }
             }
         }
 
@@ -2009,7 +2044,8 @@
         v.getDrawingRect(clipRect);
 
         // For a TextView, adjust the clip rect so that we don't include the text label
-        if (v instanceof BubbleTextView) {
+        if (v instanceof FolderIcon) {
+        } else if (v instanceof BubbleTextView) {
             final BubbleTextView tv = (BubbleTextView) v;
             clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +
                     tv.getLayout().getLineTop(0);
@@ -2140,12 +2176,24 @@
 
         final int bmpWidth = b.getWidth();
         final int bmpHeight = b.getHeight();
+
         child.getLocationOnScreen(mTempXY);
         final int screenX = (int) mTempXY[0] + (child.getWidth() - bmpWidth) / 2;
         final int screenY = (int) mTempXY[1] + (child.getHeight() - bmpHeight) / 2;
+
+        Rect dragRect = null;
+        if ((child instanceof BubbleTextView) && !(child instanceof FolderIcon)) {
+            int iconSize = getResources().getDimensionPixelSize(R.dimen.app_icon_size);
+            int top = child.getPaddingTop();
+            int left = (bmpWidth - iconSize) / 2;
+            int right = left + iconSize;
+            int bottom = top + iconSize;
+            dragRect = new Rect(left, top, right, bottom);
+        }
+
         mLauncher.lockScreenOrientation();
-        mDragController.startDrag(
-                b, screenX, screenY, this, child.getTag(), DragController.DRAG_ACTION_MOVE);
+        mDragController.startDrag(b, screenX, screenY, this, child.getTag(),
+                DragController.DRAG_ACTION_MOVE, dragRect);
         b.recycle();
     }
 
@@ -2167,15 +2215,15 @@
         final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
 
         // Based on the position of the drag view, find the top left of the original view
-        int viewX = dragViewX + (dragView.getWidth() - child.getWidth()) / 2;
-        int viewY = dragViewY + (dragView.getHeight() - child.getHeight()) / 2;
-        viewX += getResources().getInteger(R.integer.config_dragViewOffsetX);
-        viewY += getResources().getInteger(R.integer.config_dragViewOffsetY);
+        int viewX = dragViewX + (dragView.getWidth() - child.getMeasuredWidth()) / 2;
+        int viewY = dragViewY + (dragView.getHeight() - child.getMeasuredHeight()) / 2;
+
+        CellLayout layout = (CellLayout) parent;
 
         // Set its old pos (in the new parent's coordinates); it will be animated
         // in animateViewIntoPosition after the next layout pass
-        lp.oldX = viewX - (parent.getLeft() - mScrollX);
-        lp.oldY = viewY - (parent.getTop() - mScrollY);
+        lp.oldX = viewX - (layout.getLeft() + layout.getLeftPadding() - mScrollX);
+        lp.oldY = viewY - (layout.getTop() + layout.getTopPadding() - mScrollY);
     }
 
     /*
@@ -2187,8 +2235,8 @@
         final CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
 
         // Convert the animation params to be relative to the Workspace, not the CellLayout
-        final int fromX = lp.oldX + parent.getLeft();
-        final int fromY = lp.oldY + parent.getTop();
+        final int fromX = lp.oldX + parent.getLeft() + parent.getLeftPadding();
+        final int fromY = lp.oldY + parent.getTop() + parent.getTopPadding();
 
         final int dx = lp.x - lp.oldX;
         final int dy = lp.y - lp.oldY;
@@ -2271,23 +2319,80 @@
         return true;
     }
 
+    boolean willCreateUserFolder(ItemInfo info, CellLayout target, int originX, int originY) {
+        mTargetCell = findNearestArea(originX, originY,
+                1, 1, target,
+                mTargetCell);
+
+        View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
+        boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
+                mDragInfo.cellY == mTargetCell[1]);
+
+        if (v == null || hasntMoved) return false;
+
+        boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
+        boolean willBecomeShortcut =
+            (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
+            info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+
+        return (aboveShortcut && willBecomeShortcut);
+    }
+
+    boolean createUserFolderIfNecessary(View newView, CellLayout target, int originX,
+            int originY, boolean external) {
+        int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
+        int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
+
+        // First we find the cell nearest to point at which the item is dropped, without
+        // any consideration to whether there is an item there.
+        mTargetCell = findNearestArea(originX, originY,
+                spanX, spanY, target,
+                mTargetCell);
+
+        View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
+        boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
+                mDragInfo.cellY == mTargetCell[1]);
+
+        if (v == null || hasntMoved) return false;
+
+        final int screen = (mTargetCell == null) ?
+                mDragInfo.screen : indexOfChild(target);
+
+        boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);
+        boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);
+
+        if (aboveShortcut && willBecomeShortcut) {
+            ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();
+            ShortcutInfo destInfo = (ShortcutInfo) v.getTag();
+            // if the drag started here, we need to remove it from the workspace
+            if (!external) {
+                int fromScreen = mDragInfo.screen;
+                CellLayout sourceLayout = (CellLayout) getChildAt(fromScreen);
+                sourceLayout.removeView(newView);
+            }
+
+            target.removeView(v);
+            FolderIcon fi = mLauncher.addFolder(screen, mTargetCell[0], mTargetCell[1]);
+            destInfo.cellX = -1;
+            destInfo.cellY = -1;
+            sourceInfo.cellX = -1;
+            sourceInfo.cellY = -1;
+            fi.addItem(destInfo);
+            fi.addItem(sourceInfo);
+            return true;
+        }
+        return false;
+    }
+
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        boolean largeOrSpringLoaded = !mIsSmall || mWasSpringLoadedOnDragExit;
-        int originX = largeOrSpringLoaded ? x - xOffset : x - xOffset + dragView.getWidth() / 2;
-        int originY = largeOrSpringLoaded ? y - yOffset : y - yOffset + dragView.getHeight() / 2;
 
-        if (mIsSmall || mIsInUnshrinkAnimation) {
-            // get originX and originY in the local coordinate system of the screen
-            mTempOriginXY[0] = originX;
-            mTempOriginXY[1] = originY;
-            mapPointFromSelfToChild(mDragTargetLayout, mTempOriginXY);
-            originX = (int)mTempOriginXY[0];
-            originY = (int)mTempOriginXY[1];
-            if (!largeOrSpringLoaded) {
-               originX -= mDragTargetLayout.getCellWidth() / 2;
-               originY -= mDragTargetLayout.getCellHeight() / 2;
-            }
+        mDragViewVisualCenter = getDragViewVisualCenter(x, y, xOffset, yOffset, dragView,
+                mDragViewVisualCenter);
+
+        // We want the point to be mapped to the dragTarget.
+        if (mDragTargetLayout != null) {
+            mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
         }
 
         // When you are in customization mode and drag to a particular screen, make that the
@@ -2300,21 +2405,25 @@
         }
 
         if (source != this) {
-            final int[] touchXY = new int[] { originX, originY };
-            if ((mIsSmall || mIsInUnshrinkAnimation) && !mLauncher.isAllAppsVisible()) {
+            final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
+                    (int) mDragViewVisualCenter[1] };
+            if (LauncherApplication.isScreenLarge() && (mIsSmall || mIsInUnshrinkAnimation)
+                    && !mLauncher.isAllAppsVisible()) {
                 // When the workspace is shrunk and the drop comes from customize, don't actually
                 // add the item to the screen -- customize will do this itself
                 ((ItemInfo) dragInfo).dropPos = touchXY;
                 return;
             }
-            onDropExternal(touchXY, dragInfo, mDragTargetLayout, false);
+            onDropExternal(touchXY, dragInfo, mDragTargetLayout, false, dragView);
         } else if (mDragInfo != null) {
             final View cell = mDragInfo.cell;
             CellLayout dropTargetLayout = mDragTargetLayout;
+            boolean dropInscrollArea = false;
 
             // Handle the case where the user drops when in the scroll area.
             // This is treated as a drop on the adjacent page.
             if (dropTargetLayout == null && mInScrollArea) {
+                dropInscrollArea = true;
                 if (mPendingScrollDirection == DragController.SCROLL_LEFT) {
                     dropTargetLayout = (CellLayout) getChildAt(mCurrentPage - 1);
                 } else if (mPendingScrollDirection == DragController.SCROLL_RIGHT) {
@@ -2324,13 +2433,22 @@
 
             if (dropTargetLayout != null) {
                 // Move internally
-                mTargetCell = findNearestVacantArea(originX, originY,
-                        mDragInfo.spanX, mDragInfo.spanY, cell, dropTargetLayout,
-                        mTargetCell);
-
                 final int screen = (mTargetCell == null) ?
                         mDragInfo.screen : indexOfChild(dropTargetLayout);
 
+                // If the item being dropped is a shortcut and the nearest drop cell also contains
+                // a shortcut, then create a folder with the two shortcuts.
+                if (!dropInscrollArea && createUserFolderIfNecessary(cell, dropTargetLayout,
+                        (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], false)) {
+                    return;
+                }
+
+                // Aside from the special case where we're dropping a shortcut onto a shortcut,
+                // we need to find the nearest cell location that is vacant
+                mTargetCell = findNearestVacantArea((int) mDragViewVisualCenter[0],
+                        (int) mDragViewVisualCenter[1], mDragInfo.spanX, mDragInfo.spanY, cell,
+                        dropTargetLayout, mTargetCell);
+
                 if (screen != mCurrentPage) {
                     snapToPage(screen);
                 }
@@ -2353,7 +2471,6 @@
                             mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
 
                     if (cell instanceof LauncherAppWidgetHostView) {
-                        final CellLayoutChildren children = dropTargetLayout.getChildrenLayout();
                         final CellLayout cellLayout = dropTargetLayout;
                         // We post this call so that the widget has a chance to be placed
                         // in its final location
@@ -2361,10 +2478,21 @@
                         final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;
                         AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();
                         if (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
+                            final Runnable resizeRunnable = new Runnable() {
+                                public void run() {
+                                    DragLayer dragLayer = (DragLayer)
+                                            mLauncher.findViewById(R.id.drag_layer);
+                                    dragLayer.addResizeFrame(info, hostView,
+                                            cellLayout);
+                                }
+                            };
                             post(new Runnable() {
                                 public void run() {
-                                    children.addResizeFrame(info, hostView, 
-                                            cellLayout);
+                                    if (!isPageMoving()) {
+                                        resizeRunnable.run();
+                                    } else {
+                                        mDelayedResizeRunnable = resizeRunnable;
+                                    }
                                 }
                             });
                         }
@@ -2378,14 +2506,30 @@
 
             final CellLayout parent = (CellLayout) cell.getParent().getParent();
 
+            int loc[] = new int[2];
+            getViewLocationRelativeToSelf(dragView, loc);
+
             // Prepare it to be animated into its new position
             // This must be called after the view has been re-parented
-            setPositionForDropAnimation(dragView, originX, originY, parent, cell);
+            setPositionForDropAnimation(dragView, loc[0], loc[1], parent, cell);
             boolean animateDrop = !mWasSpringLoadedOnDragExit;
             parent.onDropChild(cell, animateDrop);
         }
     }
 
+    private void getViewLocationRelativeToSelf(View v, int[] location) {
+        getLocationOnScreen(location);
+        int x = location[0];
+        int y = location[1];
+
+        v.getLocationOnScreen(location);
+        int vX = location[0];
+        int vY = location[1];
+
+        location[0] = vX - x;
+        location[1] = vY - y;
+    }
+
     public void onDragEnter(DragSource source, int x, int y, int xOffset,
             int yOffset, DragView dragView, Object dragInfo) {
         mDragTargetLayout = null; // Reset the drag state
@@ -2614,11 +2758,11 @@
        xy[1] -= (mScrollY - v.getTop());
    }
 
-    static private float squaredDistance(float[] point1, float[] point2) {
+   static private float squaredDistance(float[] point1, float[] point2) {
         float distanceX = point1[0] - point2[0];
         float distanceY = point2[1] - point2[1];
         return distanceX * distanceX + distanceY * distanceY;
-    }
+   }
 
     /*
      *
@@ -2716,38 +2860,79 @@
         return bestMatchingScreen;
     }
 
+    // This is used to compute the visual center of the dragView. This point is then
+    // used to visualize drop locations and determine where to drop an item. The idea is that
+    // the visual center represents the user's interpretation of where the item is, and hence
+    // is the appropriate point to use when determining drop location.
+    private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,
+            DragView dragView, float[] recycle) {
+        float res[];
+        if (recycle == null) {
+            res = new float[2];
+        } else {
+            res = recycle;
+        }
+
+        // First off, the drag view has been shifted in a way that is not represented in the
+        // x and y values or the x/yOffsets. Here we account for that shift.
+        x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);
+        y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
+
+        // These represent the visual top and left of drag view if a dragRect was provided.
+        // If a dragRect was not provided, then they correspond to the actual view left and
+        // top, as the dragRect is in that case taken to be the entire dragView.
+        // R.dimen.dragViewOffsetY.
+        int left = x - xOffset;
+        int top = y - yOffset;
+
+        // In order to find the visual center, we shift by half the dragRect
+        res[0] = left + dragView.getDragRegion().width() / 2;
+        res[1] = top + dragView.getDragRegion().height() / 2;
+
+        return res;
+    }
+
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
         // When touch is inside the scroll area, skip dragOver actions for the current screen
         if (!mInScrollArea) {
             CellLayout layout;
-            int originX = x - xOffset;
-            int originY = y - yOffset;
+            int left = x - xOffset;
+            int top = y - yOffset;
+
+            mDragViewVisualCenter = getDragViewVisualCenter(x, y, xOffset, yOffset, dragView,
+                    mDragViewVisualCenter);
+
             boolean shrunken = mIsSmall || mIsInUnshrinkAnimation;
             if (shrunken) {
                 mLastDragView = dragView;
-                mLastDragOriginX = originX;
-                mLastDragOriginY = originY;
+                mLastDragOriginX = left;
+                mLastDragOriginY = top;
                 mLastDragXOffset = xOffset;
                 mLastDragYOffset = yOffset;
-                layout = findMatchingPageForDragOver(dragView, originX, originY, xOffset, yOffset);
+                layout = findMatchingPageForDragOver(dragView, left, top, xOffset, yOffset);
 
-                if (layout != mDragTargetLayout) {
+                if (layout != null && layout != mDragTargetLayout) {
                     if (mDragTargetLayout != null) {
                         mDragTargetLayout.setIsDragOverlapping(false);
                         mSpringLoadedDragController.onDragExit();
                     }
                     mDragTargetLayout = layout;
-                    // In spring-loaded mode, we still want the user to be able to hover over a
-                    // full screen (which is traditionally set to not accept drops) if they want to
-                    // get to pages beyond the screen that is full.
-                    boolean allowDragOver = (mDragTargetLayout != null) &&
-                            (mDragTargetLayout.getAcceptsDrops() ||
-                                    (mShrinkState == ShrinkState.SPRING_LOADED));
-                    if (allowDragOver) {
-                        mDragTargetLayout.setIsDragOverlapping(true);
-                        mSpringLoadedDragController.onDragEnter(
-                                mDragTargetLayout, mShrinkState == ShrinkState.SPRING_LOADED);
+
+                    // Workaround the fact that we don't actually want spring-loaded mode in phone
+                    // UI yet.
+                    if (LauncherApplication.isScreenLarge()) {
+                        // In spring-loaded mode, we still want the user to be able to hover over a
+                        // full screen (which is traditionally set to not accept drops) if they want
+                        // to get to pages beyond the screen that is full.
+                        boolean allowDragOver = (mDragTargetLayout != null) &&
+                                (mDragTargetLayout.getAcceptsDrops() ||
+                                        (mShrinkState == ShrinkState.SPRING_LOADED));
+                        if (allowDragOver) {
+                            mDragTargetLayout.setIsDragOverlapping(true);
+                            mSpringLoadedDragController.onDragEnter(
+                                    mDragTargetLayout, mShrinkState == ShrinkState.SPRING_LOADED);
+                        }
                     }
                 }
             } else {
@@ -2776,35 +2961,23 @@
                     }
                 }
 
-                if (source instanceof AllAppsPagedView) {
-                    // This is a hack to fix the point used to determine which cell an icon from
-                    // the all apps screen is over
-                    if (item != null && item.spanX == 1 && layout != null) {
-                        int dragRegionLeft = (dragView.getWidth() - layout.getCellWidth()) / 2;
-
-                        originX += dragRegionLeft - dragView.getDragRegionLeft();
-                        if (dragView.getDragRegionWidth() != layout.getCellWidth()) {
-                            dragView.setDragRegion(dragView.getDragRegionLeft(),
-                                    dragView.getDragRegionTop(),
-                                    layout.getCellWidth(),
-                                    dragView.getDragRegionHeight());
-                        }
-                    }
-                } else if (source == this) {
-                    // When dragging from the workspace, the drag view is slightly bigger than
-                    // the original view, and offset vertically. Adjust to account for this.
-                    final View origView = mDragInfo.cell;
-                    originX += (dragView.getMeasuredWidth() - origView.getWidth()) / 2;
-                    originY += (dragView.getMeasuredHeight() - origView.getHeight()) / 2
-                            + dragView.getOffsetY();
-                }
-
                 if (mDragTargetLayout != null) {
                     final View child = (mDragInfo == null) ? null : mDragInfo.cell;
-                    float[] localOrigin = { originX, originY };
-                    mapPointFromSelfToChild(mDragTargetLayout, localOrigin, null);
-                    mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
-                            (int) localOrigin[0], (int) localOrigin[1], item.spanX, item.spanY);
+                    // We want the point to be mapped to the dragTarget.
+                    mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
+                    ItemInfo info = (ItemInfo) dragInfo;
+
+                    if (!willCreateUserFolder(info, mDragTargetLayout,
+                            (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1])) {
+                        mIsDraggingOverIcon = false;
+                        mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
+                                (int) mDragViewVisualCenter[0],
+                                (int) mDragViewVisualCenter[1],
+                                item.spanX, item.spanY);
+                    } else if (!mIsDraggingOverIcon) {
+                        mIsDraggingOverIcon = true;
+                        mDragTargetLayout.clearDragOutlines();
+                    }
                 }
             }
         }
@@ -2850,6 +3023,11 @@
         return false;
     }
 
+    private void onDropExternal(int[] touchXY, Object dragInfo,
+            CellLayout cellLayout, boolean insertAtFirst) {
+        onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);
+    }
+
     /**
      * Drop an item that didn't originate on one of the workspace screens.
      * It may have come from Launcher (e.g. from all apps or customize), or it may have
@@ -2859,7 +3037,7 @@
      * to add an item to one of the workspace screens.
      */
     private void onDropExternal(int[] touchXY, Object dragInfo,
-            CellLayout cellLayout, boolean insertAtFirst) {
+            CellLayout cellLayout, boolean insertAtFirst, DragView dragView) {
         int screen = indexOfChild(cellLayout);
         if (dragInfo instanceof PendingAddItemInfo) {
             PendingAddItemInfo info = (PendingAddItemInfo) dragInfo;
@@ -2869,9 +3047,6 @@
                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                     mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) info, screen, touchXY);
                     break;
-                case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER:
-                    mLauncher.addLiveFolderFromDrop(info.componentName, screen, touchXY);
-                    break;
                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                     mLauncher.processShortcutFromDrop(info.componentName, screen, touchXY);
                     break;
@@ -2894,18 +3069,26 @@
                 view = mLauncher.createShortcut(R.layout.application, cellLayout,
                         (ShortcutInfo) info);
                 break;
-            case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER:
+            case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher,
-                        cellLayout, (UserFolderInfo) info, mIconCache);
+                        cellLayout, (FolderInfo) info, mIconCache);
                 break;
             default:
                 throw new IllegalStateException("Unknown item type: " + info.itemType);
             }
 
+            // If the item being dropped is a shortcut and the nearest drop cell also contains
+            // a shortcut, then create a folder with the two shortcuts.
+            if (touchXY != null && createUserFolderIfNecessary(view, cellLayout, touchXY[0],
+                  touchXY[1], true)) {
+                return;
+            }
+
             mTargetCell = new int[2];
             if (touchXY != null) {
                 // when dragging and dropping, just find the closest free spot
-                cellLayout.findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, mTargetCell);
+                mTargetCell = findNearestVacantArea(touchXY[0], touchXY[1], 1, 1, null, cellLayout,
+                        mTargetCell);
             } else {
                 cellLayout.findCellForSpan(mTargetCell, 1, 1);
             }
@@ -2915,6 +3098,15 @@
             cellLayout.onDropChild(view, animateDrop);
             cellLayout.animateDrop();
             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
+            cellLayout.getChildrenLayout().measureChild(view);
+
+            if (dragView != null) {
+                // we have the visual center of the drag view, we need to find the actual
+                // left and top of the dragView.
+                int loc[] = new int[2];
+                getViewLocationRelativeToSelf(dragView, loc);
+                setPositionForDropAnimation(dragView, loc[0], loc[1], cellLayout, view);
+            }
 
             LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
                     LauncherSettings.Favorites.CONTAINER_DESKTOP, screen,
@@ -2942,16 +3134,24 @@
 
     /**
      * Calculate the nearest cell where the given object would be dropped.
+     *
+     * pixelX and pixelY should be in the coordinate system of layout
      */
     private int[] findNearestVacantArea(int pixelX, int pixelY,
             int spanX, int spanY, View ignoreView, CellLayout layout, int[] recycle) {
-
-        int localPixelX = pixelX - (layout.getLeft() - mScrollX);
-        int localPixelY = pixelY - (layout.getTop() - mScrollY);
-
-        // Find the best target drop location
         return layout.findNearestVacantArea(
-                localPixelX, localPixelY, spanX, spanY, ignoreView, recycle);
+                pixelX, pixelY, spanX, spanY, ignoreView, recycle);
+    }
+
+    /**
+     * Calculate the nearest cell where the given object would be dropped.
+     *
+     * pixelX and pixelY should be in the coordinate system of layout
+     */
+    private int[] findNearestArea(int pixelX, int pixelY,
+            int spanX, int spanY, CellLayout layout, int[] recycle) {
+        return layout.findNearestArea(
+                pixelX, pixelY, spanX, spanY, recycle);
     }
 
     void setLauncher(Launcher launcher) {
@@ -3104,6 +3304,21 @@
         return null;
     }
 
+    void clearDropTargets() {
+        final int screenCount = getChildCount();
+
+        for (int i = 0; i < screenCount; i++) {
+            final CellLayout layoutParent = (CellLayout) getChildAt(i);
+            final ViewGroup layout = layoutParent.getChildrenLayout();
+            int childCount = layout.getChildCount();
+            for (int j = 0; j < childCount; j++) {
+                View v = layout.getChildAt(j);
+                if (v instanceof DropTarget) {
+                    mDragController.removeDropTarget((DropTarget) v);
+                }
+            }
+        }
+    }
 
     void removeItems(final ArrayList<ApplicationInfo> apps) {
         final int screenCount = getChildCount();
@@ -3144,8 +3359,8 @@
                                     }
                                 }
                             }
-                        } else if (tag instanceof UserFolderInfo) {
-                            final UserFolderInfo info = (UserFolderInfo) tag;
+                        } else if (tag instanceof FolderInfo) {
+                            final FolderInfo info = (FolderInfo) tag;
                             final ArrayList<ShortcutInfo> contents = info.contents;
                             final ArrayList<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(1);
                             final int contentsCount = contents.size();
@@ -3173,20 +3388,6 @@
                                 if (folder != null)
                                     folder.notifyDataSetChanged();
                             }
-                        } else if (tag instanceof LiveFolderInfo) {
-                            final LiveFolderInfo info = (LiveFolderInfo) tag;
-                            final Uri uri = info.uri;
-                            final ProviderInfo providerInfo = manager.resolveContentProvider(
-                                    uri.getAuthority(), 0);
-
-                            if (providerInfo != null) {
-                                for (String packageName: packageNames) {
-                                    if (packageName.equals(providerInfo.packageName)) {
-                                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                                        childrenToRemove.add(view);
-                                    }
-                                }
-                            }
                         } else if (tag instanceof LauncherAppWidgetInfo) {
                             final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
                             final AppWidgetProviderInfo provider =