Merge "Deduping shortcuts to app-shortcuts if they have a valid intent" into ub-launcher3-burnaby
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f43106f..b61b90c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -192,15 +192,6 @@
             </intent-filter>
         </receiver>
 
-        <!-- New user initialization; set up initial wallpaper -->
-        <receiver
-            android:name="com.android.launcher3.UserInitializeReceiver"
-            android:exported="false">
-            <intent-filter>
-                <action android:name="android.intent.action.USER_INITIALIZE" />
-            </intent-filter>
-        </receiver>
-
         <receiver android:name="com.android.launcher3.StartupReceiver" >
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/res/drawable/apps_list_bg.xml b/res/drawable/apps_list_bg.xml
index 64177c1..0e56684 100644
--- a/res/drawable/apps_list_bg.xml
+++ b/res/drawable/apps_list_bg.xml
@@ -14,7 +14,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:drawable="@drawable/apps_list_bg_inset"
-       android:insetLeft="@dimen/apps_container_inset"
-       android:insetRight="@dimen/apps_container_inset" />
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#ffffff" />
+    <corners
+        android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_list_search_bg.xml b/res/drawable/apps_list_search_bg.xml
index eda33a9..63c4d55 100644
--- a/res/drawable/apps_list_search_bg.xml
+++ b/res/drawable/apps_list_search_bg.xml
@@ -18,6 +18,6 @@
        android:shape="rectangle">
     <solid android:color="#ffffff" />
     <corners
-        android:topLeftRadius="3dp"
-        android:topRightRadius="3dp" />
+        android:bottomLeftRadius="2dp"
+        android:bottomRightRadius="2dp" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/apps_reveal_bg.xml b/res/drawable/apps_reveal_bg.xml
index 47c608f..07505a5 100644
--- a/res/drawable/apps_reveal_bg.xml
+++ b/res/drawable/apps_reveal_bg.xml
@@ -14,7 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:drawable="@drawable/apps_reveal_bg_inset"
-       android:insetLeft="@dimen/apps_container_inset"
-       android:insetRight="@dimen/apps_container_inset" />
\ No newline at end of file
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#ffffff" />
+    <corners android:radius="2dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_reveal_bg_inset.xml b/res/drawable/apps_reveal_bg_inset.xml
deleted file mode 100644
index 61f1c08..0000000
--- a/res/drawable/apps_reveal_bg_inset.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="#ffffff" />
-    <corners android:radius="3dp" />
-</shape>
\ No newline at end of file
diff --git a/res/drawable/apps_list_bg_inset.xml b/res/drawable/apps_search_bg.xml
similarity index 90%
rename from res/drawable/apps_list_bg_inset.xml
rename to res/drawable/apps_search_bg.xml
index 5ea7895..405e844 100644
--- a/res/drawable/apps_list_bg_inset.xml
+++ b/res/drawable/apps_search_bg.xml
@@ -18,6 +18,6 @@
        android:shape="rectangle">
     <solid android:color="#ffffff" />
     <corners
-        android:bottomLeftRadius="3dp"
-        android:bottomRightRadius="3dp" />
+        android:topLeftRadius="2dp"
+        android:topRightRadius="2dp" />
 </shape>
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index b13984a..d5dd91a 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -57,8 +57,8 @@
             android:id="@+id/overview_panel"
             android:visibility="gone" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 3cb338e..5a018c5 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -66,8 +66,8 @@
             android:id="@+id/search_drop_target_bar"
             layout="@layout/search_drop_target_bar" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout-sw600dp/apps_view.xml b/res/layout-sw600dp/apps_view.xml
index fba170b..e6e0ec3 100644
--- a/res/layout-sw600dp/apps_view.xml
+++ b/res/layout-sw600dp/apps_view.xml
@@ -19,7 +19,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:padding="@dimen/apps_container_inset"
-    android:background="@drawable/apps_customize_bg"
     android:descendantFocusability="afterDescendants">
     <include
         layout="@layout/apps_reveal_view"
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index a3d502c..a9601af 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -66,8 +66,8 @@
             android:layout_height="wrap_content"
             android:layout_gravity="center_horizontal" />
 
-        <include layout="@layout/apps_customize_pane"
-            android:id="@+id/apps_customize_pane"
+        <include layout="@layout/widgets_view"
+            android:id="@+id/widgets_view"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:visibility="invisible" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
deleted file mode 100644
index e42576f..0000000
--- a/res/layout/apps_customize_pane.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.AppsCustomizeTabHost
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:clipChildren="false">
-
-    <LinearLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        android:orientation="vertical">
-
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:clipChildren="false">
-            <FrameLayout
-                android:id="@+id/fake_page_container"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:clipChildren="false"
-                android:clipToPadding="false">
-                <FrameLayout
-                    android:id="@+id/fake_page"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:visibility="invisible"
-                    android:clipToPadding="false" />
-            </FrameLayout>
-            <com.android.launcher3.AppsCustomizePagedView
-                android:id="@+id/apps_customize_pane_content"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
-                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
-                launcher:maxGap="@dimen/workspace_max_gap"
-                launcher:pageIndicator="@+id/apps_customize_page_indicator" />
-        </FrameLayout>
-        <include
-            android:id="@+id/apps_customize_page_indicator"
-            layout="@layout/page_indicator"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center" />
-    </LinearLayout>
-</com.android.launcher3.AppsCustomizeTabHost>
diff --git a/res/layout/apps_customize_widget.xml b/res/layout/apps_customize_widget.xml
deleted file mode 100644
index a8344e3..0000000
--- a/res/layout/apps_customize_widget.xml
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<com.android.launcher3.PagedViewWidget
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_weight="1"
-    android:orientation="vertical"
-
-    android:background="@drawable/focusable_view_bg"
-    android:focusable="true">
-
-    <LinearLayout
-        android:orientation="horizontal"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1">
-        <FrameLayout
-            android:id="@+id/left_border"
-            android:layout_width="1dp"
-            android:layout_height="match_parent"
-            android:background="@color/widget_text_panel"
-            android:visibility="gone" />
-
-        <!-- The preview of the widget or shortcut. -->
-        <com.android.launcher3.PagedViewWidgetImageView
-            android:id="@+id/widget_preview"
-            style="@style/PagedViewWidgetImageView"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:paddingTop="@dimen/app_widget_preview_padding_top"
-            android:paddingEnd="@dimen/app_widget_preview_padding_right"
-            android:paddingRight="@dimen/app_widget_preview_padding_right"
-            android:scaleType="matrix" />
-        <FrameLayout
-            android:id="@+id/right_border"
-            android:layout_width="1dp"
-            android:layout_height="match_parent"
-            android:background="@color/widget_text_panel"
-            android:visibility="gone" />
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="@dimen/app_widget_preview_label_vertical_padding"
-        android:paddingBottom="@dimen/app_widget_preview_label_vertical_padding"
-        android:paddingLeft="@dimen/app_widget_preview_label_horizontal_padding"
-        android:paddingRight="@dimen/app_widget_preview_label_horizontal_padding"
-        android:background="@color/widget_text_panel"
-        android:orientation="horizontal">
-        <!-- The name of the widget. -->
-        <TextView
-            android:id="@+id/widget_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:gravity="start"
-            android:singleLine="true"
-            android:ellipsize="marquee"
-            android:fadingEdge="horizontal"
-
-            android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
-            android:textAlignment="viewStart"
-            android:fontFamily="sans-serif-condensed"
-            android:shadowRadius="2.0"
-            android:shadowColor="#B0000000" />
-
-        <!-- The original dimensions of the widget (can't be the same text as above due to different
-             style. -->
-        <TextView
-            android:id="@+id/widget_dims"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:layout_marginStart="5dp"
-            android:layout_weight="0"
-            android:gravity="start"
-
-            android:textColor="#FFFFFFFF"
-            android:textSize="12sp"
-            android:fontFamily="sans-serif-condensed"
-            android:shadowRadius="2.0"
-            android:shadowColor="#B0000000" />
-    </LinearLayout>
-
-
-</com.android.launcher3.PagedViewWidget>
diff --git a/res/layout/apps_list_row_view.xml b/res/layout/apps_list_row_view.xml
index 83c175b..e80285b 100644
--- a/res/layout/apps_list_row_view.xml
+++ b/res/layout/apps_list_row_view.xml
@@ -30,4 +30,4 @@
         android:textColor="@color/apps_view_section_text_color"
         android:textSize="@dimen/apps_view_section_text_size"
         android:focusable="false" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index 3e42f84..595c46c 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -25,8 +25,6 @@
         android:id="@+id/app_search_box"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginLeft="@dimen/apps_container_inset"
-        android:layout_marginRight="@dimen/apps_container_inset"
         android:padding="16dp"
         android:hint="@string/apps_view_search_bar_hint"
         android:maxLines="1"
@@ -37,7 +35,7 @@
         android:textColor="#4c4c4c"
         android:textColorHint="#9c9c9c"
         android:imeOptions="actionDone|flagNoExtractUi"
-        android:background="@drawable/apps_list_search_bg"
+        android:background="@drawable/apps_search_bg"
         android:elevation="4dp" />
     <com.android.launcher3.AppsContainerRecyclerView
         android:id="@+id/apps_list_view"
@@ -48,6 +46,5 @@
         android:paddingBottom="12dp"
         android:clipToPadding="false"
         android:focusable="true"
-        android:descendantFocusability="afterDescendants"
-        android:background="@drawable/apps_list_bg" />
+        android:descendantFocusability="afterDescendants" />
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/apps_reveal_view.xml b/res/layout/apps_reveal_view.xml
index bc93359..2951ea4 100644
--- a/res/layout/apps_reveal_view.xml
+++ b/res/layout/apps_reveal_view.xml
@@ -21,5 +21,4 @@
     android:layout_gravity="center"
     android:elevation="15dp"
     android:visibility="invisible"
-    android:background="@drawable/apps_reveal_bg"
     android:focusable="false" />
\ No newline at end of file
diff --git a/res/layout/apps_view.xml b/res/layout/apps_view.xml
index 86d67e1..7f09f77 100644
--- a/res/layout/apps_view.xml
+++ b/res/layout/apps_view.xml
@@ -21,9 +21,6 @@
     android:id="@+id/apps_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="@dimen/apps_container_inset"
-    android:paddingBottom="@dimen/apps_container_inset"
-    android:background="@drawable/apps_customize_bg"
     android:descendantFocusability="afterDescendants">
     <include
         layout="@layout/apps_reveal_view"
diff --git a/res/layout/page_indicator_marker.xml b/res/layout/page_indicator_marker.xml
index 686d275..564a958 100644
--- a/res/layout/page_indicator_marker.xml
+++ b/res/layout/page_indicator_marker.xml
@@ -16,8 +16,8 @@
 <com.android.launcher3.PageIndicatorMarker
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="16dp"
-    android:layout_height="16dp"
+    android:layout_width="12dp"
+    android:layout_height="12dp"
     android:layout_gravity="center_vertical">
     <ImageView
         android:id="@+id/inactive"
diff --git a/res/layout/user_folder.xml b/res/layout/user_folder.xml
index 7a4d5e8..cd3a051 100644
--- a/res/layout/user_folder.xml
+++ b/res/layout/user_folder.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2008 The Android Open Source Project
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -34,30 +34,44 @@
             android:layout_width="20dp"
             android:layout_height="20dp" />
 
-        <com.android.launcher3.FolderCellLayout
+        <com.android.launcher3.FolderPagedView
             android:id="@+id/folder_content"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:cacheColorHint="#ff333333"
-            android:hapticFeedbackEnabled="false" />
+            launcher:pageIndicator="@+id/folder_page_indicator" />
     </FrameLayout>
 
-    <com.android.launcher3.FolderEditText
-        android:id="@+id/folder_name"
+    <LinearLayout
+        android:id="@+id/folder_footer"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="#00000000"
-        android:fontFamily="sans-serif-condensed"
-        android:gravity="center_horizontal"
-        android:hint="@string/folder_hint_text"
-        android:imeOptions="flagNoExtractUi"
-        android:paddingBottom="@dimen/folder_name_padding"
-        android:paddingTop="@dimen/folder_name_padding"
-        android:singleLine="true"
-        android:textColor="#ff777777"
-        android:textColorHighlight="#ffCCCCCC"
-        android:textColorHint="#ff808080"
-        android:textCursorDrawable="@null"
-        android:textSize="14sp" />
+        android:orientation="vertical" >
+
+        <include
+            android:id="@+id/folder_page_indicator"
+            android:layout_width="wrap_content"
+            android:layout_height="12dp"
+            android:layout_gravity="center_horizontal"
+            layout="@layout/page_indicator" />
+
+        <com.android.launcher3.FolderEditText
+            android:id="@+id/folder_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:background="#00000000"
+            android:fontFamily="sans-serif-condensed"
+            android:gravity="center_horizontal"
+            android:hint="@string/folder_hint_text"
+            android:imeOptions="flagNoExtractUi"
+            android:paddingBottom="@dimen/folder_name_padding"
+            android:paddingTop="@dimen/folder_name_padding"
+            android:singleLine="true"
+            android:textColor="#ff777777"
+            android:textColorHighlight="#ffCCCCCC"
+            android:textColorHint="#ff808080"
+            android:textCursorDrawable="@null"
+            android:textSize="14sp" />
+    </LinearLayout>
 
 </com.android.launcher3.Folder>
\ No newline at end of file
diff --git a/res/layout/user_folder_scroll.xml b/res/layout/user_folder_scroll.xml
deleted file mode 100644
index 12e5097..0000000
--- a/res/layout/user_folder_scroll.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher3.Folder xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:launcher="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="@drawable/quantum_panel"
-    android:orientation="vertical" >
-
-    <FrameLayout
-        android:id="@+id/folder_content_wrapper"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" >
-
-        <!-- Actual size of the indicator doesn't matter as it is scaled to match the view size -->
-
-        <com.android.launcher3.FocusIndicatorView
-            android:id="@+id/focus_indicator"
-            android:layout_width="20dp"
-            android:layout_height="20dp" />
-
-        <com.android.launcher3.FolderPagedView
-            android:id="@+id/folder_content"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            launcher:pageIndicator="@+id/folder_page_indicator" />
-    </FrameLayout>
-
-    <LinearLayout
-        android:id="@+id/folder_footer"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:paddingStart="12dp"
-        android:paddingEnd="8dp" >
-
-        <com.android.launcher3.FolderEditText
-            android:id="@+id/folder_name"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:layout_weight="1"
-            android:background="#00000000"
-            android:fontFamily="sans-serif-condensed"
-            android:gravity="start"
-            android:hint="@string/folder_hint_text"
-            android:imeOptions="flagNoExtractUi"
-            android:paddingBottom="@dimen/folder_name_padding"
-            android:paddingTop="@dimen/folder_name_padding"
-            android:singleLine="true"
-            android:textColor="#ff777777"
-            android:textColorHighlight="#ffCCCCCC"
-            android:textColorHint="#ff808080"
-            android:textCursorDrawable="@null"
-            android:textSize="14sp" />
-
-        <include
-            android:id="@+id/folder_page_indicator"
-            android:layout_width="wrap_content"
-            android:layout_height="12dp"
-            android:layout_gravity="top"
-            android:layout_marginTop="5dp"
-            layout="@layout/page_indicator" />
-
-        <LinearLayout
-            android:id="@+id/folder_sort"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_gravity="center_vertical"
-            android:gravity="end|center_vertical" >
-
-            <TextView
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="8dp"
-                android:text="@string/sort_alphabetical"
-                android:textColor="#ff777777"
-                android:textSize="14sp" />
-
-            <Switch
-                android:id="@+id/folder_sort_switch"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:clickable="false"
-                android:duplicateParentState="true"
-                android:focusable="false" />
-        </LinearLayout>
-    </LinearLayout>
-
-</com.android.launcher3.Folder>
\ No newline at end of file
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
new file mode 100644
index 0000000..9e91f67
--- /dev/null
+++ b/res/layout/widget_cell.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.widget.WidgetCell
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:background="@drawable/focusable_view_bg"
+    android:focusable="true">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/widget_preview_label_vertical_padding"
+        android:paddingBottom="@dimen/widget_preview_label_vertical_padding"
+        android:paddingLeft="@dimen/widget_preview_label_horizontal_padding"
+        android:paddingRight="@dimen/widget_preview_label_horizontal_padding"
+        android:orientation="horizontal">
+
+        <!-- The name of the widget. -->
+        <TextView
+            android:id="@+id/widget_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="start"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+
+            android:textColor="#FFFFFFFF"
+            android:textSize="12sp"
+            android:textAlignment="viewStart"
+            android:fontFamily="sans-serif-condensed"
+            android:shadowRadius="2.0"
+            android:shadowColor="#B0000000" />
+
+        <!-- The original dimensions of the widget (can't be the same text as above due to different
+             style. -->
+        <TextView
+            android:id="@+id/widget_dims"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginStart="5dp"
+            android:layout_marginLeft="5dp"
+            android:layout_weight="0"
+            android:gravity="start"
+
+            android:textColor="#FFFFFFFF"
+            android:textSize="12sp"
+            android:fontFamily="sans-serif-condensed"
+            android:shadowRadius="2.0"
+            android:shadowColor="#B0000000" />
+    </LinearLayout>
+
+    <!-- The image of the widget. -->
+    <com.android.launcher3.widget.WidgetImageView
+        android:id="@+id/widget_preview"
+        style="@style/WidgetImageView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="@dimen/widget_preview_padding_top"
+        android:paddingEnd="@dimen/widget_preview_padding_right"
+        android:paddingRight="@dimen/widget_preview_padding_right"
+        android:scaleType="matrix" />
+
+</com.android.launcher3.widget.WidgetCell>
diff --git a/res/layout/widgets_list_row_view.xml b/res/layout/widgets_list_row_view.xml
new file mode 100644
index 0000000..017b450
--- /dev/null
+++ b/res/layout/widgets_list_row_view.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/widgets_cell_list_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:layout_marginLeft="8dp"
+    android:layout_marginRight="8dp"
+    android:layout_marginTop="8dp"
+    android:layout_marginBottom="8dp"
+    android:focusable="true"
+    android:background="@drawable/focusable_view_bg"
+    android:descendantFocusability="afterDescendants">
+
+    <!-- Section info -->
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:focusable="true"
+        android:background="@drawable/focusable_view_bg"
+        android:descendantFocusability="afterDescendants">
+        <ImageView
+            android:id="@+id/section_image"
+            android:layout_width="@dimen/widget_section_height"
+            android:layout_height="@dimen/widget_section_height"
+            android:paddingLeft="@dimen/widget_section_icon_padding"
+            android:paddingRight="@dimen/widget_section_icon_padding"
+            android:paddingTop="@dimen/widget_section_icon_padding"
+            android:paddingBottom="@dimen/widget_section_icon_padding"
+            android:background="@color/widget_text_panel"
+        />
+        <TextView
+            android:id="@+id/section"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/widget_section_height"
+            android:paddingTop="8dp"
+            android:paddingLeft="16dp"
+            android:paddingRight="16dp"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:gravity="start|center_vertical"
+            android:textColor="@color/widgets_view_section_text_color"
+            android:background="@color/widget_text_panel"
+            android:textSize="20sp"
+            android:focusable="false" />
+    </LinearLayout>
+
+    <!--  Widget list -->
+    <RelativeLayout 
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="end"
+        >
+        <!-- TODO(hyunyoungs): replace the indicator with actual assets. -->
+        <FrameLayout
+            android:id="@+id/scrollable_indicator"
+            android:layout_gravity="center_vertical"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/ic_pageindicator_default"
+            android:visibility="invisible"
+            />
+        <HorizontalScrollView
+            android:id="@+id/widgets_scroll_container"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/widget_cell_height"
+            android:scrollbars="none" >
+            <LinearLayout
+                android:id="@+id/widgets_cell_list"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal" />
+        </HorizontalScrollView>
+    </RelativeLayout>
+</LinearLayout>
diff --git a/res/layout/widgets_view.xml b/res/layout/widgets_view.xml
new file mode 100644
index 0000000..8e7ed16
--- /dev/null
+++ b/res/layout/widgets_view.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- The top and bottom paddings are defined in this container, but since we want
+     the list view to span the full width (for touch interception purposes), we
+     will bake the left/right padding into that view's background itself. -->
+<com.android.launcher3.widget.WidgetsContainerView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/widgets_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="@dimen/widget_container_inset"
+    android:paddingBottom="@dimen/widget_container_inset"
+    android:descendantFocusability="afterDescendants">
+
+    <!-- Temporary until finalizing on animation.  -->
+    <include
+        android:id="@+id/widgets_reveal_view"
+        layout="@layout/apps_reveal_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center" />
+
+    <LinearLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        android:orientation="vertical">
+
+        <android.support.v7.widget.RecyclerView
+                android:id="@+id/widgets_list_view"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@drawable/quantum_panel_dark"/>
+    </LinearLayout>
+</com.android.launcher3.widget.WidgetsContainerView>
\ No newline at end of file
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 1b34181..06a9984 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -18,9 +18,4 @@
 <!-- QSB -->
     <dimen name="toolbar_button_vertical_padding">8dip</dimen>
     <dimen name="toolbar_button_horizontal_padding">0dip</dimen>
-
-<!-- AppsCustomize -->
-    <dimen name="apps_customize_tab_bar_height">42dp</dimen>
-    <integer name="apps_customize_widget_cell_count_x">3</integer>
-    <integer name="apps_customize_widget_cell_count_y">2</integer>
 </resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index d80f18c..13a1f40 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -24,11 +24,9 @@
     <dimen name="apps_view_row_height">76dp</dimen>
 
 <!-- AppsCustomize -->
-    <dimen name="apps_customize_tab_bar_height">60dp</dimen>
-    <dimen name="apps_customize_tab_bar_margin_top">8dp</dimen>
-    <dimen name="app_widget_preview_label_margin_top">8dp</dimen>
-    <dimen name="app_widget_preview_label_margin_left">@dimen/app_widget_preview_padding_left</dimen>
-    <dimen name="app_widget_preview_label_margin_right">@dimen/app_widget_preview_padding_right</dimen>
+    <dimen name="widget_preview_label_margin_top">8dp</dimen>
+    <dimen name="widget_preview_label_margin_left">@dimen/widget_preview_padding_left</dimen>
+    <dimen name="widget_preview_label_margin_right">@dimen/widget_preview_padding_right</dimen>
 
 <!-- Cling -->
     <dimen name="cling_migration_logo_height">400dp</dimen>
diff --git a/res/values-v17/styles.xml b/res/values-v17/styles.xml
index 11d2a1f..229375f 100644
--- a/res/values-v17/styles.xml
+++ b/res/values-v17/styles.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-    <style name="PagedViewWidgetImageView">
-        <item name="android:paddingStart">@dimen/app_widget_preview_padding_left</item>
+    <style name="WidgetImageView">
+        <item name="android:paddingStart">@dimen/widget_preview_padding_left</item>
     </style>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 590a887..3a06bd9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -36,8 +36,10 @@
     <color name="outline_color">#FFFFFFFF</color>
     <color name="widget_text_panel">#FF374248</color>
 
-<!-- Apps view -->
+    <!-- Apps view -->
     <color name="apps_view_scrollbar_thumb_color">#009688</color>
     <color name="apps_view_section_text_color">#009688</color>
 
+    <!-- Widgetss view -->
+    <color name="widgets_view_section_text_color">#009688</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 735373d..101b755 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -50,6 +50,8 @@
     <dimen name="apps_container_width">0dp</dimen>
     <dimen name="apps_container_height">0dp</dimen>
     <dimen name="apps_container_inset">8dp</dimen>
+    <!-- Note: This needs to match the fixed insets for the search box -->
+    <dimen name="apps_container_fixed_bounds_inset">8dp</dimen>
     <dimen name="apps_grid_view_start_margin">52dp</dimen>
     <dimen name="apps_view_row_height">64dp</dimen>
     <dimen name="apps_view_section_text_size">24sp</dimen>
@@ -60,18 +62,9 @@
     <dimen name="apps_view_fast_scroll_text_size">40dp</dimen>
 
 <!-- AllApps/Customize/AppsCustomize -->
-    <!-- The height of the tab bar - if this changes, we should update the
-         external icon width/height above to compensate -->
-    <dimen name="apps_customize_tab_bar_height">52dp</dimen>
-    <dimen name="apps_customize_tab_bar_margin_top">0dp</dimen>
     <dimen name="app_icon_size">48dp</dimen>
     <dimen name="apps_customize_horizontal_padding">0dp</dimen>
 
-    <!-- The AppsCustomize page indicator -->
-    <dimen name="apps_customize_page_indicator_height">12dp</dimen>
-    <dimen name="apps_customize_page_indicator_margin">4dp</dimen>
-    <dimen name="apps_customize_page_indicator_offset">16dp</dimen>
-
     <!-- Drag padding to add to the bottom of drop targets -->
     <dimen name="drop_target_drag_padding">14dp</dimen>
     <dimen name="drop_target_text_size">14sp</dimen>
@@ -85,12 +78,19 @@
           should be. If 0, it will not be scaled at all. -->
     <dimen name="dragViewScale">12dp</dimen>
 
-    <!-- Padding applied to AppWidget previews -->
-    <dimen name="app_widget_preview_padding_left">16dp</dimen>
-    <dimen name="app_widget_preview_padding_right">16dp</dimen>
-    <dimen name="app_widget_preview_padding_top">32dp</dimen>
-    <dimen name="app_widget_preview_label_vertical_padding">8dp</dimen>
-    <dimen name="app_widget_preview_label_horizontal_padding">8dp</dimen>
+<!-- Widget tray -->
+    <dimen name="widget_container_inset">8dp</dimen>
+    <dimen name="widget_preview_size">140dp</dimen>
+    <dimen name="widget_preview_padding_left">16dp</dimen>
+    <dimen name="widget_preview_padding_right">16dp</dimen>
+    <dimen name="widget_preview_padding_top">8dp</dimen>
+    <dimen name="widget_preview_label_vertical_padding">8dp</dimen>
+    <dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
+
+    <dimen name="widget_section_height">52dp</dimen>
+    <dimen name="widget_section_icon_padding">8dp</dimen>
+
+    <dimen name="widget_cell_height">160dp</dimen>
 
     <!-- Padding applied to shortcut previews -->
     <dimen name="shortcut_preview_padding_left">0dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 77798f1..94efebc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -91,8 +91,8 @@
     </style>
 
     <!-- Overridden in device overlays -->
-    <style name="PagedViewWidgetImageView">
-        <item name="android:paddingLeft">@dimen/app_widget_preview_padding_left</item>
+    <style name="WidgetImageView">
+        <item name="android:paddingLeft">@dimen/widget_preview_padding_left</item>
     </style>
 
 </resources>
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index a1391b2..7c6b066 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -43,7 +43,7 @@
     /**
      * A bitmap version of the application icon.
      */
-    Bitmap iconBitmap;
+    public Bitmap iconBitmap;
 
     /**
      * Indicates whether we're using a low res icon
@@ -55,7 +55,7 @@
      */
     long firstInstallTime;
 
-    ComponentName componentName;
+    public ComponentName componentName;
 
     static final int DOWNLOADED_FLAG = 1;
     static final int UPDATED_SYSTEM_APP_FLAG = 2;
@@ -121,12 +121,15 @@
                 + " user=" + user + ")";
     }
 
+    /**
+     * Helper method used for debugging.
+     */
     public static void dumpApplicationInfoList(String tag, String label, ArrayList<AppInfo> list) {
         Log.d(tag, label + " size=" + list.size());
         for (AppInfo info: list) {
-            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap="
-                    + info.iconBitmap + " firstInstallTime="
-                    + info.firstInstallTime);
+            Log.d(tag, "   title=\"" + info.title + "\" iconBitmap=" + info.iconBitmap 
+                    + " firstInstallTime=" + info.firstInstallTime
+                    + " componentName=" + info.componentName.getPackageName());
         }
     }
 
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index c93bacf..bb2aeb0 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -196,13 +196,27 @@
                 }
                 break;
             case MotionEvent.ACTION_UP:
+                ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
+                float dx = ev.getX() - mDownX;
+                float dy = ev.getY() - mDownY;
+                float distance = (float) Math.sqrt(dx * dx + dy * dy);
+                if (distance < viewConfig.getScaledTouchSlop()) {
+                    Rect backgroundPadding = new Rect();
+                    getBackground().getPadding(backgroundPadding);
+                    boolean isOutsideBounds = ev.getX() < backgroundPadding.left ||
+                            ev.getX() > (getWidth() - backgroundPadding.right);
+                    if (isOutsideBounds) {
+                        Launcher launcher = (Launcher) getContext();
+                        launcher.showWorkspace(true);
+                    }
+                }
+                // Fall through
             case MotionEvent.ACTION_CANCEL:
                 mDraggingFastScroller = false;
                 animateFastScrollerVisibility(false);
                 break;
         }
         return mDraggingFastScroller;
-
     }
 
     /**
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index 2de45cb..559f6eb 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -19,6 +19,7 @@
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.InsetDrawable;
 import android.support.v7.widget.RecyclerView;
 import android.text.Editable;
 import android.text.TextWatcher;
@@ -26,12 +27,13 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.EditText;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
-
 import com.android.launcher3.util.Thunk;
 
 import java.util.List;
@@ -59,8 +61,13 @@
     private EditText mSearchBar;
     private int mNumAppsPerRow;
     private Point mLastTouchDownPos = new Point();
-    private Rect mPadding = new Rect();
+    private Rect mInsets = new Rect();
+    private Rect mFixedBounds = new Rect();
     private int mContentMarginStart;
+    // Normal container insets
+    private int mContainerInset;
+    // Fixed bounds container insets
+    private int mFixedBoundsContainerInset;
 
     public AppsContainerView(Context context) {
         this(context, null);
@@ -76,6 +83,10 @@
         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
         Resources res = context.getResources();
 
+        mContainerInset = context.getResources().getDimensionPixelSize(
+                R.dimen.apps_container_inset);
+        mFixedBoundsContainerInset = context.getResources().getDimensionPixelSize(
+                R.dimen.apps_container_fixed_bounds_inset);
         mLauncher = (Launcher) context;
         mApps = new AlphabeticalAppsList(context);
         if (USE_LAYOUT == GRID_LAYOUT) {
@@ -126,6 +137,15 @@
     }
 
     /**
+     * Hides the search bar
+     */
+    public void hideSearchBar() {
+        mSearchBar.setVisibility(View.GONE);
+        updateBackgrounds();
+        updatePaddings();
+    }
+
+    /**
      * Scrolls this list view to the top.
      */
     public void scrollToTop() {
@@ -154,45 +174,58 @@
             ((AppsGridAdapter) mAdapter).setRtl(isRtl);
         }
         mSearchBar = (EditText) findViewById(R.id.app_search_box);
-        mSearchBar.addTextChangedListener(this);
-        mSearchBar.setOnEditorActionListener(this);
+        if (mSearchBar != null) {
+            mSearchBar.addTextChangedListener(this);
+            mSearchBar.setOnEditorActionListener(this);
+        }
         mAppsListView = (AppsContainerRecyclerView) findViewById(R.id.apps_list_view);
         mAppsListView.setApps(mApps);
         mAppsListView.setNumAppsPerRow(mNumAppsPerRow);
         mAppsListView.setLayoutManager(mLayoutManager);
         mAppsListView.setAdapter(mAdapter);
         mAppsListView.setHasFixedSize(true);
-        if (isRtl) {
-            mAppsListView.setPadding(
-                    mAppsListView.getPaddingLeft(),
-                    mAppsListView.getPaddingTop(),
-                    mAppsListView.getPaddingRight() + mContentMarginStart,
-                    mAppsListView.getPaddingBottom());
-        } else {
-            mAppsListView.setPadding(
-                    mAppsListView.getPaddingLeft() + mContentMarginStart,
-                    mAppsListView.getPaddingTop(),
-                    mAppsListView.getPaddingRight(),
-                    mAppsListView.getPaddingBottom());
-        }
         if (mItemDecoration != null) {
             mAppsListView.addItemDecoration(mItemDecoration);
         }
-        mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
-                getPaddingBottom());
+        updateBackgrounds();
+        updatePaddings();
     }
 
     @Override
     public void setInsets(Rect insets) {
-        setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
-                mPadding.right + insets.right, mPadding.bottom + insets.bottom);
+        mInsets.set(insets);
+        updatePaddings();
+    }
+
+    /**
+     * Sets the fixed bounds for this Apps view.
+     */
+    public void setFixedBounds(Context context, Rect fixedBounds) {
+        if (!fixedBounds.isEmpty() && !fixedBounds.equals(mFixedBounds)) {
+            // Update the number of items in the grid
+            LauncherAppState app = LauncherAppState.getInstance();
+            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+            if (grid.updateAppsViewNumCols(context.getResources(), fixedBounds.width())) {
+                mNumAppsPerRow = grid.appsViewNumCols;
+                mAppsListView.setNumAppsPerRow(mNumAppsPerRow);
+                if (USE_LAYOUT == GRID_LAYOUT) {
+                    ((AppsGridAdapter) mAdapter).setNumAppsPerRow(mNumAppsPerRow);
+                }
+            }
+
+            mFixedBounds.set(fixedBounds);
+        }
+        updateBackgrounds();
+        updatePaddings();
     }
 
     @Override
     public boolean onTouch(View v, MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN ||
-                ev.getAction() == MotionEvent.ACTION_MOVE) {
-            mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+        switch (ev.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_MOVE:
+                mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+                break;
         }
         return false;
     }
@@ -359,7 +392,9 @@
     public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
         if (!toWorkspace) {
             // Disable the focus so that the search bar doesn't get focus
-            mSearchBar.setFocusableInTouchMode(false);
+            if (mSearchBar != null) {
+                mSearchBar.setFocusableInTouchMode(false);
+            }
         }
     }
 
@@ -375,11 +410,69 @@
 
     @Override
     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        if (toWorkspace) {
-            // Clear the search bar
-            mSearchBar.setText("");
-        } else {
-            mSearchBar.setFocusableInTouchMode(true);
+        if (mSearchBar != null) {
+            if (toWorkspace) {
+                // Clear the search bar
+                mSearchBar.setText("");
+            } else {
+                mSearchBar.setFocusableInTouchMode(true);
+            }
         }
     }
+
+    /**
+     * Update the padding of the Apps view and children.  To ensure that the RecyclerView has the
+     * full width to handle touches right to the edge of the screen, we only apply the top and
+     * bottom padding to the AppsContainerView and then the left/right padding on the RecyclerView
+     * itself.  In particular, the left/right padding is applied to the background of the view,
+     * and then additionally inset by the start margin.
+     */
+    private void updatePaddings() {
+        boolean isRtl = (getResources().getConfiguration().getLayoutDirection() ==
+                LAYOUT_DIRECTION_RTL);
+        boolean hasSearchBar = (mSearchBar != null) && (mSearchBar.getVisibility() == View.VISIBLE);
+
+        if (mFixedBounds.isEmpty()) {
+            // If there are no fixed bounds, then use the default padding and insets
+            setPadding(mInsets.left, mContainerInset + mInsets.top, mInsets.right,
+                    mContainerInset + mInsets.bottom);
+        } else {
+            // If there are fixed bounds, then we update the padding to reflect the fixed bounds.
+            setPadding(mFixedBounds.left, mFixedBounds.top + mFixedBoundsContainerInset,
+                    getMeasuredWidth() - mFixedBounds.right,
+                    mInsets.bottom + mFixedBoundsContainerInset);
+        }
+
+        // Update the apps recycler view
+        int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset;
+        if (isRtl) {
+            mAppsListView.setPadding(inset, inset, inset + mContentMarginStart, inset);
+        } else {
+            mAppsListView.setPadding(inset + mContentMarginStart, inset, inset, inset);
+        }
+
+        // Update the search bar
+        if (hasSearchBar) {
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSearchBar.getLayoutParams();
+            lp.leftMargin = lp.rightMargin = inset;
+        }
+    }
+
+    /**
+     * Update the background of the Apps view and children.
+     */
+    private void updateBackgrounds() {
+        int inset = mFixedBounds.isEmpty() ? mContainerInset : mFixedBoundsContainerInset;
+        boolean hasSearchBar = (mSearchBar != null) && (mSearchBar.getVisibility() == View.VISIBLE);
+
+        // Update the background of the reveal view and list to be inset with the fixed bound
+        // insets instead of the default insets
+        mAppsListView.setBackground(new InsetDrawable(
+                getContext().getResources().getDrawable(
+                        hasSearchBar ? R.drawable.apps_list_search_bg : R.drawable.apps_list_bg),
+                inset, 0, inset, 0));
+        getRevealView().setBackground(new InsetDrawable(
+                getContext().getResources().getDrawable(R.drawable.apps_reveal_bg),
+                inset, 0, inset, 0));
+    }
 }
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
deleted file mode 100644
index 58bcf1d..0000000
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.appwidget.AppWidgetHostView;
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.GridLayout;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.FocusHelper.PagedViewKeyListener;
-import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.util.Thunk;
-
-import java.util.ArrayList;
-
-/**
- * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
- */
-public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
-        View.OnClickListener, DragSource,
-        PagedViewWidget.ShortPressListener, LauncherTransitionable {
-    static final String TAG = "AppsCustomizePagedView";
-
-    private static Rect sTmpRect = new Rect();
-    private static final int[] sTempPosArray = new int[2];
-
-    /**
-     * The different content types that this paged view can show.
-     */
-    public enum ContentType {
-        Widgets
-    }
-    private ContentType mContentType = ContentType.Widgets;
-
-    // Refs
-    @Thunk Launcher mLauncher;
-    private DragController mDragController;
-    private final LayoutInflater mLayoutInflater;
-    private final PackageManager mPackageManager;
-
-    // Save and Restore
-    private int mSaveInstanceStateItemIndex = -1;
-
-    // Content
-    private ArrayList<Object> mWidgets;
-
-    // Caching
-    private IconCache mIconCache;
-
-    // Dimens
-    private int mContentWidth, mContentHeight;
-    @Thunk int mWidgetCountX, mWidgetCountY;
-    private int mNumWidgetPages;
-
-    private final PagedViewKeyListener mKeyListener = new PagedViewKeyListener();
-
-    private Runnable mInflateWidgetRunnable = null;
-    private Runnable mBindWidgetRunnable = null;
-    static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
-    static final int WIDGET_PRELOAD_PENDING = 0;
-    static final int WIDGET_BOUND = 1;
-    static final int WIDGET_INFLATED = 2;
-    int mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
-    int mWidgetLoadingId = -1;
-    PendingAddWidgetInfo mCreateWidgetInfo = null;
-    private boolean mDraggingWidget = false;
-    boolean mPageBackgroundsVisible = true;
-
-    private Toast mWidgetInstructionToast;
-
-    // Deferral of loading widget previews during launcher transitions
-    private boolean mInTransition;
-
-    WidgetPreviewLoader mWidgetPreviewLoader;
-
-    private boolean mInBulkBind;
-    private boolean mNeedToUpdatePageCountsAndInvalidateData;
-
-    public AppsCustomizePagedView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mLayoutInflater = LayoutInflater.from(context);
-        mPackageManager = context.getPackageManager();
-        mWidgets = new ArrayList<>();
-        mIconCache = (LauncherAppState.getInstance()).getIconCache();
-
-        // Save the default widget preview background
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppsCustomizePagedView, 0, 0);
-        mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
-        mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
-        a.recycle();
-
-        // The padding on the non-matched dimension for the default widget preview icons
-        // (top + bottom)
-        mFadeInAdjacentScreens = false;
-
-        // Unless otherwise specified this view is important for accessibility.
-        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-        setSinglePageInViewport();
-    }
-
-    @Override
-    protected void init() {
-        super.init();
-        mCenterPagesVertically = false;
-
-        Context context = getContext();
-        Resources r = context.getResources();
-        setDragSlopeThreshold(r.getInteger(R.integer.config_appsCustomizeDragSlopeThreshold)/100f);
-    }
-
-    public void onFinishInflate() {
-        super.onFinishInflate();
-
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        setPadding(grid.edgeMarginPx, 2 * grid.edgeMarginPx,
-                grid.edgeMarginPx, 2 * grid.edgeMarginPx);
-    }
-
-    void setWidgetsPageIndicatorPadding(int pageIndicatorHeight) {
-        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), pageIndicatorHeight);
-    }
-
-    WidgetPreviewLoader getWidgetPreviewLoader() {
-        if (mWidgetPreviewLoader == null) {
-            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
-        }
-        return mWidgetPreviewLoader;
-    }
-
-    /** Returns the item index of the center item on this page so that we can restore to this
-     *  item index when we rotate. */
-    private int getMiddleComponentIndexOnCurrentPage() {
-        int i = -1;
-        if (getPageCount() > 0) {
-            int currentPage = getCurrentPage();
-            if (mContentType == ContentType.Widgets) {
-                PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(currentPage);
-                int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-                int childCount = layout.getChildCount();
-                if (childCount > 0) {
-                    i = (currentPage * numItemsPerPage) + (childCount / 2);
-                }
-            } else {
-                throw new RuntimeException("Invalid ContentType");
-            }
-        }
-        return i;
-    }
-
-    /** Get the index of the item to restore to if we need to restore the current page. */
-    int getSaveInstanceStateIndex() {
-        if (mSaveInstanceStateItemIndex == -1) {
-            mSaveInstanceStateItemIndex = getMiddleComponentIndexOnCurrentPage();
-        }
-        return mSaveInstanceStateItemIndex;
-    }
-
-    /** Returns the page in the current orientation which is expected to contain the specified
-     *  item index. */
-    int getPageForComponent(int index) {
-        if (index < 0) return 0;
-
-        int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-        return index / numItemsPerPage;
-    }
-
-    /** Restores the page for an item at the specified index */
-    void restorePageForIndex(int index) {
-        if (index < 0) return;
-        mSaveInstanceStateItemIndex = index;
-    }
-
-    private void updatePageCounts() {
-        mNumWidgetPages = (int) Math.ceil(mWidgets.size() /
-                (float) (mWidgetCountX * mWidgetCountY));
-    }
-
-    protected void onDataReady(int width, int height) {
-        updatePageCounts();
-
-        // Force a measure to update recalculate the gaps
-        mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-        mContentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
-
-        final boolean hostIsTransitioning = getTabHost().isInTransition();
-        int page = getPageForComponent(mSaveInstanceStateItemIndex);
-        invalidatePageData(Math.max(0, page), hostIsTransitioning);
-    }
-
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-
-        if (!isDataReady()) {
-            if (!mWidgets.isEmpty()) {
-                post(new Runnable() {
-                    // This code triggers requestLayout so must be posted outside of the
-                    // layout pass.
-                    public void run() {
-                        if (Utilities.isViewAttachedToWindow(AppsCustomizePagedView.this)) {
-                            setDataIsReady();
-                            onDataReady(getMeasuredWidth(), getMeasuredHeight());
-                        }
-                    }
-                });
-            }
-        }
-    }
-
-    public void onPackagesUpdated(ArrayList<Object> widgetsAndShortcuts) {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-
-        // Get the list of widgets and shortcuts
-        mWidgets.clear();
-        for (Object o : widgetsAndShortcuts) {
-            if (o instanceof LauncherAppWidgetProviderInfo) {
-                LauncherAppWidgetProviderInfo widget = (LauncherAppWidgetProviderInfo) o;
-                if (!app.shouldShowAppOrWidgetProvider(widget.provider) && !widget.isCustomWidget) {
-                    continue;
-                }
-
-                if (widget.minSpanX > 0 && widget.minSpanY > 0) {
-                    // Ensure that all widgets we show can be added on a workspace of this size
-                    int[] spanXY = Launcher.getSpanForWidget(mLauncher, widget);
-                    int[] minSpanXY = Launcher.getMinSpanForWidget(mLauncher, widget);
-                    int minSpanX = Math.min(spanXY[0], minSpanXY[0]);
-                    int minSpanY = Math.min(spanXY[1], minSpanXY[1]);
-                    if (minSpanX <= (int) grid.numColumns &&
-                        minSpanY <= (int) grid.numRows) {
-                        mWidgets.add(widget);
-                    } else {
-                        Log.e(TAG, "Widget " + widget.provider + " can not fit on this device (" +
-                              widget.minWidth + ", " + widget.minHeight + ")");
-                    }
-                } else {
-                    Log.e(TAG, "Widget " + widget.provider + " has invalid dimensions (" +
-                          widget.minWidth + ", " + widget.minHeight + ")");
-                }
-            } else {
-                // just add shortcuts
-                mWidgets.add(o);
-            }
-        }
-
-        updatePageCountsAndInvalidateData();
-    }
-
-    public void setBulkBind(boolean bulkBind) {
-        if (bulkBind) {
-            mInBulkBind = true;
-        } else {
-            mInBulkBind = false;
-            if (mNeedToUpdatePageCountsAndInvalidateData) {
-                updatePageCountsAndInvalidateData();
-            }
-        }
-    }
-
-    private void updatePageCountsAndInvalidateData() {
-        if (mInBulkBind) {
-            mNeedToUpdatePageCountsAndInvalidateData = true;
-        } else {
-            updatePageCounts();
-            invalidateOnDataChange();
-            mNeedToUpdatePageCountsAndInvalidateData = false;
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        // When we have exited all apps or are in transition, disregard clicks
-        if (!mLauncher.isWidgetsViewVisible()
-                || mLauncher.getWorkspace().isSwitchingState()
-                || !(v instanceof PagedViewWidget)) return;
-
-        // Let the user know that they have to long press to add a widget
-        if (mWidgetInstructionToast != null) {
-            mWidgetInstructionToast.cancel();
-        }
-        mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
-            Toast.LENGTH_SHORT);
-        mWidgetInstructionToast.show();
-    }
-
-    /*
-     * PagedViewWithDraggableItems implementation
-     */
-    @Override
-    protected void determineDraggingStart(android.view.MotionEvent ev) {
-    }
-
-    static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
-        Bundle options = null;
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, sTmpRect);
-            Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
-                    info.componentName, null);
-
-            float density = launcher.getResources().getDisplayMetrics().density;
-            int xPaddingDips = (int) ((padding.left + padding.right) / density);
-            int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
-
-            options = new Bundle();
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
-                    sTmpRect.left - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
-                    sTmpRect.top - yPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
-                    sTmpRect.right - xPaddingDips);
-            options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
-                    sTmpRect.bottom - yPaddingDips);
-        }
-        return options;
-    }
-
-    private void preloadWidget(final PendingAddWidgetInfo info) {
-        final LauncherAppWidgetProviderInfo pInfo = info.info;
-        final Bundle options = pInfo.isCustomWidget ? null :
-                getDefaultOptionsForWidget(mLauncher, info);
-
-        if (pInfo.configure != null) {
-            info.bindOptions = options;
-            return;
-        }
-
-        mWidgetCleanupState = WIDGET_PRELOAD_PENDING;
-        mBindWidgetRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if (pInfo.isCustomWidget) {
-                    mWidgetCleanupState = WIDGET_BOUND;
-                    return;
-                }
-
-                mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
-                if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
-                        mWidgetLoadingId, pInfo, options)) {
-                    mWidgetCleanupState = WIDGET_BOUND;
-                }
-
-            }
-        };
-        post(mBindWidgetRunnable);
-
-        mInflateWidgetRunnable = new Runnable() {
-            @Override
-            public void run() {
-                if (mWidgetCleanupState != WIDGET_BOUND) {
-                    return;
-                }
-                AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
-                        getContext(), mWidgetLoadingId, pInfo);
-                info.boundWidget = hostView;
-                mWidgetCleanupState = WIDGET_INFLATED;
-                hostView.setVisibility(INVISIBLE);
-                int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
-
-                // We want the first widget layout to be the correct size. This will be important
-                // for width size reporting to the AppWidgetManager.
-                DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
-                        unScaledSize[1]);
-                lp.x = lp.y = 0;
-                lp.customPosition = true;
-                hostView.setLayoutParams(lp);
-                mLauncher.getDragLayer().addView(hostView);
-            }
-        };
-        post(mInflateWidgetRunnable);
-    }
-
-    @Override
-    public void onShortPress(View v) {
-        // We are anticipating a long press, and we use this time to load bind and instantiate
-        // the widget. This will need to be cleaned up if it turns out no long press occurs.
-        if (mCreateWidgetInfo != null) {
-            // Just in case the cleanup process wasn't properly executed. This shouldn't happen.
-            cleanupWidgetPreloading(false);
-        }
-        mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
-        preloadWidget(mCreateWidgetInfo);
-    }
-
-    private void cleanupWidgetPreloading(boolean widgetWasAdded) {
-        if (!widgetWasAdded) {
-            // If the widget was not added, we may need to do further cleanup.
-            PendingAddWidgetInfo info = mCreateWidgetInfo;
-            mCreateWidgetInfo = null;
-
-            if (mWidgetCleanupState == WIDGET_PRELOAD_PENDING) {
-                // We never did any preloading, so just remove pending callbacks to do so
-                removeCallbacks(mBindWidgetRunnable);
-                removeCallbacks(mInflateWidgetRunnable);
-            } else if (mWidgetCleanupState == WIDGET_BOUND) {
-                 // Delete the widget id which was allocated
-                if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
-                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-                }
-
-                // We never got around to inflating the widget, so remove the callback to do so.
-                removeCallbacks(mInflateWidgetRunnable);
-            } else if (mWidgetCleanupState == WIDGET_INFLATED) {
-                // Delete the widget id which was allocated
-                if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
-                    mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
-                }
-
-                // The widget was inflated and added to the DragLayer -- remove it.
-                AppWidgetHostView widget = info.boundWidget;
-                mLauncher.getDragLayer().removeView(widget);
-            }
-        }
-        mWidgetCleanupState = WIDGET_NO_CLEANUP_REQUIRED;
-        mWidgetLoadingId = -1;
-        mCreateWidgetInfo = null;
-        PagedViewWidget.resetShortPressTarget();
-    }
-
-    @Override
-    public void cleanUpShortPress(View v) {
-        if (!mDraggingWidget) {
-            cleanupWidgetPreloading(false);
-        }
-    }
-
-    private boolean beginDraggingWidget(PagedViewWidget v) {
-        mDraggingWidget = true;
-        // Get the widget preview as the drag representation
-        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
-        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
-
-        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
-        // we abort the drag.
-        if (image.getDrawable() == null) {
-            mDraggingWidget = false;
-            return false;
-        }
-
-        // Compose the drag image
-        Bitmap preview;
-        Bitmap outline;
-        float scale = 1f;
-        Point previewPadding = null;
-
-        if (createItemInfo instanceof PendingAddWidgetInfo) {
-            // This can happen in some weird cases involving multi-touch. We can't start dragging
-            // the widget if this is null, so we break out.
-            if (mCreateWidgetInfo == null) {
-                return false;
-            }
-
-            PendingAddWidgetInfo createWidgetInfo = mCreateWidgetInfo;
-            createItemInfo = createWidgetInfo;
-            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
-
-            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
-            float minScale = 1.25f;
-            int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
-
-            int[] previewSizeBeforeScale = new int[1];
-            preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
-                    maxWidth, null, previewSizeBeforeScale);
-            // Compare the size of the drag preview to the preview in the AppsCustomize tray
-            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
-                    v.getActualItemWidth());
-            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
-
-            // The bitmap in the AppsCustomize tray is always the the same size, so there
-            // might be extra pixels around the preview itself - this accounts for that
-            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
-                int padding =
-                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
-                previewPadding = new Point(padding, 0);
-            }
-        } else {
-            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
-            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.shortcutActivityInfo);
-            preview = Utilities.createIconBitmap(icon, mLauncher);
-            createItemInfo.spanX = createItemInfo.spanY = 1;
-        }
-
-        // Don't clip alpha values for the drag outline if we're using the default widget preview
-        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
-                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
-
-        // Save the preview for the outline generation, then dim the preview
-        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
-                false);
-
-        // Start the drag
-        mLauncher.lockScreenOrientation();
-        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
-        mDragController.startDrag(image, preview, this, createItemInfo,
-                DragController.DRAG_ACTION_COPY, previewPadding, scale);
-        outline.recycle();
-        preview.recycle();
-        return true;
-    }
-
-    @Override
-    protected boolean beginDragging(final View v) {
-        if (!super.beginDragging(v)) return false;
-
-        if (v instanceof PagedViewWidget) {
-            if (!beginDraggingWidget((PagedViewWidget) v)) {
-                return false;
-            }
-        } else {
-            Log.e(TAG, "Unexpected dragging view: " + v);
-        }
-
-        // We delay entering spring-loaded mode slightly to make sure the UI
-        // thready is free of any work.
-        postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                // We don't enter spring-loaded mode if the drag has been cancelled
-                if (mLauncher.getDragController().isDragging()) {
-                    // Go into spring loaded mode (must happen before we startDrag())
-                    mLauncher.enterSpringLoadedDragMode();
-                }
-            }
-        }, 150);
-
-        return true;
-    }
-
-    /**
-     * Clean up after dragging.
-     *
-     * @param target where the item was dragged to (can be null if the item was flung)
-     */
-    private void endDragging(View target, boolean isFlingToDelete, boolean success) {
-        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
-                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
-            // Exit spring loaded mode if we have not successfully dropped or have not handled the
-            // drop in Workspace
-            mLauncher.exitSpringLoadedDragModeDelayed(true,
-                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
-            mLauncher.unlockScreenOrientation(false);
-        } else {
-            mLauncher.unlockScreenOrientation(false);
-        }
-    }
-
-    @Override
-    public View getContent() {
-        if (getChildCount() > 0) {
-            return getChildAt(0);
-        }
-        return null;
-    }
-
-    @Override
-    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
-        mInTransition = true;
-        if (toWorkspace) {
-            cancelAllTasks(false);
-        }
-    }
-
-    @Override
-    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
-    }
-
-    @Override
-    public void onLauncherTransitionStep(Launcher l, float t) {
-    }
-
-    @Override
-    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        mInTransition = false;
-        mForceDrawAllChildrenNextFrame = !toWorkspace;
-        if (!toWorkspace) {
-            loadPreviewsForPage(getNextPage());
-        }
-    }
-
-    @Override
-    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
-            boolean success) {
-        // Return early and wait for onFlingToDeleteCompleted if this was the result of a fling
-        if (isFlingToDelete) return;
-
-        endDragging(target, false, success);
-
-        // Display an error message if the drag failed due to there not being enough space on the
-        // target layout we were dropping on.
-        if (!success) {
-            boolean showOutOfSpaceMessage = false;
-            if (target instanceof Workspace) {
-                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
-                Workspace workspace = (Workspace) target;
-                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
-                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
-                if (layout != null) {
-                    layout.calculateSpans(itemInfo);
-                    showOutOfSpaceMessage =
-                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
-                }
-            }
-            if (showOutOfSpaceMessage) {
-                mLauncher.showOutOfSpaceMessage(false);
-            }
-
-            d.deferDragViewCleanupPostAnimation = false;
-        }
-        cleanupWidgetPreloading(success);
-        mDraggingWidget = false;
-    }
-
-    @Override
-    public void onFlingToDeleteCompleted() {
-        // We just dismiss the drag when we fling, so cleanup here
-        endDragging(null, true, true);
-        cleanupWidgetPreloading(false);
-        mDraggingWidget = false;
-    }
-
-    @Override
-    public boolean supportsFlingToDelete() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsAppInfoDropTarget() {
-        return true;
-    }
-
-    @Override
-    public boolean supportsDeleteDropTarget() {
-        return false;
-    }
-
-    @Override
-    public float getIntrinsicIconScaleFactor() {
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        return (float) grid.allAppsIconSizePx / grid.iconSizePx;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        cancelAllTasks(true);
-    }
-
-    @Override
-    public void trimMemory() {
-        super.trimMemory();
-        cancelAllTasks(true);
-    }
-
-    private void cancelAllTasks(boolean clearCompletedTasks) {
-        for (int page = getPageCount() - 1; page >= 0; page--) {
-            final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-            if (layout != null) {
-                for (int i = 0; i < layout.getChildCount(); i++) {
-                    ((PagedViewWidget) layout.getChildAt(i)).deletePreview(clearCompletedTasks);
-                }
-            }
-        }
-    }
-
-
-    public void setContentType(ContentType type) {
-        // Widgets appear to be cleared every time you leave, always force invalidate for them
-        if (mContentType != type || type == ContentType.Widgets) {
-            int page = (mContentType != type) ? 0 : getCurrentPage();
-            mContentType = type;
-            invalidatePageData(page, true);
-        }
-    }
-
-    public ContentType getContentType() {
-        return mContentType;
-    }
-
-    public void setPageBackgroundsVisible(boolean visible) {
-        mPageBackgroundsVisible = visible;
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; ++i) {
-            Drawable bg = getChildAt(i).getBackground();
-            if (bg != null) {
-                bg.setAlpha(visible ? 255 : 0);
-            }
-        }
-    }
-
-    /*
-     * Widgets PagedView implementation
-     */
-    private void setupPage(PagedViewGridLayout layout) {
-        // Note: We force a measure here to get around the fact that when we do layout calculations
-        // immediately after syncing, we don't have a proper width.
-        int widthSpec = MeasureSpec.makeMeasureSpec(mContentWidth, MeasureSpec.AT_MOST);
-        int heightSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.AT_MOST);
-
-        Drawable bg = getContext().getResources().getDrawable(R.drawable.quantum_panel_dark);
-        if (bg != null) {
-            bg.setAlpha(mPageBackgroundsVisible ? 255 : 0);
-            layout.setBackground(bg);
-        }
-        layout.measure(widthSpec, heightSpec);
-    }
-
-    public void syncWidgetPageItems(final int page, final boolean immediate) {
-        int numItemsPerPage = mWidgetCountX * mWidgetCountY;
-
-        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
-        // Calculate the dimensions of each cell we are giving to each widget
-        final ArrayList<Object> items = new ArrayList<Object>();
-        int contentWidth = mContentWidth - layout.getPaddingLeft() - layout.getPaddingRight();
-        final int cellWidth = contentWidth / mWidgetCountX;
-        int contentHeight = mContentHeight - layout.getPaddingTop() - layout.getPaddingBottom();
-
-        final int cellHeight = contentHeight / mWidgetCountY;
-
-        // Prepare the set of widgets to load previews for in the background
-        int offset = page * numItemsPerPage;
-        for (int i = offset; i < Math.min(offset + numItemsPerPage, mWidgets.size()); ++i) {
-            items.add(mWidgets.get(i));
-        }
-
-        // Prepopulate the pages with the other widget info, and fill in the previews later
-        layout.setColumnCount(layout.getCellCountX());
-        for (int i = 0; i < items.size(); ++i) {
-            Object rawInfo = items.get(i);
-            PendingAddItemInfo createItemInfo = null;
-            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
-                    R.layout.apps_customize_widget, layout, false);
-
-            if (rawInfo instanceof LauncherAppWidgetProviderInfo) {
-                // Fill in the widget information
-                LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) rawInfo;
-                createItemInfo = new PendingAddWidgetInfo(info, null);
-
-                widget.applyFromAppWidgetProviderInfo(info, -1, getWidgetPreviewLoader());
-                widget.setTag(createItemInfo);
-                widget.setShortPressListener(this);
-            } else if (rawInfo instanceof ResolveInfo) {
-                // Fill in the shortcuts information
-                ResolveInfo info = (ResolveInfo) rawInfo;
-                createItemInfo = new PendingAddShortcutInfo(info.activityInfo);
-                createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-                createItemInfo.componentName = new ComponentName(info.activityInfo.packageName,
-                        info.activityInfo.name);
-                widget.applyFromResolveInfo(mPackageManager, info, getWidgetPreviewLoader());
-                widget.setTag(createItemInfo);
-            }
-
-            widget.setOnClickListener(this);
-            widget.setOnLongClickListener(this);
-            widget.setOnTouchListener(this);
-            widget.setOnKeyListener(mKeyListener);
-
-            // Layout each widget
-            int ix = i % mWidgetCountX;
-            int iy = i / mWidgetCountX;
-
-            if (ix > 0) {
-                View border = widget.findViewById(R.id.left_border);
-                border.setVisibility(View.VISIBLE);
-            }
-            if (ix < mWidgetCountX - 1) {
-                View border = widget.findViewById(R.id.right_border);
-                border.setVisibility(View.VISIBLE);
-            }
-
-            GridLayout.LayoutParams lp = new GridLayout.LayoutParams(
-                    GridLayout.spec(iy, GridLayout.START),
-                    GridLayout.spec(ix, GridLayout.TOP));
-            lp.width = cellWidth;
-            lp.height = cellHeight;
-            lp.setGravity(Gravity.TOP | Gravity.START);
-            layout.addView(widget, lp);
-        }
-
-        if (immediate && !mInTransition) {
-            loadPreviewsForPage(page);
-        }
-    }
-
-    private void loadPreviewsForPage(int page) {
-        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page);
-
-        if (layout != null) {
-            for (int i = 0; i < layout.getChildCount(); i++) {
-                ((PagedViewWidget) layout.getChildAt(i)).ensurePreview();
-            }
-        }
-    }
-
-    @Override
-    public void syncPages() {
-        disablePagedViewAnimations();
-
-        removeAllViews();
-        cancelAllTasks(true);
-
-        Context context = getContext();
-        if (mContentType == ContentType.Widgets) {
-            for (int j = 0; j < mNumWidgetPages; ++j) {
-                PagedViewGridLayout layout = new PagedViewGridLayout(context, mWidgetCountX,
-                        mWidgetCountY);
-                setupPage(layout);
-                addView(layout, new PagedView.LayoutParams(LayoutParams.MATCH_PARENT,
-                        LayoutParams.MATCH_PARENT));
-            }
-        } else {
-            throw new RuntimeException("Invalid ContentType");
-        }
-
-        enablePagedViewAnimations();
-    }
-
-    @Override
-    public void syncPageItems(int page, boolean immediate) {
-        if (mContentType == ContentType.Widgets) {
-            syncWidgetPageItems(page, immediate);
-        } else {
-            Log.e(TAG, "Unexpected ContentType");
-        }
-    }
-
-    // We want our pages to be z-ordered such that the further a page is to the left, the higher
-    // it is in the z-order. This is important to insure touch events are handled correctly.
-    View getPageAt(int index) {
-        return getChildAt(indexToPage(index));
-    }
-
-    @Override
-    protected int indexToPage(int index) {
-        return getChildCount() - index - 1;
-    }
-
-    // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack.
-    @Override
-    protected void screenScrolled(int screenCenter) {
-        super.screenScrolled(screenCenter);
-        enableHwLayersOnVisiblePages();
-    }
-
-    private void enableHwLayersOnVisiblePages() {
-        final int screenCount = getChildCount();
-
-        getVisiblePages(mTempVisiblePagesRange);
-        int leftScreen = mTempVisiblePagesRange[0];
-        int rightScreen = mTempVisiblePagesRange[1];
-        int forceDrawScreen = -1;
-        if (leftScreen == rightScreen) {
-            // make sure we're caching at least two pages always
-            if (rightScreen < screenCount - 1) {
-                rightScreen++;
-                forceDrawScreen = rightScreen;
-            } else if (leftScreen > 0) {
-                leftScreen--;
-                forceDrawScreen = leftScreen;
-            }
-        } else {
-            forceDrawScreen = leftScreen + 1;
-        }
-
-        for (int i = 0; i < screenCount; i++) {
-            final View layout = (View) getPageAt(i);
-            if (!(leftScreen <= i && i <= rightScreen &&
-                    (i == forceDrawScreen || shouldDrawChild(layout)))) {
-                layout.setLayerType(LAYER_TYPE_NONE, null);
-            }
-        }
-
-        for (int i = 0; i < screenCount; i++) {
-            final View layout = (View) getPageAt(i);
-
-            if (leftScreen <= i && i <= rightScreen &&
-                    (i == forceDrawScreen || shouldDrawChild(layout))) {
-                if (layout.getLayerType() != LAYER_TYPE_HARDWARE) {
-                    layout.setLayerType(LAYER_TYPE_HARDWARE, null);
-                }
-            }
-        }
-    }
-
-    protected void overScroll(float amount) {
-        dampedOverScroll(amount);
-    }
-
-    /**
-     * Used by the parent to get the content width to set the tab bar to
-     * @return
-     */
-    public int getPageContentWidth() {
-        return mContentWidth;
-    }
-
-    @Override
-    protected void onPageEndMoving() {
-        super.onPageEndMoving();
-        mForceDrawAllChildrenNextFrame = true;
-        // We reset the save index when we change pages so that it will be recalculated on next
-        // rotation
-        mSaveInstanceStateItemIndex = -1;
-    }
-
-    @Override
-    protected void onPageBeginMoving() {
-        super.onPageBeginMoving();
-        if (!mInTransition) {
-            getVisiblePages(sTempPosArray);
-            for (int i = sTempPosArray[0]; i <= sTempPosArray[1]; i++) {
-                loadPreviewsForPage(i);
-            }
-        }
-    }
-
-    /*
-     * AllAppsView implementation
-     */
-    public void setup(Launcher launcher, DragController dragController) {
-        mLauncher = launcher;
-        mDragController = dragController;
-    }
-
-    /**
-     * We should call thise method whenever the core data changes (mWidgets) so that we can
-     * appropriately determine when to invalidate the PagedView page data.  In cases where the data
-     * has yet to be set, we can requestLayout() and wait for onDataReady() to be called in the
-     * next onMeasure() pass, which will trigger an invalidatePageData() itself.
-     */
-    private void invalidateOnDataChange() {
-        if (!isDataReady()) {
-            // The next layout pass will trigger data-ready if both widgets and apps are set, so
-            // request a layout to trigger the page data when ready.
-            requestLayout();
-        } else {
-            cancelAllTasks(false);
-            invalidatePageData();
-        }
-    }
-
-    public void reset() {
-        // If we have reset, then we should not continue to restore the previous state
-        mSaveInstanceStateItemIndex = -1;
-
-        if (mContentType != ContentType.Widgets) {
-            setContentType(ContentType.Widgets);
-        }
-
-        if (mCurrentPage != 0) {
-            invalidatePageData(0);
-        }
-    }
-
-    private AppsCustomizeTabHost getTabHost() {
-        return (AppsCustomizeTabHost) mLauncher.findViewById(R.id.apps_customize_pane);
-    }
-
-    public void dumpState() {
-        // TODO: Dump information related to current list of Applications, Widgets, etc.
-        dumpAppWidgetProviderInfoList(TAG, "mWidgets", mWidgets);
-    }
-
-    private void dumpAppWidgetProviderInfoList(String tag, String label,
-            ArrayList<Object> list) {
-        Log.d(tag, label + " size=" + list.size());
-        for (Object i: list) {
-            if (i instanceof AppWidgetProviderInfo) {
-                AppWidgetProviderInfo info = (AppWidgetProviderInfo) i;
-                Log.d(tag, "   label=\"" + info.label + "\" previewImage=" + info.previewImage
-                        + " resizeMode=" + info.resizeMode + " configure=" + info.configure
-                        + " initialLayout=" + info.initialLayout
-                        + " minWidth=" + info.minWidth + " minHeight=" + info.minHeight);
-            } else if (i instanceof ResolveInfo) {
-                ResolveInfo info = (ResolveInfo) i;
-                Log.d(tag, "   label=\"" + info.loadLabel(mPackageManager) + "\" icon="
-                        + info.icon);
-            }
-        }
-    }
-
-    public void surrender() {
-        // TODO: If we are in the middle of any process (ie. for holographic outlines, etc) we
-        // should stop this now.
-
-        // Stop all background tasks
-        cancelAllTasks(true);
-    }
-
-    /*
-     * We load an extra page on each side to prevent flashes from scrolling and loading of the
-     * widget previews in the background with the AsyncTasks.
-     */
-    final static int sLookBehindPageCount = 2;
-    final static int sLookAheadPageCount = 2;
-    protected int getAssociatedLowerPageBound(int page) {
-        final int count = getChildCount();
-        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
-        int windowMinIndex = Math.max(Math.min(page - sLookBehindPageCount, count - windowSize), 0);
-        return windowMinIndex;
-    }
-    protected int getAssociatedUpperPageBound(int page) {
-        final int count = getChildCount();
-        int windowSize = Math.min(count, sLookBehindPageCount + sLookAheadPageCount + 1);
-        int windowMaxIndex = Math.min(Math.max(page + sLookAheadPageCount, windowSize - 1),
-                count - 1);
-        return windowMaxIndex;
-    }
-
-    protected String getCurrentPageDescription() {
-        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-        int stringId = R.string.default_scroll_format;
-        int count = 0;
-
-        if (mContentType == ContentType.Widgets) {
-            stringId = R.string.apps_customize_widgets_scroll_format;
-            count = mNumWidgetPages;
-        } else {
-            throw new RuntimeException("Invalid ContentType");
-        }
-
-        return String.format(getContext().getString(stringId), page + 1, count);
-    }
-}
diff --git a/src/com/android/launcher3/AppsCustomizeTabHost.java b/src/com/android/launcher3/AppsCustomizeTabHost.java
deleted file mode 100644
index 5e2f05c..0000000
--- a/src/com/android/launcher3/AppsCustomizeTabHost.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.FrameLayout;
-
-public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable  {
-    static final String LOG_TAG = "AppsCustomizeTabHost";
-
-    private static final String WIDGETS_TAB_TAG = "WIDGETS";
-
-    private AppsCustomizePagedView mPagedView;
-    private View mContent;
-    private boolean mInTransition = false;
-
-    private final Rect mInsets = new Rect();
-
-    public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    /**
-     * Convenience methods to select specific tabs.  We want to set the content type immediately
-     * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
-     * reflects the new content (but doesn't do the animation and logic associated with changing
-     * tabs manually).
-     */
-    void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
-        mPagedView.setContentType(type);
-    }
-
-    @Override
-    public void setInsets(Rect insets) {
-        mInsets.set(insets);
-        LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
-        flp.topMargin = insets.top;
-        flp.bottomMargin = insets.bottom;
-        flp.leftMargin = insets.left;
-        flp.rightMargin = insets.right;
-        mContent.setLayoutParams(flp);
-    }
-
-    /**
-     * Setup the tab host and create all necessary tabs.
-     */
-    @Override
-    protected void onFinishInflate() {
-        mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
-        mContent = findViewById(R.id.content);
-    }
-
-    public String getContentTag() {
-        return getTabTagForContentType(mPagedView.getContentType());
-    }
-
-    /**
-     * Returns the content view used for the launcher transitions.
-     */
-    public View getContentView() {
-        return findViewById(R.id.apps_customize_pane_content);
-    }
-
-    /**
-     * Returns the reveal view used for the launcher transitions.
-     */
-    public View getRevealView() {
-        return findViewById(R.id.fake_page);
-    }
-
-    /**
-     * Returns the page indicators view.
-     */
-    public View getPageIndicators() {
-        return findViewById(R.id.apps_customize_page_indicator);
-    }
-
-    /**
-     * Returns the content type for the specified tab tag.
-     */
-    public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
-        return AppsCustomizePagedView.ContentType.Widgets;
-    }
-
-    /**
-     * Returns the tab tag for a given content type.
-     */
-    public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
-        return WIDGETS_TAB_TAG;
-    }
-
-    /**
-     * Disable focus on anything under this view in the hierarchy if we are not visible.
-     */
-    @Override
-    public int getDescendantFocusability() {
-        if (getVisibility() != View.VISIBLE) {
-            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
-        }
-        return super.getDescendantFocusability();
-    }
-
-    void reset() {
-        // Reset immediately
-        mPagedView.reset();
-    }
-
-    void trimMemory() {
-        mPagedView.trimMemory();
-    }
-
-    public void onWindowVisible() {
-        if (getVisibility() == VISIBLE) {
-            mContent.setVisibility(VISIBLE);
-            // We unload the widget previews when the UI is hidden, so need to reload pages
-            // Load the current page synchronously, and the neighboring pages asynchronously
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-        }
-    }
-    @Override
-    public ViewGroup getContent() {
-        return mPagedView;
-    }
-
-    public boolean isInTransition() {
-        return mInTransition;
-    }
-
-    /* LauncherTransitionable overrides */
-    @Override
-    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
-        mInTransition = true;
-
-        if (toWorkspace) {
-            // Going from All Apps -> Workspace
-            setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
-        } else {
-            // Going from Workspace -> All Apps
-            mContent.setVisibility(VISIBLE);
-
-            // Make sure the current page is loaded (we start loading the side pages after the
-            // transition to prevent slowing down the animation)
-            // TODO: revisit this
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-        }
-    }
-
-    @Override
-    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
-    }
-
-    @Override
-    public void onLauncherTransitionStep(Launcher l, float t) {
-        mPagedView.onLauncherTransitionStep(l, t);
-    }
-
-    @Override
-    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
-        mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
-        mInTransition = false;
-
-        if (!toWorkspace) {
-            // Make sure adjacent pages are loaded (we wait until after the transition to
-            // prevent slowing down the animation)
-            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
-
-            // Opening apps, need to announce what page we are on.
-            AccessibilityManager am = (AccessibilityManager)
-                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
-            if (am.isEnabled()) {
-                // Notify the user when the page changes
-                announceForAccessibility(mPagedView.getCurrentPageDescription());
-            }
-
-            // Going from Workspace -> All Apps
-            // NOTE: We should do this at the end since we check visibility state in some of the
-            // cling initialization/dismiss code above.
-            setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
-        }
-    }
-
-    private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
-        ViewGroup parent = (ViewGroup) getParent();
-        if (parent == null) return;
-
-        View appsView = ((Launcher) getContext()).getAppsView();
-        View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
-        final int count = parent.getChildCount();
-        if (!isChildrenDrawingOrderEnabled()) {
-            for (int i = 0; i < count; i++) {
-                final View child = parent.getChildAt(i);
-                if (child == this) {
-                    break;
-                } else {
-                    if (child.getVisibility() == GONE || child == overviewPanel ||
-                            child == appsView) {
-                        continue;
-                    }
-                    child.setVisibility(visibility);
-                }
-            }
-        } else {
-            throw new RuntimeException("Failed; can't get z-order of views");
-        }
-    }
-}
diff --git a/src/com/android/launcher3/AppsGridAdapter.java b/src/com/android/launcher3/AppsGridAdapter.java
index 5b6967c..c8ce397 100644
--- a/src/com/android/launcher3/AppsGridAdapter.java
+++ b/src/com/android/launcher3/AppsGridAdapter.java
@@ -112,6 +112,7 @@
 
     private LayoutInflater mLayoutInflater;
     @Thunk AlphabeticalAppsList mApps;
+    private GridLayoutManager mGridLayoutMgr;
     private GridSpanSizer mGridSizer;
     private GridItemDecoration mItemDecoration;
     private View.OnTouchListener mTouchListener;
@@ -135,6 +136,9 @@
         mApps = apps;
         mAppsPerRow = appsPerRow;
         mGridSizer = new GridSpanSizer();
+        mGridLayoutMgr = new GridLayoutManager(context, appsPerRow, GridLayoutManager.VERTICAL,
+                false);
+        mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
         mItemDecoration = new GridItemDecoration();
         mLayoutInflater = LayoutInflater.from(context);
         mTouchListener = touchListener;
@@ -150,6 +154,14 @@
     }
 
     /**
+     * Sets the number of apps per row.
+     */
+    public void setNumAppsPerRow(int appsPerRow) {
+        mAppsPerRow = appsPerRow;
+        mGridLayoutMgr.setSpanCount(appsPerRow);
+    }
+
+    /**
      * Sets whether we are in RTL mode.
      */
     public void setRtl(boolean rtl) {
@@ -167,10 +179,7 @@
      * Returns the grid layout manager.
      */
     public GridLayoutManager getLayoutManager(Context context) {
-        GridLayoutManager layoutMgr = new GridLayoutManager(context, mAppsPerRow,
-                GridLayoutManager.VERTICAL, false);
-        layoutMgr.setSpanSizeLookup(mGridSizer);
-        return layoutMgr;
+        return mGridLayoutMgr;
     }
 
     /**
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 63afa30..f4afb95 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -45,7 +45,6 @@
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -56,6 +55,7 @@
 import com.android.launcher3.FolderIcon.FolderRingAnimator;
 import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -3025,7 +3025,7 @@
      *
      * @return True if a vacant cell of the specified dimension was found, false otherwise.
      */
-    boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
+    public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
         return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
     }
 
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 1f0dad2..62aa285 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -42,6 +42,7 @@
 
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetsContainerView;
 
 public class DeleteDropTarget extends ButtonDropTarget {
     private static int DELETE_ANIMATION_DURATION = 285;
@@ -100,8 +101,9 @@
     private boolean isAllAppsApplication(DragSource source, Object info) {
         return source.supportsAppInfoDropTarget() && (info instanceof AppInfo);
     }
-    private boolean isAllAppsWidget(DragSource source, Object info) {
-        if (source instanceof AppsCustomizePagedView) {
+
+    private boolean isWidget(DragSource source, Object info) {
+        if (source instanceof WidgetsContainerView) {
             if (info instanceof PendingAddItemInfo) {
                 PendingAddItemInfo addInfo = (PendingAddItemInfo) info;
                 switch (addInfo.itemType) {
@@ -173,7 +175,7 @@
         // If we are dragging an application from AppsCustomize, only show the control if we can
         // delete the app (it was downloaded), and rename the string to "uninstall" in such a case.
         // Hide the delete target if it is a widget from AppsCustomize.
-        if (!willAcceptDrop(info) || isAllAppsWidget(source, info)) {
+        if (!willAcceptDrop(info) || isWidget(source, info)) {
             isVisible = false;
         }
         if (useUninstallLabel) {
@@ -489,13 +491,14 @@
     }
 
     public void onFlingToDelete(final DragObject d, int x, int y, PointF vel) {
-        final boolean isAllApps = d.dragSource instanceof AppsCustomizePagedView;
+        final boolean isWidgets = d.dragSource instanceof WidgetsContainerView;
+        final boolean isAllapps = d.dragSource instanceof AppsContainerView;
 
         // Don't highlight the icon as it's animating
         d.dragView.setColor(0);
         d.dragView.updateInitialScaleToCurrentScale();
         // Don't highlight the target if we are flinging from AllApps
-        if (isAllApps) {
+        if (isWidgets || isAllapps) {
             resetHoverColor();
         }
 
@@ -545,7 +548,7 @@
             public void run() {
                 // If we are dragging from AllApps, then we allow AppsCustomizePagedView to clean up
                 // itself, otherwise, complete the drop to initiate the deletion process
-                if (!isAllApps) {
+                if (!isWidgets || !isAllapps) {
                     mLauncher.exitSpringLoadedDragMode();
                     completeDrop(d);
                 }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 331695a..786f2ce 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -106,8 +106,8 @@
     public int cellWidthPx;
     public int cellHeightPx;
 
-    int iconSizePx;
-    int iconTextSizePx;
+    public int iconSizePx;
+    public int iconTextSizePx;
     int iconDrawablePaddingPx;
     int allAppsIconSizePx;
     int allAppsIconTextSizePx;
@@ -423,13 +423,21 @@
             allAppsNumCols = Math.max(minEdgeCellCount, Math.min(maxCols, allAppsNumCols));
         }
 
-        int appsContainerViewPx = res.getDimensionPixelSize(R.dimen.apps_container_width);
+        int appsContainerViewWidthPx = res.getDimensionPixelSize(R.dimen.apps_container_width);
+        updateAppsViewNumCols(res, appsContainerViewWidthPx);
+    }
+
+    public boolean updateAppsViewNumCols(Resources res, int containerWidth) {
         int appsViewLeftMarginPx =
                 res.getDimensionPixelSize(R.dimen.apps_grid_view_start_margin);
-        int availableAppsWidthPx = (appsContainerViewPx > 0) ? appsContainerViewPx :
-                availableWidthPx;
-        appsViewNumCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
+        int availableAppsWidthPx = (containerWidth > 0) ? containerWidth : availableWidthPx;
+        int numCols = (availableAppsWidthPx - appsViewLeftMarginPx) /
                 (allAppsCellWidthPx + 2 * allAppsCellPaddingPx);
+        if (numCols != appsViewNumCols) {
+            appsViewNumCols = numCols;
+            return true;
+        }
+        return false;
     }
 
     void updateFromConfiguration(Context context, Resources resources, int wPx, int hPx,
@@ -803,64 +811,6 @@
             }
         }
 
-        // Layout AllApps
-        AppsCustomizeTabHost host = (AppsCustomizeTabHost)
-                launcher.findViewById(R.id.apps_customize_pane);
-        if (host != null) {
-            // Center the all apps page indicator
-            int pageIndicatorHeight = (int) (pageIndicatorHeightPx * Math.min(1f,
-                    (allAppsIconSizePx / DynamicGrid.DEFAULT_ICON_SIZE_PX)));
-            pageIndicator = host.findViewById(R.id.apps_customize_page_indicator);
-            if (pageIndicator != null) {
-                LinearLayout.LayoutParams lllp = (LinearLayout.LayoutParams) pageIndicator.getLayoutParams();
-                lllp.width = LayoutParams.WRAP_CONTENT;
-                lllp.height = pageIndicatorHeight;
-                pageIndicator.setLayoutParams(lllp);
-            }
-
-            AppsCustomizePagedView pagedView = (AppsCustomizePagedView)
-                    host.findViewById(R.id.apps_customize_pane_content);
-
-            FrameLayout fakePageContainer = (FrameLayout)
-                    host.findViewById(R.id.fake_page_container);
-            FrameLayout fakePage = (FrameLayout) host.findViewById(R.id.fake_page);
-
-            padding = new Rect();
-            if (pagedView != null) {
-                // Constrain the dimensions of all apps so that it does not span the full width
-                int paddingLR = (availableWidthPx - (allAppsCellWidthPx * allAppsNumCols)) /
-                        (2 * (allAppsNumCols + 1));
-                int paddingTB = (availableHeightPx - (allAppsCellHeightPx * allAppsNumRows)) /
-                        (2 * (allAppsNumRows + 1));
-                paddingLR = Math.min(paddingLR, (int)((paddingLR + paddingTB) * 0.75f));
-                paddingTB = Math.min(paddingTB, (int)((paddingLR + paddingTB) * 0.75f));
-                int maxAllAppsWidth = (allAppsNumCols * (allAppsCellWidthPx + 2 * paddingLR));
-                int gridPaddingLR = (availableWidthPx - maxAllAppsWidth) / 2;
-                // Only adjust the side paddings on landscape phones, or tablets
-                if ((isTablet() || isLandscape) && gridPaddingLR > (allAppsCellWidthPx / 4)) {
-                    padding.left = padding.right = gridPaddingLR;
-                }
-
-                // The icons are centered, so we can't just offset by the page indicator height
-                // because the empty space will actually be pageIndicatorHeight + paddingTB
-                padding.bottom = Math.max(0, pageIndicatorHeight - paddingTB);
-
-                pagedView.setWidgetsPageIndicatorPadding(pageIndicatorHeight);
-                fakePage.setBackground(res.getDrawable(R.drawable.quantum_panel));
-
-                // Horizontal padding for the whole paged view
-                int pagedFixedViewPadding =
-                        res.getDimensionPixelSize(R.dimen.apps_customize_horizontal_padding);
-
-                padding.left += pagedFixedViewPadding;
-                padding.right += pagedFixedViewPadding;
-
-                pagedView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-                fakePageContainer.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-
-            }
-        }
-
         // Layout the Overview Mode
         ViewGroup overviewMode = launcher.getOverviewPanel();
         if (overviewMode != null) {
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 7369eea..2a1346e 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -22,9 +22,9 @@
 
 /**
  * Interface defining an object that can originate a drag.
- *
  */
 public interface DragSource {
+
     /**
      * @return whether items dragged from this source supports
      */
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index ff02bbb..28e923e 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -32,7 +32,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.SparseArray;
 
-class FastBitmapDrawable extends Drawable {
+public class FastBitmapDrawable extends Drawable {
 
     static final TimeInterpolator CLICK_FEEDBACK_INTERPOLATOR = new TimeInterpolator() {
 
@@ -72,7 +72,7 @@
     private boolean mPressed = false;
     private ObjectAnimator mPressedAnimator;
 
-    FastBitmapDrawable(Bitmap b) {
+    public FastBitmapDrawable(Bitmap b) {
         mAlpha = 255;
         mBitmap = b;
         setBounds(0, 0, b.getWidth(), b.getHeight());
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 1e1d1ee..0eb1fd8 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -69,7 +69,6 @@
      * results in CellLayout being measured as UNSPECIFIED, which it does not support.
      */
     private static final int MIN_CONTENT_DIMEN = 5;
-    private static final boolean ALLOW_FOLDER_SCROLL = true;
 
     static final int STATE_NONE = -1;
     static final int STATE_SMALL = 0;
@@ -101,6 +100,8 @@
 
     private final Alarm mReorderAlarm = new Alarm();
     private final Alarm mOnExitAlarm = new Alarm();
+    private final Alarm mOnScrollHintAlarm = new Alarm();
+    @Thunk final Alarm mScrollPauseAlarm = new Alarm();
 
     @Thunk final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
 
@@ -116,7 +117,7 @@
 
     @Thunk FolderIcon mFolderIcon;
 
-    @Thunk FolderContent mContent;
+    @Thunk FolderPagedView mContent;
     @Thunk View mContentWrapper;
     FolderEditText mFolderName;
 
@@ -149,11 +150,6 @@
 
     // Folder scrolling
     private int mScrollAreaOffset;
-    private Alarm mOnScrollHintAlarm;
-    @Thunk Alarm mScrollPauseAlarm;
-
-    // TODO: Use {@link #mContent} once {@link #ALLOW_FOLDER_SCROLL} is removed.
-    @Thunk FolderPagedView mPagedView;
 
     @Thunk int mScrollHintDir = DragController.SCROLL_NONE;
     @Thunk int mCurrentScrollDir = DragController.SCROLL_NONE;
@@ -186,18 +182,13 @@
         // name is complete, we have something to focus on, thus hiding the cursor and giving
         // reliable behavior when clicking the text field (since it will always gain focus on click).
         setFocusableInTouchMode(true);
-
-        if (ALLOW_FOLDER_SCROLL) {
-            mOnScrollHintAlarm = new Alarm();
-            mScrollPauseAlarm = new Alarm();
-        }
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mContentWrapper = findViewById(R.id.folder_content_wrapper);
-        mContent = (FolderContent) findViewById(R.id.folder_content);
+        mContent = (FolderPagedView) findViewById(R.id.folder_content);
         mContent.setFolder(this);
 
         mFolderName = (FolderEditText) findViewById(R.id.folder_name);
@@ -211,16 +202,16 @@
         mFolderName.setInputType(mFolderName.getInputType() |
                 InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
 
-        mFooter = ALLOW_FOLDER_SCROLL ? findViewById(R.id.folder_footer) : mFolderName;
+        mFooter = findViewById(R.id.folder_footer);
+        updateFooterHeight();
+    }
+
+    public void updateFooterHeight() {
         // We find out how tall footer wants to be (it is set to wrap_content), so that
         // we can allocate the appropriate amount of space for it.
         int measureSpec = MeasureSpec.UNSPECIFIED;
         mFooter.measure(measureSpec, measureSpec);
         mFooterHeight = mFooter.getMeasuredHeight();
-
-        if (ALLOW_FOLDER_SCROLL) {
-            mPagedView = (FolderPagedView) mContent;
-        }
     }
 
     private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
@@ -398,8 +389,7 @@
      * @return A new UserFolder.
      */
     static Folder fromXml(Context context) {
-        return (Folder) LayoutInflater.from(context).inflate(
-                ALLOW_FOLDER_SCROLL ? R.layout.user_folder_scroll : R.layout.user_folder, null);
+        return (Folder) LayoutInflater.from(context).inflate(R.layout.user_folder, null);
     }
 
     /**
@@ -424,12 +414,10 @@
     public void animateOpen() {
         if (!(getParent() instanceof DragLayer)) return;
 
-        if (ALLOW_FOLDER_SCROLL) {
-            mPagedView.completePendingPageChanges();
-            if (!(mDragInProgress && mPagedView.mIsSorted)) {
-                // Open on the first page.
-                mPagedView.snapToPageImmediately(0);
-            }
+        mContent.completePendingPageChanges();
+        if (!(mDragInProgress && mContent.mIsSorted)) {
+            // Open on the first page.
+            mContent.snapToPageImmediately(0);
         }
 
         Animator openFolderAnim = null;
@@ -533,10 +521,8 @@
             mDragController.forceTouchMove();
         }
 
-        if (ALLOW_FOLDER_SCROLL) {
-            FolderPagedView pages = (FolderPagedView) mContent;
-            pages.verifyVisibleHighResIcons(pages.getNextPage());
-        }
+        FolderPagedView pages = (FolderPagedView) mContent;
+        pages.verifyVisibleHighResIcons(pages.getNextPage());
     }
 
     public void beginExternalDrag(ShortcutInfo item) {
@@ -544,7 +530,8 @@
         mEmptyCellRank = mContent.allocateRankForNewItem(item);
         mIsExternalDrag = true;
         mDragInProgress = true;
-        if (ALLOW_FOLDER_SCROLL && mPagedView.mIsSorted) {
+
+        if (mContent.mIsSorted) {
             mScrollPauseAlarm.setOnAlarmListener(null);
             mScrollPauseAlarm.cancelAlarm();
             mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
@@ -601,11 +588,9 @@
     public void onDragEnter(DragObject d) {
         mPrevTargetRank = -1;
         mOnExitAlarm.cancelAlarm();
-        if (ALLOW_FOLDER_SCROLL) {
-            // Get the area offset such that the folder only closes if half the drag icon width
-            // is outside the folder area
-            mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
-        }
+        // Get the area offset such that the folder only closes if half the drag icon width
+        // is outside the folder area
+        mScrollAreaOffset = d.dragView.getDragRegionWidth() / 2 - d.xOffset;
     }
 
     OnAlarmListener mReorderAlarmListener = new OnAlarmListener() {
@@ -632,7 +617,7 @@
     }
 
     @Thunk void onDragOver(DragObject d, int reorderDelay) {
-        if (ALLOW_FOLDER_SCROLL && mScrollPauseAlarm.alarmPending()) {
+        if (mScrollPauseAlarm.alarmPending()) {
             return;
         }
         final float[] r = new float[2];
@@ -645,27 +630,23 @@
             mPrevTargetRank = mTargetRank;
         }
 
-        if (!ALLOW_FOLDER_SCROLL) {
-            return;
-        }
-
         float x = r[0];
-        int currentPage = mPagedView.getNextPage();
+        int currentPage = mContent.getNextPage();
 
-        float cellOverlap = mPagedView.getCurrentCellLayout().getCellWidth()
+        float cellOverlap = mContent.getCurrentCellLayout().getCellWidth()
                 * ICON_OVERSCROLL_WIDTH_FACTOR;
         boolean isOutsideLeftEdge = x < cellOverlap;
         boolean isOutsideRightEdge = x > (getWidth() - cellOverlap);
 
-        if (currentPage > 0 && (mPagedView.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
+        if (currentPage > 0 && (mContent.rtlLayout ? isOutsideRightEdge : isOutsideLeftEdge)) {
             showScrollHint(DragController.SCROLL_LEFT, d);
-        } else if (currentPage < (mPagedView.getPageCount() - 1)
-                && (mPagedView.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
+        } else if (currentPage < (mContent.getPageCount() - 1)
+                && (mContent.rtlLayout ? isOutsideLeftEdge : isOutsideRightEdge)) {
             showScrollHint(DragController.SCROLL_RIGHT, d);
         } else {
             mOnScrollHintAlarm.cancelAlarm();
             if (mScrollHintDir != DragController.SCROLL_NONE) {
-                mPagedView.clearScrollHint();
+                mContent.clearScrollHint();
                 mScrollHintDir = DragController.SCROLL_NONE;
             }
         }
@@ -674,7 +655,7 @@
     private void showScrollHint(int direction, DragObject d) {
         // Show scroll hint on the right
         if (mScrollHintDir != direction) {
-            mPagedView.showScrollHint(direction);
+            mContent.showScrollHint(direction);
             mScrollHintDir = direction;
         }
 
@@ -714,13 +695,11 @@
         }
         mReorderAlarm.cancelAlarm();
 
-        if (ALLOW_FOLDER_SCROLL) {
-            mOnScrollHintAlarm.cancelAlarm();
-            mScrollPauseAlarm.cancelAlarm();
-            if (mScrollHintDir != DragController.SCROLL_NONE) {
-                mPagedView.clearScrollHint();
-                mScrollHintDir = DragController.SCROLL_NONE;
-            }
+        mOnScrollHintAlarm.cancelAlarm();
+        mScrollPauseAlarm.cancelAlarm();
+        if (mScrollHintDir != DragController.SCROLL_NONE) {
+            mContent.clearScrollHint();
+            mScrollHintDir = DragController.SCROLL_NONE;
         }
     }
 
@@ -1088,21 +1067,19 @@
             };
         }
 
-        if (ALLOW_FOLDER_SCROLL) {
-            // If the icon was dropped while the page was being scrolled, we need to compute
-            // the target location again such that the icon is placed of the final page.
-            if (!mPagedView.rankOnCurrentPage(mEmptyCellRank)) {
-                // Reorder again.
-                mTargetRank = getTargetRank(d, null);
+        // If the icon was dropped while the page was being scrolled, we need to compute
+        // the target location again such that the icon is placed of the final page.
+        if (!mContent.rankOnCurrentPage(mEmptyCellRank)) {
+            // Reorder again.
+            mTargetRank = getTargetRank(d, null);
 
-                // Rearrange items immediately.
-                mReorderAlarmListener.onAlarm(mReorderAlarm);
+            // Rearrange items immediately.
+            mReorderAlarmListener.onAlarm(mReorderAlarm);
 
-                mOnScrollHintAlarm.cancelAlarm();
-                mScrollPauseAlarm.cancelAlarm();
-            }
-            mPagedView.completePendingPageChanges();
+            mOnScrollHintAlarm.cancelAlarm();
+            mScrollPauseAlarm.cancelAlarm();
         }
+        mContent.completePendingPageChanges();
 
         View currentDragView;
         ShortcutInfo si = mCurrentDragInfo;
@@ -1252,10 +1229,10 @@
         @Override
         public void onAlarm(Alarm alarm) {
             if (mCurrentScrollDir == DragController.SCROLL_LEFT) {
-                mPagedView.scrollLeft();
+                mContent.scrollLeft();
                 mScrollHintDir = DragController.SCROLL_NONE;
             } else if (mCurrentScrollDir == DragController.SCROLL_RIGHT) {
-                mPagedView.scrollRight();
+                mContent.scrollRight();
                 mScrollHintDir = DragController.SCROLL_NONE;
             } else {
                 // This should not happen
@@ -1286,69 +1263,4 @@
             onDragOver(mDragObject, 1);
         }
     }
-
-    public static interface FolderContent {
-        void setFolder(Folder f);
-
-        void removeItem(View v);
-
-        boolean isFull();
-        int getItemCount();
-
-        int getDesiredWidth();
-        int getDesiredHeight();
-        void setFixedSize(int width, int height);
-
-        /**
-         * Iterates over all its items in a reading order.
-         * @return the view for which the operator returned true.
-         */
-        View iterateOverItems(ItemOperator op);
-        View getLastItem();
-
-        String getAccessibilityDescription();
-
-        /**
-         * Binds items to the layout.
-         * @return list of items that could not be bound, probably because we hit the max size limit.
-         */
-        ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> children);
-
-        /**
-         * Create space for a new item, and returns the rank for that item.
-         * Resizes the content if necessary.
-         */
-        int allocateRankForNewItem(ShortcutInfo info);
-
-        View createAndAddViewForRank(ShortcutInfo item, int rank);
-
-        /**
-         * Adds the {@param view} to the layout based on {@param rank} and updated the position
-         * related attributes. It assumes that {@param item} is already attached to the view.
-         */
-        void addViewForRank(View view, ShortcutInfo item, int rank);
-
-        /**
-         * Reorders the items such that the {@param empty} spot moves to {@param target}
-         */
-        void realTimeReorder(int empty, int target);
-
-        /**
-         * @return the rank of the cell nearest to the provided pixel position.
-         */
-        int findNearestArea(int pixelX, int pixelY);
-
-        /**
-         * Updates position and rank of all the children in the view based.
-         * @param list the ordered list of children.
-         * @param itemCount if greater than the total children count, empty spaces are left
-         * at the end.
-         */
-        void arrangeChildren(ArrayList<View> list, int itemCount);
-
-        /**
-         * Sets the focus on the first visible child.
-         */
-        void setFocusOnFirstChild();
-    }
 }
diff --git a/src/com/android/launcher3/FolderCellLayout.java b/src/com/android/launcher3/FolderCellLayout.java
deleted file mode 100644
index 8585add..0000000
--- a/src/com/android/launcher3/FolderCellLayout.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/**
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.launcher3.Workspace.ItemOperator;
-
-import java.util.ArrayList;
-
-public class FolderCellLayout extends CellLayout implements Folder.FolderContent {
-
-    private static final int REORDER_ANIMATION_DURATION = 230;
-    private static final int START_VIEW_REORDER_DELAY = 30;
-    private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
-
-    private static final int[] sTempPosArray = new int[2];
-
-    private final FolderKeyEventListener mKeyListener = new FolderKeyEventListener();
-    private final LayoutInflater mInflater;
-    private final IconCache mIconCache;
-
-    private final int mMaxCountX;
-    private final int mMaxCountY;
-    private final int mMaxNumItems;
-
-    // Indicates the last number of items used to set up the grid size
-    private int mAllocatedContentSize;
-
-    private Folder mFolder;
-    private FocusIndicatorView mFocusIndicatorView;
-
-    public FolderCellLayout(Context context) {
-        this(context, null);
-    }
-
-    public FolderCellLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public FolderCellLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        LauncherAppState app = LauncherAppState.getInstance();
-        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        mMaxCountX = (int) grid.numColumns;
-        mMaxCountY = (int) grid.numRows;
-        mMaxNumItems = mMaxCountX * mMaxCountY;
-
-        mInflater = LayoutInflater.from(context);
-        mIconCache = app.getIconCache();
-
-        setCellDimensions(grid.folderCellWidthPx, grid.folderCellHeightPx);
-        getShortcutsAndWidgets().setMotionEventSplittingEnabled(false);
-        setInvertIfRtl(true);
-    }
-
-    @Override
-    public void setFolder(Folder folder) {
-        mFolder = folder;
-        mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
-    }
-
-    /**
-     * Sets up the grid size such that {@param count} items can fit in the grid.
-     * The grid size is calculated such that countY <= countX and countX = ceil(sqrt(count)) while
-     * maintaining the restrictions of {@link #mMaxCountX} &amp; {@link #mMaxCountY}.
-     */
-    private void setupContentDimensions(int count) {
-        mAllocatedContentSize = count;
-        int countX = getCountX();
-        int countY = getCountY();
-        boolean done = false;
-
-        while (!done) {
-            int oldCountX = countX;
-            int oldCountY = countY;
-            if (countX * countY < count) {
-                // Current grid is too small, expand it
-                if ((countX <= countY || countY == mMaxCountY) && countX < mMaxCountX) {
-                    countX++;
-                } else if (countY < mMaxCountY) {
-                    countY++;
-                }
-                if (countY == 0) countY++;
-            } else if ((countY - 1) * countX >= count && countY >= countX) {
-                countY = Math.max(0, countY - 1);
-            } else if ((countX - 1) * countY >= count) {
-                countX = Math.max(0, countX - 1);
-            }
-            done = countX == oldCountX && countY == oldCountY;
-        }
-        setGridSize(countX, countY);
-    }
-
-    @Override
-    public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
-        ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
-        setupContentDimensions(Math.min(items.size(), mMaxNumItems));
-
-        int countX = getCountX();
-        int rank = 0;
-        for (ShortcutInfo item : items) {
-            if (rank >= mMaxNumItems) {
-                extra.add(item);
-                continue;
-            }
-
-            item.rank = rank;
-            item.cellX = rank % countX;
-            item.cellY = rank / countX;
-            addNewView(item);
-            rank++;
-        }
-        return extra;
-    }
-
-    @Override
-    public int allocateRankForNewItem(ShortcutInfo info) {
-        int rank = getItemCount();
-        mFolder.rearrangeChildren(rank + 1);
-        return rank;
-    }
-
-    @Override
-    public View createAndAddViewForRank(ShortcutInfo item, int rank) {
-        updateItemXY(item, rank);
-        return addNewView(item);
-    }
-
-    @Override
-    public void addViewForRank(View view, ShortcutInfo item, int rank) {
-        updateItemXY(item, rank);
-        CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
-        lp.cellX = item.cellX;
-        lp.cellY = item.cellY;
-        addViewToCellLayout(view, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
-    }
-
-    @Override
-    public void removeItem(View v) {
-        removeView(v);
-    }
-
-    /**
-     * Updates the item cellX and cellY position
-     */
-    private void updateItemXY(ShortcutInfo item, int rank) {
-        item.rank = rank;
-        int countX = getCountX();
-        item.cellX = rank % countX;
-        item.cellY = rank / countX;
-    }
-
-    private View addNewView(ShortcutInfo item) {
-        final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
-                R.layout.folder_application, getShortcutsAndWidgets(), false);
-        textView.applyFromShortcutInfo(item, mIconCache, false);
-        textView.setOnClickListener(mFolder);
-        textView.setOnLongClickListener(mFolder);
-        textView.setOnFocusChangeListener(mFocusIndicatorView);
-        textView.setOnKeyListener(mKeyListener);
-
-        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(
-                item.cellX, item.cellY, item.spanX, item.spanY);
-        addViewToCellLayout(textView, -1, mFolder.mLauncher.getViewIdForItem(item), lp, true);
-        return textView;
-    }
-
-    /**
-     * Refer {@link #findNearestArea(int, int, int, int, View, boolean, int[])}
-     */
-    @Override
-    public int findNearestArea(int pixelX, int pixelY) {
-        findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
-        if (mFolder.isLayoutRtl()) {
-            sTempPosArray[0] = getCountX() - sTempPosArray[0] - 1;
-        }
-
-        // Convert this position to rank.
-        return Math.min(mAllocatedContentSize - 1,
-                sTempPosArray[1] * getCountX() + sTempPosArray[0]);
-    }
-
-    @Override
-    public boolean isFull() {
-        return getItemCount() >= mMaxNumItems;
-    }
-
-    @Override
-    public int getItemCount() {
-        return getShortcutsAndWidgets().getChildCount();
-    }
-
-    @Override
-    public void arrangeChildren(ArrayList<View> list, int itemCount) {
-        setupContentDimensions(itemCount);
-        removeAllViews();
-
-        int newX, newY;
-        int rank = 0;
-        int countX = getCountX();
-        for (View v : list) {
-            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
-            newX = rank % countX;
-            newY = rank / countX;
-            ItemInfo info = (ItemInfo) v.getTag();
-            if (info.cellX != newX || info.cellY != newY || info.rank != rank) {
-                info.cellX = newX;
-                info.cellY = newY;
-                info.rank = rank;
-                LauncherModel.addOrMoveItemInDatabase(getContext(), info,
-                        mFolder.mInfo.id, 0, info.cellX, info.cellY);
-            }
-            lp.cellX = info.cellX;
-            lp.cellY = info.cellY;
-            rank ++;
-            addViewToCellLayout(v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
-        }
-    }
-
-    @Override
-    public View iterateOverItems(ItemOperator op) {
-        for (int j = 0; j < getCountY(); j++) {
-            for (int i = 0; i < getCountX(); i++) {
-                View v = getChildAt(i, j);
-                if ((v != null) && op.evaluate((ItemInfo) v.getTag(), v, this)) {
-                    return v;
-                }
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public String getAccessibilityDescription() {
-        return String.format(getContext().getString(R.string.folder_opened),
-                getCountX(), getCountY());
-    }
-
-    @Override
-    public void setFocusOnFirstChild() {
-        View firstChild = getChildAt(0, 0);
-        if (firstChild != null) {
-            firstChild.requestFocus();
-        }
-    }
-
-    @Override
-    public View getLastItem() {
-        int lastRank = getShortcutsAndWidgets().getChildCount() - 1;
-        // count can be zero if the folder is not yet laid out.
-        int count = getCountX();
-        if (count > 0) {
-            return getShortcutsAndWidgets().getChildAt(lastRank % count, lastRank / count);
-        } else {
-            return getShortcutsAndWidgets().getChildAt(lastRank);
-        }
-    }
-
-    @Override
-    public void realTimeReorder(int empty, int target) {
-        boolean wrap;
-        int startX;
-        int endX;
-        int startY;
-        int delay = 0;
-        float delayAmount = START_VIEW_REORDER_DELAY;
-
-        int countX = getCountX();
-        int emptyX = empty % getCountX();
-        int emptyY = empty / countX;
-
-        int targetX = target % countX;
-        int targetY = target / countX;
-
-        if (target > empty) {
-            wrap = emptyX == countX - 1;
-            startY = wrap ? emptyY + 1 : emptyY;
-            for (int y = startY; y <= targetY; y++) {
-                startX = y == emptyY ? emptyX + 1 : 0;
-                endX = y < targetY ? countX - 1 : targetX;
-                for (int x = startX; x <= endX; x++) {
-                    View v = getChildAt(x,y);
-                    if (animateChildToPosition(v, emptyX, emptyY,
-                            REORDER_ANIMATION_DURATION, delay, true, true)) {
-                        emptyX = x;
-                        emptyY = y;
-                        delay += delayAmount;
-                        delayAmount *= VIEW_REORDER_DELAY_FACTOR;
-                    }
-                }
-            }
-        } else {
-            wrap = emptyX == 0;
-            startY = wrap ? emptyY - 1 : emptyY;
-            for (int y = startY; y >= targetY; y--) {
-                startX = y == emptyY ? emptyX - 1 : countX - 1;
-                endX = y > targetY ? 0 : targetX;
-                for (int x = startX; x >= endX; x--) {
-                    View v = getChildAt(x,y);
-                    if (animateChildToPosition(v, emptyX, emptyY,
-                            REORDER_ANIMATION_DURATION, delay, true, true)) {
-                        emptyX = x;
-                        emptyY = y;
-                        delay += delayAmount;
-                        delayAmount *= VIEW_REORDER_DELAY_FACTOR;
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 1c42d25..6174892 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -19,7 +19,6 @@
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.LayoutDirection;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -42,10 +41,15 @@
 import java.util.Iterator;
 import java.util.Map;
 
-public class FolderPagedView extends PagedView implements Folder.FolderContent {
+public class FolderPagedView extends PagedView {
 
     private static final String TAG = "FolderPagedView";
 
+    private static final boolean ALLOW_FOLDER_SCROLL = true;
+
+    // To enable this flag, user_folder.xml needs to be modified to add sort button.
+    private static final boolean ALLOW_ITEM_SORTING = false;
+
     private static final int REORDER_ANIMATION_DURATION = 230;
     private static final int START_VIEW_REORDER_DELAY = 30;
     private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
@@ -96,34 +100,36 @@
         setDataIsReady();
 
         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
-        mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
-        mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
+        if (ALLOW_FOLDER_SCROLL) {
+            mMaxCountX = Math.min((int) grid.numColumns, MAX_ITEMS_PER_PAGE);
+            mMaxCountY = Math.min((int) grid.numRows, MAX_ITEMS_PER_PAGE);
+        } else {
+            mMaxCountX = (int) grid.numColumns;
+            mMaxCountY = (int) grid.numRows;
+        }
+
         mMaxItemsPerPage = mMaxCountX * mMaxCountY;
 
         mInflater = LayoutInflater.from(context);
         mIconCache = app.getIconCache();
 
-        rtlLayout = getResources().getConfiguration().getLayoutDirection() == LayoutDirection.RTL;
+        rtlLayout = getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_RTL;
     }
 
-    @Override
     public void setFolder(Folder folder) {
         mFolder = folder;
         mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
         mKeyListener = new PagedFolderKeyEventListener(folder);
-
-        mSortButton = folder.findViewById(R.id.folder_sort);
-        mSortButton.setOnClickListener(new OnClickListener() {
-
-            @Override
-            public void onClick(View v) {
-                onSortClicked();
-            }
-        });
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
-        mSortSwitch = (Switch) folder.findViewById(R.id.folder_sort_switch);
+
+        if (ALLOW_ITEM_SORTING) {
+            // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
+        }
     }
 
+    /**
+     * Called when sort button is clicked.
+     */
     private void onSortClicked() {
         if (mSortOperationPending) {
             return;
@@ -138,9 +144,11 @@
 
     private void setIsSorted(boolean isSorted, boolean saveChanges) {
         mIsSorted = isSorted;
-        mSortSwitch.setChecked(isSorted);
-        mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
-                saveChanges ? mFolder.mLauncher : null);
+        if (ALLOW_ITEM_SORTING) {
+            mSortSwitch.setChecked(isSorted);
+            mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
+                    saveChanges ? mFolder.mLauncher : null);
+        }
     }
 
     /**
@@ -282,26 +290,34 @@
         }
     }
 
-    @Override
+    /**
+     * Binds items to the layout.
+     * @return list of items that could not be bound, probably because we hit the max size limit.
+     */
     public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
-        mIsSorted = mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
+        mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
         ArrayList<View> icons = new ArrayList<View>();
+        ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
+
         for (ShortcutInfo item : items) {
-            icons.add(createNewView(item));
+            if (!ALLOW_FOLDER_SCROLL && icons.size() >= mMaxItemsPerPage) {
+                extra.add(item);
+            } else {
+                icons.add(createNewView(item));
+            }
         }
         arrangeChildren(icons, icons.size(), false);
-        return new ArrayList<ShortcutInfo>();
+        return extra;
     }
 
     /**
      * Create space for a new item at the end, and returns the rank for that item.
      * Also sets the current page to the last page.
      */
-    @Override
     public int allocateRankForNewItem(ShortcutInfo info) {
         int rank = getItemCount();
         ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
-        if (mIsSorted) {
+        if (ALLOW_ITEM_SORTING && mIsSorted) {
             View tmp = new View(getContext());
             tmp.setTag(info);
             int index = Collections.binarySearch(views, tmp, new ViewComparator());
@@ -321,14 +337,16 @@
         return rank;
     }
 
-    @Override
     public View createAndAddViewForRank(ShortcutInfo item, int rank) {
         View icon = createNewView(item);
         addViewForRank(icon, item, rank);
         return icon;
     }
 
-    @Override
+    /**
+     * Adds the {@param view} to the layout based on {@param rank} and updated the position
+     * related attributes. It assumes that {@param item} is already attached to the view.
+     */
     public void addViewForRank(View view, ShortcutInfo item, int rank) {
         int pagePos = rank % mMaxItemsPerPage;
         int pageNo = rank / mMaxItemsPerPage;
@@ -388,14 +406,12 @@
         return page;
     }
 
-    @Override
     public void setFixedSize(int width, int height) {
         for (int i = getChildCount() - 1; i >= 0; i --) {
             ((CellLayout) getChildAt(i)).setFixedSize(width, height);
         }
     }
 
-    @Override
     public void removeItem(View v) {
         for (int i = getChildCount() - 1; i >= 0; i --) {
             getPageAt(i).removeView(v);
@@ -412,7 +428,6 @@
      * at the end, otherwise it is ignored.
      *
      */
-    @Override
     public void arrangeChildren(ArrayList<View> list, int itemCount) {
         arrangeChildren(list, itemCount, true);
     }
@@ -488,19 +503,26 @@
             setCurrentPage(0);
         }
 
-        setIsSorted(isSorted, saveChanges);
+        setEnableOverscroll(getPageCount() > 1);
 
         // Update footer
-        if (getPageCount() > 1) {
-            mPageIndicator.setVisibility(View.VISIBLE);
-            mSortButton.setVisibility(View.VISIBLE);
-            mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
-            setEnableOverscroll(true);
+        if (ALLOW_ITEM_SORTING) {
+            setIsSorted(isSorted, saveChanges);
+            if (getPageCount() > 1) {
+                mPageIndicator.setVisibility(View.VISIBLE);
+                mSortButton.setVisibility(View.VISIBLE);
+                mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
+            } else {
+                mPageIndicator.setVisibility(View.GONE);
+                mSortButton.setVisibility(View.GONE);
+                mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
+            }
         } else {
-            mPageIndicator.setVisibility(View.GONE);
-            mSortButton.setVisibility(View.GONE);
-            mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
-            setEnableOverscroll(false);
+            int indicatorVisibility = mPageIndicator.getVisibility();
+            mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+            if (indicatorVisibility != mPageIndicator.getVisibility()) {
+                mFolder.updateFooterHeight();
+            }
         }
     }
 
@@ -521,7 +543,6 @@
         return  getPageCount() > 0 ? getPageAt(0).getDesiredHeight() : 0;
     }
 
-    @Override
     public int getItemCount() {
         int lastPageIndex = getChildCount() - 1;
         if (lastPageIndex < 0) {
@@ -532,7 +553,9 @@
                 + lastPageIndex * mMaxItemsPerPage;
     }
 
-    @Override
+    /**
+     * @return the rank of the cell nearest to the provided pixel position.
+     */
     public int findNearestArea(int pixelX, int pixelY) {
         int pageIndex = getNextPage();
         CellLayout page = getPageAt(pageIndex);
@@ -550,12 +573,10 @@
                 R.drawable.ic_pageindicator_default_folder);
     }
 
-    @Override
     public boolean isFull() {
-        return false;
+        return !ALLOW_FOLDER_SCROLL && getItemCount() >= mMaxItemsPerPage;
     }
 
-    @Override
     public View getLastItem() {
         if (getChildCount() < 1) {
             return null;
@@ -569,7 +590,10 @@
         }
     }
 
-    @Override
+    /**
+     * Iterates over all its items in a reading order.
+     * @return the view for which the operator returned true.
+     */
     public View iterateOverItems(ItemOperator op) {
         for (int k = 0 ; k < getChildCount(); k++) {
             CellLayout page = getPageAt(k);
@@ -585,13 +609,14 @@
         return null;
     }
 
-    @Override
     public String getAccessibilityDescription() {
         return String.format(getContext().getString(R.string.folder_opened),
                 mGridCountX, mGridCountY);
     }
 
-    @Override
+    /**
+     * Sets the focus on the first visible child.
+     */
     public void setFocusOnFirstChild() {
         View firstChild = getCurrentCellLayout().getChildAt(0, 0);
         if (firstChild != null) {
@@ -605,7 +630,7 @@
         if (mFolder != null) {
             mFolder.updateTextViewFocus();
         }
-        if (mSortOperationPending && getNextPage() == 0) {
+        if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
             post(new Runnable() {
 
                 @Override
@@ -680,7 +705,9 @@
         }
     }
 
-    @Override
+    /**
+     * Reorders the items such that the {@param empty} spot moves to {@param target}
+     */
     public void realTimeReorder(int empty, int target) {
         completePendingPageChanges();
         int delay = 0;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f4af7f5..f6238da 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PackageItemInfo;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -454,12 +455,13 @@
      * Fill in {@param appInfo} with the icon and label for {@param packageName}
      */
     public synchronized void getTitleAndIconForApp(
-            String packageName, UserHandleCompat user, boolean useLowResIcon, AppInfo appInfoOut) {
+            String packageName, UserHandleCompat user, boolean useLowResIcon,
+            PackageItemInfo infoOut) {
         CacheEntry entry = getEntryForPackageLocked(packageName, user, useLowResIcon);
-        appInfoOut.iconBitmap = entry.icon;
-        appInfoOut.title = entry.title;
-        appInfoOut.usingLowResIcon = entry.isLowResIcon;
-        appInfoOut.contentDescription = entry.contentDescription;
+        infoOut.iconBitmap = entry.icon;
+        infoOut.title = entry.title;
+        infoOut.usingLowResIcon = entry.isLowResIcon;
+        infoOut.contentDescription = entry.contentDescription;
     }
 
     public synchronized Bitmap getDefaultIcon(UserHandleCompat user) {
diff --git a/src/com/android/launcher3/Insettable.java b/src/com/android/launcher3/Insettable.java
index 1d2356c..3b8ef2f 100644
--- a/src/com/android/launcher3/Insettable.java
+++ b/src/com/android/launcher3/Insettable.java
@@ -18,6 +18,10 @@
 
 import android.graphics.Rect;
 
+/**
+ * Allows the implementing {@link View} to not draw underneath system bars.
+ * e.g., notification bar on top and home key area on the bottom.
+ */
 public interface Insettable {
 
     void setInsets(Rect insets);
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index f114de2..f7e0ea4 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -36,7 +36,7 @@
      */
     static final String EXTRA_PROFILE = "profile";
     
-    static final int NO_ID = -1;
+    public static final int NO_ID = -1;
     
     /**
      * The id in the settings database for this item
@@ -82,7 +82,7 @@
     /**
      * Indicates the Y cell span.
      */
-    int spanY = 1;
+    public int spanY = 1;
 
     /**
      * Indicates the minimum X cell span.
@@ -107,21 +107,21 @@
     /**
      * Title of the item
      */
-    CharSequence title;
+    public CharSequence title;
 
     /**
      * Content description of the item.
      */
-    CharSequence contentDescription;
+    public CharSequence contentDescription;
 
     /**
      * The position of the item in a drag-and-drop operation.
      */
-    int[] dropPos = null;
+    public int[] dropPos = null;
 
-    UserHandleCompat user;
+    public UserHandleCompat user;
 
-    ItemInfo() {
+    public ItemInfo() {
         user = UserHandleCompat.myUserHandle();
     }
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2fa2f4a..3d2a346 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -103,6 +103,8 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetsContainerView;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -130,11 +132,11 @@
         implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                    View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener,
                    LauncherStateTransitionAnimation.Callbacks {
-    static final String TAG = "Launcher";
-    static final boolean LOGD = false;
+    static final String TAG = "Launcher - MERONG";
+    static final boolean LOGD = true;
 
     static final boolean PROFILE_STARTUP = false;
-    static final boolean DEBUG_WIDGETS = false;
+    static final boolean DEBUG_WIDGETS = true;
     static final boolean DEBUG_STRICT_MODE = false;
     static final boolean DEBUG_RESUME_TIME = false;
     static final boolean DEBUG_DUMP_LOG = false;
@@ -264,9 +266,13 @@
     private View mAllAppsButton;
 
     private SearchDropTargetBar mSearchDropTargetBar;
+
+    // Main container view for the all apps screen.
     @Thunk AppsContainerView mAppsView;
-    @Thunk AppsCustomizeTabHost mAppsCustomizeTabHost;
-    private AppsCustomizePagedView mAppsCustomizeContent;
+
+    // Main container view for the widget tray screen.
+    private WidgetsContainerView mWidgetsView;
+
     private boolean mAutoAdvanceRunning = false;
     private AppWidgetHostView mQsb;
 
@@ -514,6 +520,17 @@
 
     public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
         mLauncherCallbacks = callbacks;
+        mLauncherCallbacks.setLauncherAppsCallback(new Launcher.LauncherAppsCallbacks() {
+            @Override
+            public void onAllAppsBoundsChanged(Rect bounds) {
+                mAppsView.setFixedBounds(Launcher.this, bounds);
+            }
+
+            @Override
+            public void dismissAllApps() {
+                showWorkspace(true);
+            }
+        });
         return true;
     }
 
@@ -672,7 +689,7 @@
         return mInflater;
     }
 
-    boolean isDraggingEnabled() {
+    public boolean isDraggingEnabled() {
         // We prevent dragging when we are loading the workspace as it is possible to pick up a view
         // that is subsequently removed from the workspace in startBinding().
         return !mModel.isLoadingWorkspace();
@@ -1013,15 +1030,9 @@
                 startTimeCallbacks = System.currentTimeMillis();
             }
 
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.setBulkBind(true);
-            }
             for (int i = 0; i < mBindOnResumeCallbacks.size(); i++) {
                 mBindOnResumeCallbacks.get(i).run();
             }
-            if (mAppsCustomizeContent != null) {
-                mAppsCustomizeContent.setBulkBind(false);
-            }
             mBindOnResumeCallbacks.clear();
             if (DEBUG_RESUME_TIME) {
                 Log.d(TAG, "Time spent processing callbacks in onResume: " +
@@ -1141,6 +1152,19 @@
         public void forceExitFullImmersion();
     }
 
+    public interface LauncherAppsCallbacks {
+        /**
+         * Updates launcher to the available space that AllApps can take so as not to overlap with
+         * any other views.
+         */
+        public void onAllAppsBoundsChanged(Rect bounds);
+
+        /**
+         * Called to dismiss all apps if it is showing.
+         */
+        public void dismissAllApps();
+    }
+
     public interface LauncherOverlayCallbacks {
         /**
          * This method indicates whether a call to {@link #enterFullImmersion()} will succeed,
@@ -1213,9 +1237,8 @@
         if (mModel.isCurrentCallbacks(this)) {
             mModel.stopLoader();
         }
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.surrender();
-        }
+        //TODO(hyunyoungs): stop the widgets loader when there is a rotation.
+
         return Boolean.TRUE;
     }
 
@@ -1336,19 +1359,6 @@
             mRestoring = true;
         }
 
-        // Restore the AppsCustomize tab
-        if (mAppsCustomizeTabHost != null) {
-            String curTab = savedState.getString("apps_customize_currentTab");
-            if (curTab != null) {
-                mAppsCustomizeTabHost.setContentTypeImmediate(
-                        mAppsCustomizeTabHost.getContentTypeForTabTag(curTab));
-                mAppsCustomizeContent.loadAssociatedPages(
-                        mAppsCustomizeContent.getCurrentPage());
-            }
-
-            int currentIndex = savedState.getInt("apps_customize_currentIndex");
-            mAppsCustomizeContent.restorePageForIndex(currentIndex);
-        }
         mItemIdToViewId = (HashMap<Integer, Integer>)
                 savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
     }
@@ -1432,12 +1442,12 @@
 
         // Setup Apps
         mAppsView = (AppsContainerView) findViewById(R.id.apps_view);
+        if (mLauncherCallbacks != null && mLauncherCallbacks.overrideAllAppsSearch()) {
+            mAppsView.hideSearchBar();
+        }
 
         // Setup AppsCustomize
-        mAppsCustomizeTabHost = (AppsCustomizeTabHost) findViewById(R.id.apps_customize_pane);
-        mAppsCustomizeContent = (AppsCustomizePagedView)
-                mAppsCustomizeTabHost.findViewById(R.id.apps_customize_pane_content);
-        mAppsCustomizeContent.setup(this, dragController);
+        mWidgetsView = (WidgetsContainerView) findViewById(R.id.widgets_view);
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
         dragController.setDragScoller(mWorkspace);
@@ -1651,7 +1661,7 @@
 
                 // Reset AllApps to its initial state only if we are not in the middle of
                 // processing a multi-step drop
-                if (mAppsView != null && mAppsCustomizeTabHost != null &&
+                if (mAppsView != null && mWidgetsView != null &&
                         mPendingAddInfo.container == ItemInfo.NO_ID) {
                     showWorkspace(false);
                 }
@@ -1735,7 +1745,6 @@
         // you're in All Apps and click home to go to the workspace. onWindowVisibilityChanged
         // is a more appropriate event to handle
         if (mVisible) {
-            mAppsCustomizeTabHost.onWindowVisible();
             if (!mWorkspaceLoading) {
                 final ViewTreeObserver observer = mWorkspace.getViewTreeObserver();
                 // We want to let Launcher draw itself at least once before we force it to build
@@ -1839,7 +1848,7 @@
         launcherInfo.hostView = null;
     }
 
-    void showOutOfSpaceMessage(boolean isHotseatLayout) {
+    public void showOutOfSpaceMessage(boolean isHotseatLayout) {
         int strId = (isHotseatLayout ? R.string.hotseat_out_of_space : R.string.out_of_space);
         Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT).show();
     }
@@ -1852,8 +1861,8 @@
         return mAppsView;
     }
 
-    public AppsCustomizeTabHost getWidgetsView() {
-        return mAppsCustomizeTabHost;
+    public WidgetsContainerView getWidgetsView() {
+        return mWidgetsView;
     }
 
     public Workspace getWorkspace() {
@@ -1946,9 +1955,9 @@
                 mAppsView.scrollToTop();
             }
 
-            // Reset the apps customize page
-            if (!alreadyOnHome && mAppsCustomizeTabHost != null) {
-                mAppsCustomizeTabHost.reset();
+            // Reset the widgets view
+            if (!alreadyOnHome && mWidgetsView != null) {
+                mWidgetsView.scrollToTop();
             }
 
             if (mLauncherCallbacks != null) {
@@ -2003,16 +2012,8 @@
             outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
         }
 
-        // Save the current AppsCustomize tab
-        if (mAppsCustomizeTabHost != null) {
-            AppsCustomizePagedView.ContentType type = mAppsCustomizeContent.getContentType();
-            String currentTabTag = mAppsCustomizeTabHost.getTabTagForContentType(type);
-            if (currentTabTag != null) {
-                outState.putString("apps_customize_currentTab", currentTabTag);
-            }
-            int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
-            outState.putInt("apps_customize_currentIndex", currentIndex);
-        }
+        // Save the current widgets tray?
+        // TODO(hyunyoungs)
         outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
 
         if (mLauncherCallbacks != null) {
@@ -2613,9 +2614,6 @@
         } else {
             showAppsView(true /* animated */, false /* resetListToTop */);
         }
-        if (mLauncherCallbacks != null) {
-            mLauncherCallbacks.onClickAllAppsButton(v);
-        }
     }
 
     private void showBrokenAppInstallDialog(final String packageName,
@@ -3276,9 +3274,7 @@
             SQLiteDatabase.releaseMemory();
 
             // This clears all widget bitmaps from the widget tray
-            if (mAppsCustomizeTabHost != null) {
-                mAppsCustomizeTabHost.trimMemory();
-            }
+            // TODO(hyunyoungs)
         }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.onTrimMemory(level);
@@ -3298,7 +3294,9 @@
     }
 
     void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
-        if (mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL) {
+        boolean changed = mState != State.WORKSPACE ||
+                mWorkspace.getState() != Workspace.State.NORMAL;
+        if (changed) {
             boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
             mWorkspace.setVisibility(View.VISIBLE);
             mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
@@ -3323,11 +3321,13 @@
         mUserPresent = true;
         updateAutoAdvanceState();
 
-        // Send an accessibility event to announce the context change
-        getWindow().getDecorView()
-                .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        if (changed) {
+            // Send an accessibility event to announce the context change
+            getWindow().getDecorView()
+                    .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
 
-        onWorkspaceShown(animated);
+            onWorkspaceShown(animated);
+        }
     }
 
     void showOverviewMode(boolean animated) {
@@ -3355,15 +3355,16 @@
      * Shows the widgets view.
      */
     void showWidgetsView(boolean animated, boolean resetPageToZero) {
+        Log.d(TAG, "showWidgetsView:" + animated + " resetPageToZero:" + resetPageToZero);
         if (resetPageToZero) {
-            mAppsCustomizeTabHost.reset();
+            mWidgetsView.scrollToTop();
         }
         showAppsOrWidgets(animated, State.WIDGETS);
-        mAppsCustomizeTabHost.post(new Runnable() {
+
+        mWidgetsView.post(new Runnable() {
             @Override
             public void run() {
-                // We post this in-case the all apps view isn't yet constructed.
-                mAppsCustomizeTabHost.requestFocus();
+                mWidgetsView.requestFocus();
             }
         });
     }
@@ -3377,6 +3378,9 @@
 
         if (toState == State.APPS) {
             mStateTransitionAnimation.startAnimationToAllApps(animated);
+            if (mLauncherCallbacks != null) {
+                mLauncherCallbacks.onAllAppsShown();
+            }
         } else {
             mStateTransitionAnimation.startAnimationToWidgets(animated);
         }
@@ -3394,7 +3398,9 @@
                 .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     }
 
-    void enterSpringLoadedDragMode() {
+    public void enterSpringLoadedDragMode() {
+        Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s",
+                mState.name()));
         if (mState == State.WORKSPACE || mState == State.APPS_SPRING_LOADED ||
                 mState == State.WIDGETS_SPRING_LOADED) {
             return;
@@ -3405,7 +3411,7 @@
         mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
     }
 
-    void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
+    public void exitSpringLoadedDragModeDelayed(final boolean successfulDrop, int delay,
             final Runnable onCompleteRunnable) {
         if (mState != State.APPS_SPRING_LOADED && mState != State.WIDGETS_SPRING_LOADED) return;
 
@@ -3413,10 +3419,12 @@
             @Override
             public void run() {
                 if (successfulDrop) {
+                    // TODO(hyunyoungs): verify if this hack is still needed, if not, delete.
+                    //
                     // Before we show workspace, hide all apps again because
                     // exitSpringLoadedDragMode made it visible. This is a bit hacky; we should
                     // clean up our state transition functions
-                    mAppsCustomizeTabHost.setVisibility(View.GONE);
+                    mWidgetsView.setVisibility(View.GONE);
                     showWorkspace(true, onCompleteRunnable);
                 } else {
                     exitSpringLoadedDragMode();
@@ -3918,8 +3926,8 @@
             pendingInfo.spanY = item.spanY;
             pendingInfo.minSpanX = item.minSpanX;
             pendingInfo.minSpanY = item.minSpanY;
-            Bundle options =
-                    AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+            Bundle options = null;
+            //        AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
 
             int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
             boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
@@ -4122,9 +4130,9 @@
         if (mAppsView != null) {
             mAppsView.setApps(apps);
         }
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.onPackagesUpdated(
-                    LauncherModel.getSortedWidgetsAndShortcuts(this, false /* refresh */));
+        if (mWidgetsView != null) {
+            mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
+                    getPackageManager());
         }
         if (mLauncherCallbacks != null) {
             mLauncherCallbacks.bindAllApplications(apps);
@@ -4276,15 +4284,16 @@
                 mWidgetsAndShortcuts = null;
             }
         };
+
     public void bindPackagesUpdated(final ArrayList<Object> widgetsAndShortcuts) {
         if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) {
             mWidgetsAndShortcuts = widgetsAndShortcuts;
             return;
         }
 
-        // Update the widgets pane
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts);
+        if (mWidgetsView != null) {
+            mWidgetsView.addWidgets(LauncherModel.getSortedWidgetsAndShortcuts(this, false),
+                    getPackageManager());
         }
     }
 
@@ -4577,10 +4586,8 @@
         Log.d(TAG, "mSavedInstanceState=" + mSavedInstanceState);
         Log.d(TAG, "sFolders.size=" + sFolders.size());
         mModel.dumpState();
+        // TODO(hyunyoungs): add mWidgetsView.dumpState(); or mWidgetsModel.dumpState();
 
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.dumpState();
-        }
         Log.d(TAG, "END launcher3 dump state");
     }
 
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2a08b81..3bd3850 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -141,7 +141,7 @@
         return mModel;
     }
 
-    LauncherAccessibilityDelegate getAccessibilityDelegate() {
+    public LauncherAccessibilityDelegate getAccessibilityDelegate() {
         return mAccessibilityDelegate;
     }
 
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index aeef0da..bb4580c 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -16,10 +16,10 @@
 public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo {
 
     public boolean isCustomWidget = false;
-    int spanX = -1;
-    int spanY = -1;
-    int minSpanX = -1;
-    int minSpanY = -1;
+    public int spanX = -1;
+    public int spanY = -1;
+    public int minSpanX = -1;
+    public int minSpanY = -1;
 
     public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context,
             AppWidgetProviderInfo info) {
@@ -78,10 +78,11 @@
         return super.loadIcon(context, cache.getFullResIconDpi());
     }
 
-    public String toString() {
+    public String toString(PackageManager pm) {
         if (isCustomWidget) {
-            return "LauncherAppWidgetProviderInfo(" + provider + ")";
+            return "WidgetProviderInfo(" + provider + ")";
         }
-        return super.toString();
+        return String.format("WidgetProviderInfo provider:%s package:%s short:%s label:%s span(%d, %d) minSpan(%d, %d)",
+                provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm), spanX, spanY, minSpanX, minSpanY);
     }
  }
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index d8128d6..2fee81c 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -50,6 +50,7 @@
     public void onLauncherProviderChange();
     public void finishBindingItems(final boolean upgradePath);
     public void onClickAllAppsButton(View v);
+    public void onAllAppsShown();
     public void bindAllApplications(ArrayList<AppInfo> apps);
     public void onClickFolderIcon(View v);
     public void onClickAppShortcut(View v);
@@ -87,6 +88,7 @@
     public ComponentName getWallpaperPickerComponent();
     public boolean overrideWallpaperDimensions();
     public boolean isLauncherPreinstalled();
+    public boolean overrideAllAppsSearch();
 
     /**
      * Returning true will immediately result in a call to {@link #setLauncherOverlayView(ViewGroup,
@@ -106,4 +108,12 @@
     public Launcher.LauncherOverlay setLauncherOverlayView(InsettableFrameLayout container,
             Launcher.LauncherOverlayCallbacks callbacks);
 
+    /**
+     * Sets the callbacks to allow any extensions to callback to the launcher.
+     *
+     * @param callbacks A set of callbacks to the Launcher, is actually a LauncherAppsCallback, but
+     *                  for implementation purposes is passed around as an object.
+     */
+    public void setLauncherAppsCallback(Object callbacks);
+
 }
diff --git a/src/com/android/launcher3/LauncherExtension.java b/src/com/android/launcher3/LauncherExtension.java
index fe9bd6c..e4fdbbc 100644
--- a/src/com/android/launcher3/LauncherExtension.java
+++ b/src/com/android/launcher3/LauncherExtension.java
@@ -124,6 +124,10 @@
         }
 
         @Override
+        public void onAllAppsShown() {
+        }
+
+        @Override
         public void bindAllApplications(ArrayList<AppInfo> apps) {
         }
 
@@ -246,6 +250,11 @@
         }
 
         @Override
+        public boolean overrideAllAppsSearch() {
+            return false;
+        }
+
+        @Override
         public boolean isLauncherPreinstalled() {
             return false;
         }
@@ -265,6 +274,11 @@
             return mLauncherOverlay;
         }
 
+        @Override
+        public void setLauncherAppsCallback(Object callbacks) {
+            // Do nothing
+        }
+
         class LauncherExtensionOverlay implements LauncherOverlay {
             LauncherOverlayCallbacks mLauncherOverlayCallbacks;
             ViewGroup mOverlayView;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 1f36331..98ba09b 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -3628,7 +3628,7 @@
         private final HashMap<Object, String> mLabelCache;
         private final Collator mCollator;
 
-        WidgetAndShortcutNameComparator(Context context) {
+        public WidgetAndShortcutNameComparator(Context context) {
             mManager = AppWidgetManagerCompat.getInstance(context);
             mPackageManager = context.getPackageManager();
             mLabelCache = new HashMap<Object, String>();
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index d657cb5..111de40 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -22,7 +22,7 @@
 /**
  * Settings related utilities.
  */
-class LauncherSettings {
+public class LauncherSettings {
     /** Columns required on table staht will be subject to backup and restore. */
     static interface ChangeLogColumns extends BaseColumns {
         /**
@@ -121,7 +121,7 @@
     /**
      * Favorites.
      */
-    static final class Favorites implements BaseLauncherColumns {
+    public static final class Favorites implements BaseLauncherColumns {
         /**
          * The content:// style URL for this table
          */
@@ -217,12 +217,12 @@
         /**
          * The favorite is a widget
          */
-        static final int ITEM_TYPE_APPWIDGET = 4;
+        public static final int ITEM_TYPE_APPWIDGET = 4;
 
         /**
          * The favorite is a custom widget provided by the launcher
          */
-        static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
+        public static final int ITEM_TYPE_CUSTOM_APPWIDGET = 5;
 
         /**
          * The favorite is a clock
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index eacf341..57bd5b2 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -23,6 +23,7 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeInterpolator;
 import android.content.res.Resources;
+import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewAnimationUtils;
@@ -30,6 +31,7 @@
 import android.view.animation.DecelerateInterpolator;
 
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetsContainerView;
 
 import java.util.HashMap;
 
@@ -172,27 +174,19 @@
             }
         };
         startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
-                toView.getRevealView(), null, animated, cb);
+                toView.getRevealView(), animated, false /* hideSearchBar */, cb);
     }
 
     /**
      * Starts an animation to the widgets view.
      */
     public void startAnimationToWidgets(final boolean animated) {
-        final AppsCustomizeTabHost toView = mLauncher.getWidgetsView();
+        final WidgetsContainerView toView = mLauncher.getWidgetsView();
         PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
             @Override
             public void onRevealViewVisible(View revealView, View contentView,
                     View allAppsButtonView) {
-                // Hide the real page background, and swap in the fake one
-                ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(false);
-                revealView.setBackground(
-                        mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark));
-            }
-            @Override
-            public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
-                // Show the real page background
-                ((AppsCustomizePagedView) contentView).setPageBackgroundsVisible(true);
+                revealView.setBackground(mLauncher.getDrawable(R.drawable.quantum_panel_dark));
             }
             @Override
             public float getMaterialRevealViewFinalAlpha(View revealView) {
@@ -204,7 +198,7 @@
             }
         };
         startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, toView, toView.getContentView(),
-                toView.getRevealView(), toView.getPageIndicators(), animated, cb);
+                toView.getRevealView(), animated, true /* hideSearchBar */, cb);
     }
 
     /**
@@ -232,8 +226,8 @@
      * Creates and starts a new animation to a particular overlay view.
      */
     private void startAnimationToOverlay(final Workspace.State toWorkspaceState, final View toView,
-             final View contentView, final View revealView, final View pageIndicatorsView,
-             final boolean animated, final PrivateTransitionCallbacks pCb) {
+             final View contentView, final View revealView, final boolean animated,
+             final boolean hideSearchBar, final PrivateTransitionCallbacks pCb) {
         final Resources res = mLauncher.getResources();
         final boolean material = Utilities.isLmpOrAbove();
         final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
@@ -299,15 +293,6 @@
             layerViews.put(revealView, BUILD_AND_SET_LAYER);
             mStateAnimation.play(panelAlphaAndDrift);
 
-            // Setup the animation for the page indicators
-            if (pageIndicatorsView != null) {
-                pageIndicatorsView.setAlpha(0.01f);
-                ObjectAnimator indicatorsAlpha =
-                        ObjectAnimator.ofFloat(pageIndicatorsView, "alpha", 1f);
-                indicatorsAlpha.setDuration(revealDuration);
-                mStateAnimation.play(indicatorsAlpha);
-            }
-
             // Setup the animation for the content view
             contentView.setVisibility(View.VISIBLE);
             contentView.setAlpha(0f);
@@ -360,8 +345,9 @@
                         }
                     }
 
-                    // Hide the search bar
-                    mCb.onStateTransitionHideSearchBar();
+                    if (hideSearchBar) {
+                        mCb.onStateTransitionHideSearchBar();
+                    }
 
                     // This can hold unnecessary references to views.
                     mStateAnimation = null;
@@ -420,8 +406,9 @@
             // Show the content view
             contentView.setVisibility(View.VISIBLE);
 
-            // Hide the search bar
-            mCb.onStateTransitionHideSearchBar();
+            if (hideSearchBar) {
+                mCb.onStateTransitionHideSearchBar();
+            }
 
             dispatchOnLauncherTransitionPrepare(fromView, animated, false);
             dispatchOnLauncherTransitionStart(fromView, animated, false);
@@ -490,8 +477,7 @@
             }
         };
         startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
-                appsView.getRevealView(), null /* pageIndicatorsView */, animated,
-                onCompleteRunnable, cb);
+                appsView.getRevealView(), animated, onCompleteRunnable, cb);
     }
 
     /**
@@ -500,45 +486,9 @@
     private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
               final Workspace.State toWorkspaceState, final boolean animated,
               final Runnable onCompleteRunnable) {
-        AppsCustomizeTabHost widgetsView = mLauncher.getWidgetsView();
+        WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
         PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
             @Override
-            public void onRevealViewVisible(View revealView, View contentView, View allAppsButtonView) {
-                AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
-
-                // Hide the real page background, and swap in the fake one
-                pagedView.stopScrolling();
-                pagedView.setPageBackgroundsVisible(false);
-                revealView.setBackground(
-                        mLauncher.getResources().getDrawable(R.drawable.quantum_panel_dark));
-
-                // Hide the side pages of the Widget tray to avoid some ugly edge cases
-                final View currentPage = pagedView.getPageAt(pagedView.getNextPage());
-                int count = pagedView.getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View child = pagedView.getChildAt(i);
-                    if (child != currentPage) {
-                        child.setVisibility(View.INVISIBLE);
-                    }
-                }
-            }
-            @Override
-            public void onAnimationComplete(View revealView, View contentView, View allAppsButtonView) {
-                AppsCustomizePagedView pagedView = ((AppsCustomizePagedView) contentView);
-
-                // Show the real page background and force-update the page
-                pagedView.setPageBackgroundsVisible(true);
-                pagedView.setCurrentPage(pagedView.getNextPage());
-                pagedView.updateCurrentPageScroll();
-
-                // Unhide the side pages
-                int count = pagedView.getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View child = pagedView.getChildAt(i);
-                    child.setVisibility(View.VISIBLE);
-                }
-            }
-            @Override
             public float getMaterialRevealViewFinalYDrift(View revealView) {
                 return revealView.getMeasuredHeight() / 2;
             }
@@ -558,8 +508,8 @@
             }
         };
         startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
-                widgetsView.getContentView(), widgetsView.getRevealView(),
-                widgetsView.getPageIndicators(), animated, onCompleteRunnable, cb);
+                widgetsView.getContentView(), widgetsView.getRevealView(), animated,
+                onCompleteRunnable, cb);
     }
 
     /**
@@ -567,8 +517,8 @@
      */
     private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
               final View fromView, final View contentView, final View revealView,
-              final View pageIndicatorsView, final boolean animated,
-              final Runnable onCompleteRunnable, final PrivateTransitionCallbacks pCb) {
+              final boolean animated, final Runnable onCompleteRunnable,
+              final PrivateTransitionCallbacks pCb) {
         final Resources res = mLauncher.getResources();
         final boolean material = Utilities.isLmpOrAbove();
         final int revealDuration = res.getInteger(R.integer.config_appsCustomizeRevealTime);
@@ -673,16 +623,6 @@
                 itemsAlpha.setInterpolator(decelerateInterpolator);
                 mStateAnimation.play(itemsAlpha);
 
-                // Setup the page indicators animation
-                if (pageIndicatorsView != null) {
-                    pageIndicatorsView.setAlpha(1f);
-                    ObjectAnimator indicatorsAlpha =
-                            LauncherAnimUtils.ofFloat(pageIndicatorsView, "alpha", 0f);
-                    indicatorsAlpha.setDuration(revealDuration);
-                    indicatorsAlpha.setInterpolator(new DecelerateInterpolator(1.5f));
-                    mStateAnimation.play(indicatorsAlpha);
-                }
-
                 if (material) {
                     // Animate the all apps button
                     float finalRadius = pCb.getMaterialRevealViewStartFinalRadius();
diff --git a/src/com/android/launcher3/PagedViewGridLayout.java b/src/com/android/launcher3/PagedViewGridLayout.java
deleted file mode 100644
index f69fa56..0000000
--- a/src/com/android/launcher3/PagedViewGridLayout.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.GridLayout;
-
-/**
- * The grid based layout used strictly for the widget/wallpaper tab of the AppsCustomize pane
- */
-public class PagedViewGridLayout extends GridLayout implements Page {
-    static final String TAG = "PagedViewGridLayout";
-
-    private int mCellCountX;
-    private int mCellCountY;
-    private Runnable mOnLayoutListener;
-
-    public PagedViewGridLayout(Context context, int cellCountX, int cellCountY) {
-        super(context, null, 0);
-        mCellCountX = cellCountX;
-        mCellCountY = cellCountY;
-    }
-
-    int getCellCountX() {
-        return mCellCountX;
-    }
-
-    int getCellCountY() {
-        return mCellCountY;
-    }
-
-    /**
-     * Clears all the key listeners for the individual widgets.
-     */
-    public void resetChildrenOnKeyListeners() {
-        int childCount = getChildCount();
-        for (int j = 0; j < childCount; ++j) {
-            getChildAt(j).setOnKeyListener(null);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mOnLayoutListener = null;
-    }
-
-    public void setOnLayoutListener(Runnable r) {
-        mOnLayoutListener = r;
-    }
-
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mOnLayoutListener != null) {
-            mOnLayoutListener.run();
-        }
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        boolean result = super.onTouchEvent(event);
-        int count = getPageChildCount();
-        if (count > 0) {
-            // We only intercept the touch if we are tapping in empty space after the final row
-            View child = getChildOnPageAt(count - 1);
-            int bottom = child.getBottom();
-            result = result || (event.getY() < bottom);
-        }
-        return result;
-    }
-
-    @Override
-    public void removeAllViewsOnPage() {
-        removeAllViews();
-        mOnLayoutListener = null;
-        setLayerType(LAYER_TYPE_NONE, null);
-    }
-
-    @Override
-    public void removeViewOnPageAt(int index) {
-        removeViewAt(index);
-    }
-
-    @Override
-    public int getPageChildCount() {
-        return getChildCount();
-    }
-
-    @Override
-    public View getChildOnPageAt(int i) {
-        return getChildAt(i);
-    }
-
-    @Override
-    public int indexOfChildOnPage(View v) {
-        return indexOfChild(v);
-    }
-
-    public static class LayoutParams extends FrameLayout.LayoutParams {
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/PagedViewWithDraggableItems.java b/src/com/android/launcher3/PagedViewWithDraggableItems.java
deleted file mode 100644
index f0743cf..0000000
--- a/src/com/android/launcher3/PagedViewWithDraggableItems.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-
-/* Class that does most of the work of enabling dragging items out of a PagedView by performing a
- * vertical drag. Used by both CustomizePagedView and AllAppsPagedView.
- * Subclasses must do the following:
- *   * call setDragSlopeThreshold after making an instance of the PagedViewWithDraggableItems
- *   * call child.setOnLongClickListener(this) and child.setOnTouchListener(this) on all children
- *       (good place to do it is in syncPageItems)
- *   * override beginDragging(View) (but be careful to call super.beginDragging(View)
- *
- */
-public abstract class PagedViewWithDraggableItems extends PagedView
-    implements View.OnLongClickListener, View.OnTouchListener {
-    private View mLastTouchedItem;
-    private boolean mIsDragging;
-    private boolean mIsDragEnabled;
-    private float mDragSlopeThreshold;
-    private Launcher mLauncher;
-
-    public PagedViewWithDraggableItems(Context context) {
-        this(context, null);
-    }
-
-    public PagedViewWithDraggableItems(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public PagedViewWithDraggableItems(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mLauncher = (Launcher) context;
-    }
-
-    protected boolean beginDragging(View v) {
-        boolean wasDragging = mIsDragging;
-        mIsDragging = true;
-        return !wasDragging;
-    }
-
-    protected void cancelDragging() {
-        mIsDragging = false;
-        mLastTouchedItem = null;
-        mIsDragEnabled = false;
-    }
-
-    private void handleTouchEvent(MotionEvent ev) {
-        final int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN:
-                cancelDragging();
-                mIsDragEnabled = true;
-                break;
-            case MotionEvent.ACTION_MOVE:
-                if (mTouchState != TOUCH_STATE_SCROLLING && !mIsDragging && mIsDragEnabled) {
-                    determineDraggingStart(ev);
-                }
-                break;
-        }
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        handleTouchEvent(ev);
-        return super.onInterceptTouchEvent(ev);
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        handleTouchEvent(ev);
-        return super.onTouchEvent(ev);
-    }
-
-    public void trimMemory() {
-        mLastTouchedItem = null;
-    }
-
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        mLastTouchedItem = v;
-        mIsDragEnabled = true;
-        return false;
-    }
-
-    @Override
-    public boolean onLongClick(View v) {
-        // Return early if this is not initiated from a touch
-        if (!v.isInTouchMode()) return false;
-        // Return early if we are still animating the pages
-        if (mNextPage != INVALID_PAGE) return false;
-        // When we have exited all apps or are in transition, disregard long clicks
-        if (!mLauncher.isWidgetsViewVisible() ||
-                mLauncher.getWorkspace().isSwitchingState()) return false;
-        // Return if global dragging is not enabled
-        if (!mLauncher.isDraggingEnabled()) return false;
-
-        return beginDragging(v);
-    }
-
-    /*
-     * Determines if we should change the touch state to start scrolling after the
-     * user moves their touch point too far.
-     */
-    protected void determineScrollingStart(MotionEvent ev) {
-        if (!mIsDragging) super.determineScrollingStart(ev);
-    }
-
-    /*
-     * Determines if we should change the touch state to start dragging after the
-     * user moves their touch point far enough.
-     */
-    protected void determineDraggingStart(MotionEvent ev) {
-        /*
-         * Locally do absolute value. mLastMotionX is set to the y value
-         * of the down event.
-         */
-        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
-        final float x = ev.getX(pointerIndex);
-        final float y = ev.getY(pointerIndex);
-        final int xDiff = (int) Math.abs(x - mLastMotionX);
-        final int yDiff = (int) Math.abs(y - mLastMotionY);
-
-        final int touchSlop = mTouchSlop;
-        boolean yMoved = yDiff > touchSlop;
-        boolean isUpwardMotion = (yDiff / (float) xDiff) > mDragSlopeThreshold;
-
-        if (isUpwardMotion && yMoved && mLastTouchedItem != null) {
-            // Drag if the user moved far enough along the Y axis
-            beginDragging(mLastTouchedItem);
-
-            // Cancel any pending long press
-            if (mAllowLongPress) {
-                mAllowLongPress = false;
-                // Try canceling the long press. It could also have been scheduled
-                // by a distant descendant, so use the mAllowLongPress flag to block
-                // everything
-                final View currentPage = getPageAt(mCurrentPage);
-                if (currentPage != null) {
-                    currentPage.cancelLongPress();
-                }
-            }
-        }
-    }
-
-    public void setDragSlopeThreshold(float dragSlopeThreshold) {
-        mDragSlopeThreshold = dragSlopeThreshold;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        cancelDragging();
-        super.onDetachedFromWindow();
-    }
-}
diff --git a/src/com/android/launcher3/PendingAddItemInfo.java b/src/com/android/launcher3/PendingAddItemInfo.java
index ac54a26..1aaf85b 100644
--- a/src/com/android/launcher3/PendingAddItemInfo.java
+++ b/src/com/android/launcher3/PendingAddItemInfo.java
@@ -16,93 +16,17 @@
 
 package com.android.launcher3;
 
-import android.appwidget.AppWidgetHostView;
 import android.content.ComponentName;
-import android.content.pm.ActivityInfo;
-import android.os.Bundle;
-import android.os.Parcelable;
 
 /**
- * We pass this object with a drag from the customization tray
+ * Meta data that is used for deferred binding.
+ * e.g., this object is used to pass information on dragable targets when they are dropped onto
+ * the workspace from another container.
  */
-class PendingAddItemInfo extends ItemInfo {
+public class PendingAddItemInfo extends ItemInfo {
+
     /**
      * The component that will be created.
      */
-    ComponentName componentName;
-}
-
-class PendingAddShortcutInfo extends PendingAddItemInfo {
-
-    ActivityInfo shortcutActivityInfo;
-
-    public PendingAddShortcutInfo(ActivityInfo activityInfo) {
-        shortcutActivityInfo = activityInfo;
-    }
-
-    @Override
-    public String toString() {
-        return "Shortcut: " + shortcutActivityInfo.packageName;
-    }
-}
-
-class PendingAddWidgetInfo extends PendingAddItemInfo {
-    int minWidth;
-    int minHeight;
-    int minResizeWidth;
-    int minResizeHeight;
-    int previewImage;
-    int icon;
-    LauncherAppWidgetProviderInfo info;
-    AppWidgetHostView boundWidget;
-    Bundle bindOptions = null;
-
-    public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) {
-        if (i.isCustomWidget) {
-            itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-        } else {
-            itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
-        }
-        this.info = i;
-        componentName = i.provider;
-        minWidth = i.minWidth;
-        minHeight = i.minHeight;
-        minResizeWidth = i.minResizeWidth;
-        minResizeHeight = i.minResizeHeight;
-        previewImage = i.previewImage;
-        icon = i.icon;
-
-        spanX = i.spanX;
-        spanY = i.spanY;
-        minSpanX = i.minSpanX;
-        minSpanY = i.minSpanY;
-    }
-
-    public boolean isCustomWidget() {
-        return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-    }
-
-    // Copy constructor
-    public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
-        minWidth = copy.minWidth;
-        minHeight = copy.minHeight;
-        minResizeWidth = copy.minResizeWidth;
-        minResizeHeight = copy.minResizeHeight;
-        previewImage = copy.previewImage;
-        icon = copy.icon;
-        info = copy.info;
-        boundWidget = copy.boundWidget;
-        componentName = copy.componentName;
-        itemType = copy.itemType;
-        spanX = copy.spanX;
-        spanY = copy.spanY;
-        minSpanX = copy.minSpanX;
-        minSpanY = copy.minSpanY;
-        bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
-    }
-
-    @Override
-    public String toString() {
-        return "Widget: " + componentName.toShortString();
-    }
+    public ComponentName componentName;
 }
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 1043e2e..5c3ed92 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -32,6 +32,7 @@
 import com.android.launcher3.compat.UserManagerCompat;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.WidgetCell;
 
 import java.lang.ref.WeakReference;
 import java.util.Collections;
@@ -45,6 +46,7 @@
 public class WidgetPreviewLoader {
 
     private static final String TAG = "WidgetPreviewLoader";
+    private static final boolean DEBUG = false;
 
     private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f;
 
@@ -78,7 +80,7 @@
      * @return a request id which can be used to cancel the request.
      */
     public PreviewLoadRequest getPreview(final Object o, int previewWidth, int previewHeight,
-            PagedViewWidget caller, Bitmap[] immediateResult) {
+            WidgetCell caller, Bitmap[] immediateResult) {
         String size = previewWidth + "x" + previewHeight;
         WidgetCacheKey key = getObjectKey(o, size);
 
@@ -576,21 +578,26 @@
         private final Object mInfo;
         private final int mPreviewHeight;
         private final int mPreviewWidth;
-        private final PagedViewWidget mCaller;
+        private final WidgetCell mCaller;
 
         PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth,
-                int previewHeight, PagedViewWidget caller) {
+                int previewHeight, WidgetCell caller) {
             mKey = key;
             mInfo = info;
             mPreviewHeight = previewHeight;
             mPreviewWidth = previewWidth;
             mCaller = caller;
+            if (DEBUG) {
+                Log.d(TAG, String.format("%s, %s, %d, %d",
+                        mKey, mInfo, mPreviewHeight, mPreviewWidth));
+            }
         }
 
-
         @Override
         protected Bitmap doInBackground(Void... params) {
             Bitmap unusedBitmap = null;
+
+            // TODO(hyunyoungs): Figure out why this path causes concurrency issue.
             synchronized (mUnusedBitmaps) {
                 // Check if we can use a bitmap
                 for (Bitmap candidate : mUnusedBitmaps) {
@@ -608,7 +615,6 @@
                     mUnusedBitmaps.remove(unusedBitmap);
                 }
             }
-
             if (isCancelled()) {
                 return null;
             }
diff --git a/src/com/android/launcher3/WidgetsContainerView.java b/src/com/android/launcher3/WidgetsContainerView.java
deleted file mode 100644
index 7004d8b..0000000
--- a/src/com/android/launcher3/WidgetsContainerView.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.android.launcher3;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-
-class SectionedWidgetsRow {
-    String section;
-    List<List<Object>> widgets;
-
-    public SectionedWidgetsRow(String sc) {
-        section = sc;
-    }
-}
-
-class SectionedWidgetsAlgorithm {
-    public List<SectionedWidgetsRow> computeSectionedWidgetRows(List<Object> sortedWidgets,
-            int widgetsPerRow) {
-        List<SectionedWidgetsRow> rows = new ArrayList<>();
-        LinkedHashMap<String, List<Object>> sections = computeSectionedApps(sortedWidgets);
-        for (Map.Entry<String, List<Object>> sectionEntry : sections.entrySet()) {
-            String section = sectionEntry.getKey();
-            SectionedWidgetsRow row = new SectionedWidgetsRow(section);
-            List<Object> widgets = sectionEntry.getValue();
-            int numRows = (int) Math.ceil((float) widgets.size() / widgetsPerRow);
-            for (int i = 0; i < numRows; i++) {
-                List<Object> widgetsInRow = new ArrayList<>();
-                int offset = i * widgetsPerRow;
-                for (int j = 0; j < widgetsPerRow; j++) {
-                    widgetsInRow.add(widgets.get(offset + j));
-                }
-                row.widgets.add(widgetsInRow);
-            }
-        }
-        return rows;
-    }
-
-    private LinkedHashMap<String, List<Object>> computeSectionedApps(List<Object> sortedWidgets) {
-        LinkedHashMap<String, List<Object>> sections = new LinkedHashMap<>();
-        for (Object info : sortedWidgets) {
-            String section = getSection(info);
-            List<Object> sectionedWidgets = sections.get(section);
-            if (sectionedWidgets == null) {
-                sectionedWidgets = new ArrayList<>();
-                sections.put(section, sectionedWidgets);
-            }
-            sectionedWidgets.add(info);
-        }
-        return sections;
-    }
-
-    private String getSection(Object widgetOrShortcut) {
-        return "UNKNOWN";
-    }
-}
-
-/**
- * The widgets list view container.
- */
-public class WidgetsContainerView extends FrameLayout {
-
-
-    public WidgetsContainerView(Context context) {
-        this(context, null);
-    }
-
-    public WidgetsContainerView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-    }
-}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a79add0..9173971 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -71,6 +71,8 @@
 import com.android.launcher3.compat.UserHandleCompat;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperUtils;
+import com.android.launcher3.widget.PendingAddShortcutInfo;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -1698,7 +1700,11 @@
 
         mLastCustomContentScrollProgress = progress;
 
-        mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+        // We should only update the drag layer background alpha if we are not in all apps or the
+        // widgets tray
+        if (mState == State.NORMAL) {
+            mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);
+        }
 
         if (mLauncher.getHotseat() != null) {
             mLauncher.getHotseat().setTranslationX(translationX);
@@ -2250,7 +2256,8 @@
         float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
         float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
         float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
-        float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;
+        // We keep the search bar visible on the workspace and in AllApps now
+        float finalSearchBarAlpha = (stateIsNormal || stateIsNormalHidden) ? 1f : 0f;
         float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
                 getOverviewModeTranslationY() : 0;
 
diff --git a/src/com/android/launcher3/widget/PackageItemInfo.java b/src/com/android/launcher3/widget/PackageItemInfo.java
new file mode 100644
index 0000000..d7edf22
--- /dev/null
+++ b/src/com/android/launcher3/widget/PackageItemInfo.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.ComponentName;
+import android.graphics.Bitmap;
+
+import com.android.launcher3.ItemInfo;
+
+import java.util.Arrays;
+
+/**
+ * Represents a {@link Package} in the widget tray section.
+ */
+public class PackageItemInfo extends ItemInfo {
+    private static final String TAG = "PackageInfo";
+
+    /**
+     * A bitmap version of the application icon.
+     */
+    public Bitmap iconBitmap;
+
+    /**
+     * Indicates whether we're using a low res icon
+     */
+    public boolean usingLowResIcon;
+
+    public ComponentName componentName;
+
+    int flags = 0;
+
+    PackageItemInfo() {
+    }
+
+    @Override
+    public String toString() {
+        return "PackageItemInfo(title=" + title.toString() + " id=" + this.id
+                + " type=" + this.itemType + " container=" + this.container
+                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
+                + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + Arrays.toString(dropPos)
+                + " user=" + user + ")";
+    }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddShortcutInfo.java b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
new file mode 100644
index 0000000..a569850
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddShortcutInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+
+/**
+ * Meta data used for late binding of the short cuts.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddShortcutInfo extends PendingAddItemInfo {
+
+    ActivityInfo activityInfo;
+
+    public PendingAddShortcutInfo(ActivityInfo activityInfo) {
+        this.activityInfo = activityInfo;
+        componentName = new ComponentName(activityInfo.packageName, activityInfo.name);
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PendingAddShortcutInfo package=%s, name=%s",
+                activityInfo.packageName, activityInfo.name);
+    }
+}
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
new file mode 100644
index 0000000..db16998
--- /dev/null
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.os.Bundle;
+import android.os.Parcelable;
+
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.PendingAddItemInfo;
+
+/**
+ * Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}.
+ *
+ * @see {@link PendingAddItemInfo}
+ */
+public class PendingAddWidgetInfo extends PendingAddItemInfo {
+    public int minWidth;
+    public int minHeight;
+    public int minResizeWidth;
+    public int minResizeHeight;
+    public int previewImage;
+    public int icon;
+    public LauncherAppWidgetProviderInfo info;
+    public AppWidgetHostView boundWidget;
+    public Bundle bindOptions = null;
+
+    public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, Parcelable data) {
+        if (i.isCustomWidget) {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+        } else {
+            itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+        }
+        this.info = i;
+        componentName = i.provider;
+        minWidth = i.minWidth;
+        minHeight = i.minHeight;
+        minResizeWidth = i.minResizeWidth;
+        minResizeHeight = i.minResizeHeight;
+        previewImage = i.previewImage;
+        icon = i.icon;
+
+        spanX = i.spanX;
+        spanY = i.spanY;
+        minSpanX = i.minSpanX;
+        minSpanY = i.minSpanY;
+    }
+
+    public boolean isCustomWidget() {
+        return itemType == LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+    }
+
+    // Copy constructor
+    public PendingAddWidgetInfo(PendingAddWidgetInfo copy) {
+        minWidth = copy.minWidth;
+        minHeight = copy.minHeight;
+        minResizeWidth = copy.minResizeWidth;
+        minResizeHeight = copy.minResizeHeight;
+        previewImage = copy.previewImage;
+        icon = copy.icon;
+        info = copy.info;
+        boundWidget = copy.boundWidget;
+        componentName = copy.componentName;
+        itemType = copy.itemType;
+        spanX = copy.spanX;
+        spanY = copy.spanY;
+        minSpanX = copy.minSpanX;
+        minSpanY = copy.minSpanY;
+        bindOptions = copy.bindOptions == null ? null : (Bundle) copy.bindOptions.clone();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("PendingAddWidgetInfo package=%s, name=%s",
+                componentName.getPackageName(), componentName.getShortClassName());
+    }
+}
diff --git a/src/com/android/launcher3/PagedViewWidget.java b/src/com/android/launcher3/widget/WidgetCell.java
similarity index 79%
rename from src/com/android/launcher3/PagedViewWidget.java
rename to src/com/android/launcher3/widget/WidgetCell.java
index d9ca7be..93ee94a 100644
--- a/src/com/android/launcher3/PagedViewWidget.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.widget;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -23,6 +23,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.MotionEvent;
 import android.view.View;
@@ -31,15 +32,31 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.WidgetPreviewLoader;
 import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
 import com.android.launcher3.compat.AppWidgetManagerCompat;
 
 /**
- * The linear layout used strictly for the widget/wallpaper tab of the customization tray
+ * The linear layout used strictly for the widget tray.
  */
-public class PagedViewWidget extends LinearLayout implements OnLayoutChangeListener {
+public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
 
-    private static PagedViewWidget sShortpressTarget = null;
+    private static final String TAG = "PagedViewWidget";
+    private static final boolean DEBUG = false;
+
+    // Temporary preset width and height of the image to keep them aligned.
+    //private static final int PRESET_PREVIEW_HEIGHT = 480;
+    //private static final int PRESET_PREVIEW_WIDTH = 480;
+
+    private int mPresetPreviewSize;
+
+    private static WidgetCell sShortpressTarget = null;
 
     private final Rect mOriginalImagePadding = new Rect();
 
@@ -53,23 +70,25 @@
     private WidgetPreviewLoader mWidgetPreviewLoader;
     private PreviewLoadRequest mActiveRequest;
 
-    public PagedViewWidget(Context context) {
+    public WidgetCell(Context context) {
         this(context, null);
     }
 
-    public PagedViewWidget(Context context, AttributeSet attrs) {
+    public WidgetCell(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public PagedViewWidget(Context context, AttributeSet attrs, int defStyle) {
+    public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         final Resources r = context.getResources();
         mDimensionsFormatString = r.getString(R.string.widget_dims_format);
+        mPresetPreviewSize = r.getDimensionPixelSize(R.dimen.widget_preview_size);
 
         setWillNotDraw(false);
         setClipToPadding(false);
         setAccessibilityDelegate(LauncherAppState.getInstance().getAccessibilityDelegate());
+
     }
 
     @Override
@@ -97,6 +116,9 @@
 
     @Override
     protected void onDetachedFromWindow() {
+        if (DEBUG) {
+            Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
+        }
         super.onDetachedFromWindow();
         deletePreview(true);
     }
@@ -154,15 +176,19 @@
     public int[] getPreviewSize() {
         final ImageView i = (ImageView) findViewById(R.id.widget_preview);
         int[] maxSize = new int[2];
-        maxSize[0] = i.getWidth() - mOriginalImagePadding.left - mOriginalImagePadding.right;
-        maxSize[1] = i.getHeight() - mOriginalImagePadding.top;
+        maxSize[0] = mPresetPreviewSize;
+        maxSize[1] = mPresetPreviewSize;
         return maxSize;
     }
 
     public void applyPreview(Bitmap bitmap) {
         FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
-        final PagedViewWidgetImageView image =
-            (PagedViewWidgetImageView) findViewById(R.id.widget_preview);
+        final WidgetImageView image =
+            (WidgetImageView) findViewById(R.id.widget_preview);
+        if (DEBUG) {
+            Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s",
+                    getTagToString(), preview));
+        }
         if (preview != null) {
             image.mAllowRequestLayout = false;
             image.setImageDrawable(preview);
@@ -177,6 +203,7 @@
             }
             image.setAlpha(1f);
             image.mAllowRequestLayout = true;
+            image.requestLayout();
         }
     }
 
@@ -193,8 +220,8 @@
         public void run() {
             if (sShortpressTarget != null) return;
             if (mShortPressListener != null) {
-                mShortPressListener.onShortPress(PagedViewWidget.this);
-                sShortpressTarget = PagedViewWidget.this;
+                mShortPressListener.onShortPress(WidgetCell.this);
+                sShortpressTarget = WidgetCell.this;
             }
             mShortPressTriggered = true;
         }
@@ -221,7 +248,7 @@
         removeShortPressCallback();
         if (mShortPressTriggered) {
             if (mShortPressListener != null) {
-                mShortPressListener.cleanUpShortPress(PagedViewWidget.this);
+                mShortPressListener.cleanUpShortPress(WidgetCell.this);
             }
             mShortPressTriggered = false;
         }
@@ -264,6 +291,10 @@
             return;
         }
         int[] size = getPreviewSize();
+        if (DEBUG) {
+            Log.d(TAG, String.format("[tag=%s] ensurePreview (%d, %d):",
+                    getTagToString(), size[0], size[1]));
+        }
 
         if (size[0] <= 0 || size[1] <= 0) {
             addOnLayoutChangeListener(this);
@@ -292,4 +323,16 @@
 
         return Math.min(size[0], info.spanX * cellWidth);
     }
+
+    /**
+     * Helper method to get the string info of the tag.
+     */
+    private String getTagToString() {
+        if (getTag() instanceof PendingAddWidgetInfo) {
+            return ((PendingAddWidgetInfo)getTag()).toString();
+        } else if (getTag() instanceof PendingAddShortcutInfo) {
+            return ((PendingAddShortcutInfo)getTag()).toString();
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/launcher3/PagedViewWidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
similarity index 88%
rename from src/com/android/launcher3/PagedViewWidgetImageView.java
rename to src/com/android/launcher3/widget/WidgetImageView.java
index 7d82795..75167bc 100644
--- a/src/com/android/launcher3/PagedViewWidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.launcher3;
+package com.android.launcher3.widget;
 
 import android.content.Context;
 import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.widget.ImageView;
 
-public class PagedViewWidgetImageView extends ImageView {
+public class WidgetImageView extends ImageView {
     public boolean mAllowRequestLayout = true;
 
-    public PagedViewWidgetImageView(Context context, AttributeSet attrs) {
+    public WidgetImageView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
@@ -44,6 +44,5 @@
 
         super.onDraw(canvas);
         canvas.restore();
-
     }
 }
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
new file mode 100644
index 0000000..5aa80a9
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeleteDropTarget;
+import com.android.launcher3.DragController;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.FastBitmapDrawable;
+import com.android.launcher3.Folder;
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.PendingAddItemInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.Workspace;
+
+import java.util.ArrayList;
+
+/**
+ * The widgets list view container.
+ */
+public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
+        View.OnLongClickListener, DragSource{
+
+    private static final String TAG = "WidgetContainerView";
+    private static final boolean DEBUG = false;
+
+    /* {@link RecyclerView} will keep following # of views in cache, before recycling. */
+    private static final int WIDGET_CACHE_SIZE = 2;
+
+    /* Global instances that are used inside this container. */
+    private Launcher mLauncher;
+    private DragController mDragController;
+    private IconCache mIconCache;
+
+    /* Data model for the widget */
+    private WidgetsModel mWidgets;
+
+    /* Recycler view related member variables */
+    private RecyclerView mView;
+    private WidgetsListAdapter mAdapter;
+
+    /* Dragging related. */
+    private boolean mDraggingWidget = false;    // TODO(hyunyoungs): seems not needed? check!
+    private Point mLastTouchDownPos = new Point();
+
+    /* Rendering related. */
+    private WidgetPreviewLoader mWidgetPreviewLoader;
+    private Rect mPadding = new Rect();
+
+    public WidgetsContainerView(Context context) {
+        this(context, null);
+    }
+
+    public WidgetsContainerView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetsContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLauncher = (Launcher) context;
+        mDragController = mLauncher.getDragController();
+
+        mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
+        mWidgets = new WidgetsModel(context, mAdapter);
+        mAdapter.setWidgetsModel(mWidgets);
+        mIconCache = (LauncherAppState.getInstance()).getIconCache();
+
+        if (DEBUG) {
+            Log.d(TAG, "WidgetsContainerView constructor");
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        if (DEBUG) {
+            Log.d(TAG, String.format("onFinishInflate [widgets size=%d]",
+                    mWidgets.getPackageSize()));
+        }
+        mView = (RecyclerView) findViewById(R.id.widgets_list_view);
+        mView.setAdapter(mAdapter);
+        mView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mView.setItemViewCacheSize(WIDGET_CACHE_SIZE);
+
+        mPadding.set(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
+                getPaddingBottom());
+    }
+
+    //
+    // Returns views used for launcher transitions.
+    //
+
+    public View getContentView() {
+        return findViewById(R.id.widgets_list_view);
+    }
+
+    public View getRevealView() {
+        // TODO(hyunyoungs): temporarily use apps view transition.
+        return findViewById(R.id.widgets_reveal_view);
+    }
+
+    public void scrollToTop() {
+        mView.scrollToPosition(0);
+        if (DEBUG) {
+            Log.d(TAG, String.format("scrollToTop, [widgets size=%d]",
+                    mWidgets.getPackageSize()));
+        }
+    }
+
+    //
+    // Touch related handling.
+    //
+
+    @Override
+    public boolean onLongClick(View v) {
+        if (DEBUG) {
+            Log.d(TAG, String.format("onLonglick [v=%s]", v));
+        }
+
+        // Return early if this is not initiated from a touch
+        if (!v.isInTouchMode()) return false;
+        // When we have exited all apps or are in transition, disregard long clicks
+        if (!mLauncher.isWidgetsViewVisible() ||
+                mLauncher.getWorkspace().isSwitchingState()) return false;
+        // Return if global dragging is not enabled
+        Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
+        if (!mLauncher.isDraggingEnabled()) return false;
+
+        return beginDragging(v);
+    }
+
+    private boolean beginDragging(View v) {
+        if (v instanceof WidgetCell) {
+            if (!beginDraggingWidget((WidgetCell) v)) {
+                return false;
+            }
+        } else {
+            Log.e(TAG, "Unexpected dragging view: " + v);
+        }
+
+        // We delay entering spring-loaded mode slightly to make sure the UI
+        // thready is free of any work.
+        postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                // We don't enter spring-loaded mode if the drag has been cancelled
+                if (mLauncher.getDragController().isDragging()) {
+                    // Go into spring loaded mode (must happen before we startDrag())
+                    mLauncher.enterSpringLoadedDragMode();
+                }
+            }
+        }, 150);
+
+        return true;
+    }
+
+    private boolean beginDraggingWidget(WidgetCell v) {
+        mDraggingWidget = true;
+        // Get the widget preview as the drag representation
+        ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
+        PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
+
+        // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
+        // we abort the drag.
+        if (image.getDrawable() == null) {
+            mDraggingWidget = false;
+            return false;
+        }
+
+        // Compose the drag image
+        Bitmap preview;
+        Bitmap outline;
+        float scale = 1f;
+        Point previewPadding = null;
+
+        if (createItemInfo instanceof PendingAddWidgetInfo) {
+            // This can happen in some weird cases involving multi-touch. We can't start dragging
+            // the widget if this is null, so we break out.
+
+            PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) createItemInfo;
+            int[] size = mLauncher.getWorkspace().estimateItemSize(createWidgetInfo, true);
+
+            FastBitmapDrawable previewDrawable = (FastBitmapDrawable) image.getDrawable();
+            float minScale = 1.25f;
+            int maxWidth = Math.min((int) (previewDrawable.getIntrinsicWidth() * minScale), size[0]);
+
+            int[] previewSizeBeforeScale = new int[1];
+            preview = getWidgetPreviewLoader().generateWidgetPreview(createWidgetInfo.info,
+                    maxWidth, null, previewSizeBeforeScale);
+            // Compare the size of the drag preview to the preview in the AppsCustomize tray
+            int previewWidthInAppsCustomize = Math.min(previewSizeBeforeScale[0],
+                    v.getActualItemWidth());
+            scale = previewWidthInAppsCustomize / (float) preview.getWidth();
+
+            // The bitmap in the AppsCustomize tray is always the the same size, so there
+            // might be extra pixels around the preview itself - this accounts for that
+            if (previewWidthInAppsCustomize < previewDrawable.getIntrinsicWidth()) {
+                int padding =
+                        (previewDrawable.getIntrinsicWidth() - previewWidthInAppsCustomize) / 2;
+                previewPadding = new Point(padding, 0);
+            }
+        } else {
+            PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) v.getTag();
+            Drawable icon = mIconCache.getFullResIcon(createShortcutInfo.activityInfo);
+            preview = Utilities.createIconBitmap(icon, mLauncher);
+            createItemInfo.spanX = createItemInfo.spanY = 1;
+        }
+
+        // Don't clip alpha values for the drag outline if we're using the default widget preview
+        boolean clipAlpha = !(createItemInfo instanceof PendingAddWidgetInfo &&
+                (((PendingAddWidgetInfo) createItemInfo).previewImage == 0));
+
+        // Save the preview for the outline generation, then dim the preview
+        outline = Bitmap.createScaledBitmap(preview, preview.getWidth(), preview.getHeight(),
+                false);
+
+        // Start the drag
+        mLauncher.lockScreenOrientation();
+        mLauncher.getWorkspace().onDragStartedWithItem(createItemInfo, outline, clipAlpha);
+        mDragController.startDrag(image, preview, this, createItemInfo,
+                DragController.DRAG_ACTION_COPY, previewPadding, scale);
+        outline.recycle();
+        preview.recycle();
+        return true;
+    }
+
+    /*
+     * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
+     */
+    @Override
+    public boolean onTouch(View v, MotionEvent ev) {
+        Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
+        if (ev.getAction() == MotionEvent.ACTION_DOWN ||
+                ev.getAction() == MotionEvent.ACTION_MOVE) {
+            mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
+        }
+        return false;
+    }
+
+    //
+    // Drag related handling methods that implement {@link DragSource} interface.
+    //
+
+    @Override
+    public boolean supportsFlingToDelete() {
+        return false;
+    }
+
+    @Override
+    public boolean supportsAppInfoDropTarget() {
+        return true;
+    }
+
+    /*
+     * Both this method and {@link #supportsFlingToDelete} has to return {@code false} for the
+     * {@link DeleteDropTarget} to be invisible.)
+     */
+    @Override
+    public boolean supportsDeleteDropTarget() {
+        return false;
+    }
+
+    @Override
+    public float getIntrinsicIconScaleFactor() {
+        return 0;
+    }
+
+    @Override
+    public void onFlingToDeleteCompleted() {
+        // We just dismiss the drag when we fling, so cleanup here
+        mLauncher.exitSpringLoadedDragModeDelayed(true,
+                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        mLauncher.unlockScreenOrientation(false);
+    }
+
+    @Override
+    public void onDropCompleted(View target, DragObject d, boolean isFlingToDelete,
+            boolean success) {
+        if (isFlingToDelete || !success || (target != mLauncher.getWorkspace() &&
+                !(target instanceof DeleteDropTarget) && !(target instanceof Folder))) {
+            // Exit spring loaded mode if we have not successfully dropped or have not handled the
+            // drop in Workspace
+            mLauncher.exitSpringLoadedDragModeDelayed(true,
+                    Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);
+        }
+        mLauncher.unlockScreenOrientation(false);
+
+        // Display an error message if the drag failed due to there not being enough space on the
+        // target layout we were dropping on.
+        if (!success) {
+            boolean showOutOfSpaceMessage = false;
+            if (target instanceof Workspace) {
+                int currentScreen = mLauncher.getCurrentWorkspaceScreen();
+                Workspace workspace = (Workspace) target;
+                CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen);
+                ItemInfo itemInfo = (ItemInfo) d.dragInfo;
+                if (layout != null) {
+                    layout.calculateSpans(itemInfo);
+                    showOutOfSpaceMessage =
+                            !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY);
+                }
+            }
+            if (showOutOfSpaceMessage) {
+                mLauncher.showOutOfSpaceMessage(false);
+            }
+            d.deferDragViewCleanupPostAnimation = false;
+        }
+    }
+
+    //
+    // Container rendering related.
+    //
+
+    /*
+     * @see Insettable#setInsets(Rect)
+     */
+    @Override
+    public void setInsets(Rect insets) {
+        setPadding(mPadding.left + insets.left, mPadding.top + insets.top,
+                mPadding.right + insets.right, mPadding.bottom + insets.bottom);
+    }
+
+    /**
+     * Initialize the widget data model.
+     */
+    public void addWidgets(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
+        mWidgets.addWidgetsAndShortcuts(widgetsShortcuts, pm);
+    }
+
+    private WidgetPreviewLoader getWidgetPreviewLoader() {
+        if (mWidgetPreviewLoader == null) {
+            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+        }
+        return mWidgetPreviewLoader;
+    }
+
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
new file mode 100644
index 0000000..8d1f20c
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.WidgetPreviewLoader;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.List;
+
+/**
+ * List view adapter for the widget tray.
+ *
+ * <p>Memory vs. Performance:
+ * The less number of types of views are inserted into a {@link RecyclerView}, the more recycling
+ * happens and less memory is consumed. {@link #getItemViewType} was not overridden as there is
+ * only a single type of view.
+ */
+public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
+
+    private static final String TAG = "WidgetsListAdapter";
+    private static final boolean DEBUG = false;
+
+    private Context mContext;
+    private Launcher mLauncher;
+    private LayoutInflater mLayoutInflater;
+    private IconCache mIconCache;
+
+    private WidgetsModel mWidgetsModel;
+    private WidgetPreviewLoader mWidgetPreviewLoader;
+
+    private View.OnTouchListener mTouchListener;
+    private View.OnClickListener mIconClickListener;
+    private View.OnLongClickListener mIconLongClickListener;
+
+
+    public WidgetsListAdapter(Context context,
+            View.OnTouchListener touchListener,
+            View.OnClickListener iconClickListener,
+            View.OnLongClickListener iconLongClickListener,
+            Launcher launcher) {
+        mLayoutInflater = LayoutInflater.from(context);
+        mContext = context;
+
+        mTouchListener = touchListener;
+        mIconClickListener = iconClickListener;
+        mIconLongClickListener = iconLongClickListener;
+
+        mLauncher = launcher;
+        mIconCache = LauncherAppState.getInstance().getIconCache();
+    }
+
+    public void setWidgetsModel(WidgetsModel w) {
+        mWidgetsModel = w;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mWidgetsModel.getPackageSize();
+    }
+
+    @Override
+    public void onBindViewHolder(WidgetsRowViewHolder holder, int pos) {
+        String packageName = mWidgetsModel.getPackageName(pos);
+        List<Object> infoList = mWidgetsModel.getSortedWidgets(packageName);
+
+        ViewGroup row = ((ViewGroup) holder.getContent().findViewById(R.id.widgets_cell_list));
+        if (DEBUG) {
+            Log.d(TAG, String.format(
+                    "onBindViewHolder [pos=%d, packageName=%s, widget#=%d, row.getChildCount=%d]",
+                    pos, packageName, infoList.size(), row.getChildCount()));
+        }
+
+        // Add more views.
+        // if there are too many, hide them.
+        int diff = infoList.size() - row.getChildCount();
+        if (diff > 0) {
+            for (int i = 0; i < diff; i++) {
+                WidgetCell widget = new WidgetCell(mContext);
+                widget = (WidgetCell) mLayoutInflater.inflate(
+                        R.layout.widget_cell, row, false);
+
+                // set up touch.
+                widget.setOnClickListener(mIconClickListener);
+                widget.setOnLongClickListener(mIconLongClickListener);
+                widget.setOnTouchListener(mTouchListener);
+                row.addView(widget);
+            }
+        } else if (diff < 0) {
+            for (int i=infoList.size() ; i < row.getChildCount(); i++) {
+                row.getChildAt(i).setVisibility(View.GONE);
+            }
+        }
+
+        // Bind the views in the application info section.
+        PackageItemInfo infoOut = mWidgetsModel.getPackageItemInfo(packageName);
+        if (infoOut.usingLowResIcon) {
+            mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
+                false /* useLowResIcon */, infoOut);
+            mWidgetsModel.setPackageItemInfo(packageName, infoOut);
+        }
+        ((TextView) holder.getContent().findViewById(R.id.section)).setText(infoOut.title);
+        ImageView iv = (ImageView) holder.getContent().findViewById(R.id.section_image);
+        iv.setImageBitmap(infoOut.iconBitmap);
+
+        // Bind the view in the widget horizontal tray region.
+        for (int i=0; i < infoList.size(); i++) {
+            WidgetCell widget = (WidgetCell) row.getChildAt(i);
+            if (getWidgetPreviewLoader() == null || widget == null) {
+                return;
+            }
+            if (infoList.get(i) instanceof LauncherAppWidgetProviderInfo) {
+                LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) infoList.get(i);
+                PendingAddWidgetInfo pawi = new PendingAddWidgetInfo(info, null);
+                widget.setTag(pawi);
+                widget.applyFromAppWidgetProviderInfo(info, -1, mWidgetPreviewLoader);
+            } else if (infoList.get(i) instanceof ResolveInfo) {
+                ResolveInfo info = (ResolveInfo) infoList.get(i);
+                PendingAddShortcutInfo pasi = new PendingAddShortcutInfo(info.activityInfo);
+                widget.setTag(pasi);
+                widget.applyFromResolveInfo(mLauncher.getPackageManager(), info, mWidgetPreviewLoader);
+            }
+            widget.setVisibility(View.VISIBLE);
+            widget.ensurePreview();
+        }
+        // TODO(hyunyoungs): Draw the scrollable indicator.
+    }
+
+    @Override
+    public WidgetsRowViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (DEBUG) {
+            Log.v(TAG, String.format("\nonCreateViewHolder, [widget#=%d]", viewType));
+        }
+
+        ViewGroup container = (ViewGroup) mLayoutInflater.inflate(
+                R.layout.widgets_list_row_view, parent, false);
+        return new WidgetsRowViewHolder(container);
+    }
+
+    @Override
+    public long getItemId(int pos) {
+        return pos;
+    }
+
+    private WidgetPreviewLoader getWidgetPreviewLoader() {
+        if (mWidgetPreviewLoader == null) {
+            mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+        }
+        return mWidgetPreviewLoader;
+    }
+
+    /**
+     * TODO(hyunyoungs): this is temporary. Figure out the width of each widget cell
+     * and then check if the total sum is longer than the parent width.
+     */
+    private void addScrollableIndicator(int contentSize, ViewGroup parent) {
+        if (contentSize > 2) {
+            ViewGroup indicator = (ViewGroup) parent.findViewById(R.id.scrollable_indicator);
+            indicator.setVisibility(View.VISIBLE);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsModel.java b/src/com/android/launcher3/widget/WidgetsModel.java
new file mode 100644
index 0000000..463c79e
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsModel.java
@@ -0,0 +1,140 @@
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.LauncherModel.WidgetAndShortcutNameComparator;
+import com.android.launcher3.compat.UserHandleCompat;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Widgets data model that is used by the adapters of the widget views and controllers.
+ *
+ * <p> The widgets and shortcuts are organized using package name as its index.
+ */
+public class WidgetsModel {
+
+    private static final String TAG = "WidgetsModel";
+    private static final boolean DEBUG = false;
+
+    /* List of packages that is tracked by this model. */
+    private List<String> mPackageNames = new ArrayList<>();
+
+    private Map<String, PackageItemInfo> mPackageItemInfoList = new HashMap<>();
+
+    /* Map of widgets and shortcuts that are tracked per package. */
+    private Map<String, ArrayList<Object>> mWidgetsList = new HashMap<>();
+
+    /* Notifies the adapter when data changes. */
+    private RecyclerView.Adapter mAdapter;
+
+    private Comparator mWidgetAndShortcutNameComparator;
+
+    private IconCache mIconCache;
+
+    public WidgetsModel(Context context, RecyclerView.Adapter adapter) {
+        mAdapter = adapter;
+        mWidgetAndShortcutNameComparator = new WidgetAndShortcutNameComparator(context);
+        mIconCache = LauncherAppState.getInstance().getIconCache();
+    }
+
+    // Access methods that may be deleted if the private fields are made package-private.
+    public int getPackageSize() {
+        return mPackageNames.size();
+    }
+
+    // Access methods that may be deleted if the private fields are made package-private.
+    public String getPackageName(int pos) {
+        return mPackageNames.get(pos);
+    }
+
+    public PackageItemInfo getPackageItemInfo(String packageName) {
+        return mPackageItemInfoList.get(packageName);
+    }
+
+    public List<Object> getSortedWidgets(String packageName) {
+        return mWidgetsList.get(packageName);
+    }
+
+    public void addWidgetsAndShortcuts(ArrayList<Object> widgetsShortcuts, PackageManager pm) {
+        if (DEBUG) {
+            Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + widgetsShortcuts.size());
+        }
+
+        // clear the lists.
+        mPackageNames.clear();
+        mWidgetsList.clear();
+
+        // add and update.
+        for (Object o: widgetsShortcuts) {
+            String packageName = "";
+            if (o instanceof LauncherAppWidgetProviderInfo) {
+                LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o;
+                packageName = widgetInfo.provider.getPackageName();
+            } else if (o instanceof ResolveInfo) {
+                ResolveInfo resolveInfo = (ResolveInfo) o;
+                packageName = resolveInfo.activityInfo.packageName;
+            } else {
+                Log.e(TAG, String.format("addWidgetsAndShortcuts, nothing added for class=%s",
+                        o.getClass().toString()));
+                
+            }
+
+            ArrayList<Object> widgetsShortcutsList = mWidgetsList.get(packageName);
+            if (widgetsShortcutsList != null) {
+                widgetsShortcutsList.add(o);
+            } else {
+                widgetsShortcutsList = new ArrayList<Object>();
+                widgetsShortcutsList.add(o);
+                mWidgetsList.put(packageName, widgetsShortcutsList);
+                mPackageNames.add(packageName);
+            }
+        }
+        for (String packageName: mPackageNames) {
+            PackageItemInfo pInfo = mPackageItemInfoList.get(packageName);
+            if (pInfo == null) {
+                pInfo = new PackageItemInfo();
+                mIconCache.getTitleAndIconForApp(packageName, UserHandleCompat.myUserHandle(),
+                        true /* useLowResIcon */, pInfo);
+                mPackageItemInfoList.put(packageName, pInfo);
+            }
+        }
+
+        // sort.
+        sortPackageList();
+        for (String packageName: mPackageNames) {
+            Collections.sort(mWidgetsList.get(packageName), mWidgetAndShortcutNameComparator);
+        }
+
+        // notify.
+        mAdapter.notifyDataSetChanged();
+    }
+
+    private void sortPackageList() {
+        Collections.sort(mPackageNames, new Comparator<String>() {
+            @Override
+            public int compare(String lhs, String rhs) {
+                String lhsTitle = mPackageItemInfoList.get(lhs).title.toString();
+                String rhsTitle = mPackageItemInfoList.get(rhs).title.toString();
+                return lhsTitle.compareTo(rhsTitle);
+            }
+        });
+    }
+
+    public void setPackageItemInfo(String packageName, PackageItemInfo infoOut) {
+        mPackageItemInfoList.put(packageName, infoOut);
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRowView.java b/src/com/android/launcher3/widget/WidgetsRowView.java
new file mode 100644
index 0000000..5466738
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRowView.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import com.android.launcher3.R;
+
+/**
+ * Layout used for widget tray rows for each app. For performance, this view can be replaced with
+ * a {@link RecyclerView} in the future if we settle on scrollable single row for the widgets.
+ * If we decide on collapsable grid, then HorizontalScrollView can be replaced with a
+ * {@link GridLayout}.
+ */
+public class WidgetsRowView extends HorizontalScrollView {
+    static final String TAG = "WidgetsRow";
+
+    private Runnable mOnLayoutListener;
+    private String mAppName;
+
+    public WidgetsRowView(Context context, String appName) {
+        super(context, null, 0);
+        mAppName = appName;
+    }
+
+    /**
+     * Clears all the key listeners for the individual widgets.
+     */
+    public void resetChildrenOnKeyListeners() {
+        int childCount = getChildCount();
+        for (int j = 0; j < childCount; ++j) {
+            getChildAt(j).setOnKeyListener(null);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TextView tv = (TextView) findViewById(R.id.widget_name);
+        tv.setText(mAppName);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mOnLayoutListener = null;
+    }
+
+    public void setOnLayoutListener(Runnable r) {
+        mOnLayoutListener = r;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mOnLayoutListener != null) {
+            mOnLayoutListener.run();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        boolean result = super.onTouchEvent(event);
+        return result;
+    }
+
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsRowViewHolder.java b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
new file mode 100644
index 0000000..99a192c
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetsRowViewHolder.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+public class WidgetsRowViewHolder extends ViewHolder {
+
+    ViewGroup mContent;
+
+   public WidgetsRowViewHolder(ViewGroup v) {
+        super(v);
+        mContent = v;
+    }
+
+    ViewGroup getContent() {
+        return mContent;
+    }
+}