Merge "Adding drag target bar."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5206896..7cbc2eb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -102,9 +102,7 @@
 
         <activity android:name="com.android.launcher2.RocketLauncher"
             android:label="@string/dream_name"
-            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"
-            android:hardwareAccelerated="true"
-            >
+            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/res/layout/apps_customize_pane.xml b/res/layout/apps_customize_pane.xml
index e22ba12..7083bf8 100644
--- a/res/layout/apps_customize_pane.xml
+++ b/res/layout/apps_customize_pane.xml
@@ -94,9 +94,7 @@
                 launcher:widgetCellWidthGap="@dimen/apps_customize_widget_cell_width_gap"
                 launcher:widgetCellHeightGap="@dimen/apps_customize_widget_cell_height_gap"
                 launcher:widgetCountX="@integer/apps_customize_widget_cell_count_x"
-                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y"
-                launcher:wallpaperCountX="@integer/apps_customize_wallpaper_cell_count_x"
-                launcher:wallpaperCountY="@integer/apps_customize_wallpaper_cell_count_y" />
+                launcher:widgetCountY="@integer/apps_customize_widget_cell_count_y" />
          </FrameLayout>
       </LinearLayout>
 </com.android.launcher2.AppsCustomizeTabHost>
diff --git a/res/values-large/dimens.xml b/res/values-large/dimens.xml
index fa660e5..970a200 100644
--- a/res/values-large/dimens.xml
+++ b/res/values-large/dimens.xml
@@ -95,4 +95,10 @@
 
     <!-- Max number of rows in all apps, because too many looks weird. -->
     <integer name="all_apps_view_maxCellCountY">6</integer>
+
+    <!-- Padding applied to AppWidgets -->
+    <dimen name="app_widget_padding_left">12dp</dimen>
+    <dimen name="app_widget_padding_right">12dp</dimen>
+    <dimen name="app_widget_padding_top">4dp</dimen>
+    <dimen name="app_widget_padding_bottom">20dp</dimen>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 75b93bf..ae1b7f7 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -120,10 +120,6 @@
         <attr name="widgetCountX" format="integer" />
         <!-- Number of widgets vertically -->
         <attr name="widgetCountY" format="integer" />
-        <!-- Number of wallpaper pickers horizontally -->
-        <attr name="wallpaperCountX" format="integer" />
-        <!-- Number of wallpaper pickers vertically -->
-        <attr name="wallpaperCountY" format="integer" />
     </declare-styleable>
 
     <!-- CustomizePagedView specific attributes. These attributes are used to customize
diff --git a/res/values/config.xml b/res/values/config.xml
index de05a4b..44ba589 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,7 +1,4 @@
 <resources>
-<!-- System -->
-    <bool name="config_hardwareAccelerated">false</bool>
-
 <!-- AllApps/Customize/AppsCustomize -->
     <!-- Fade in/out duration of icons being dragged from the trays -->
     <integer name="config_dragAppsCustomizeIconFadeInDuration">150</integer>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d159f9..f51f8b1 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -78,4 +78,10 @@
     <!-- Width/height gap overrides for the workspace -->
     <dimen name="workspace_width_gap">-1dp</dimen>
     <dimen name="workspace_height_gap">-1dp</dimen>
+
+    <!-- Padding applied to AppWidgets -->
+    <dimen name="app_widget_padding_left">0dp</dimen>
+    <dimen name="app_widget_padding_right">0dp</dimen>
+    <dimen name="app_widget_padding_top">0dp</dimen>
+    <dimen name="app_widget_padding_bottom">0dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e59fd6e..5ecfdd6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -21,16 +21,16 @@
     <!-- Manifest configuration. -->
     <skip />
     <!-- Do not translate. android:sharedUserId of this application. -->
-    <string name="sharedUserId" translate="false"><xliff:g id="x"></xliff:g></string>
+    <string name="sharedUserId" translatable="false"><xliff:g id="x"></xliff:g></string>
     <!-- Do not translate. android:process of this application. -->
-    <string name="process" translate="false"><xliff:g id="x"></xliff:g></string>
+    <string name="process" translatable="false"><xliff:g id="x"></xliff:g></string>
     
     <!-- Do not translate. We wish to prioritize the Wallpaper and Live Wallpaper pickers,
          but because they are in a different package, we need to reference the component in
          a non language-dependent way.  If the Live Wallpaper picker component name changes
          this will have to be updated as well. -->
-    <string name="live_wallpaper_picker_package_name" translate="false">com.android.wallpaper.livepicker</string>
-    <string name="live_wallpaper_picker_class_name" translate="false">com.android.wallpaper.livepicker.LiveWallpaperActivity</string>
+    <string name="live_wallpaper_picker_package_name" translatable="false">com.android.wallpaper.livepicker</string>
+    <string name="live_wallpaper_picker_class_name" translatable="false">com.android.wallpaper.livepicker.LiveWallpaperActivity</string>
 
     <!-- General -->
     <skip />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 36a4be0..f2c07f7 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -115,8 +115,8 @@
     </style>
 
     <style name="MarketButton">
-        <item name="android:paddingRight">20dp</item>
-        <item name="android:text">@string/market</item>
+        <item name="android:paddingLeft">5dp</item>
+        <item name="android:paddingRight">5dp</item>
         <item name="android:textColor">@color/workspace_all_apps_and_delete_zone_text_color</item>
         <item name="android:textSize">18sp</item>
         <item name="android:shadowColor">@color/workspace_all_apps_and_delete_zone_text_shadow_color</item>
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 64e6f98..94e6af4 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -72,6 +72,7 @@
 
     private int mLastMeasureWidth = -1;
     private int mLastMeasureHeight = -1;
+    private boolean mWaitingToInitPages = true;
 
     private int mMaxCellCountY;
 
@@ -119,13 +120,16 @@
             mCellCountY = determineCellCountY(height, layout);
             mLastMeasureWidth = width;
             mLastMeasureHeight = height;
+            removeAllViews();
+            invalidatePageData();
         }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mFirstLayout) {
+        if (mWaitingToInitPages) {
+            mWaitingToInitPages = false;
             invalidatePageData();
 
             // invalidatePageData() is what causes the child pages to be created. We need the
@@ -567,12 +571,17 @@
     }
 
     @Override
-    public void syncPages() {
-        if (mCellCountX <= 0 || mCellCountY <= 0) {
+    protected void invalidatePageData() {
+        if (mWaitingToInitPages || mCellCountX <= 0 || mCellCountY <= 0) {
             // We don't know our size yet, which means we haven't calculated cell count x/y;
             // onMeasure will call us once we figure out our size
             return;
         }
+        super.invalidatePageData();
+    }
+
+    @Override
+    public void syncPages() {
         // ensure that we have the right number of pages (min of 1, since we have placeholders)
         int numPages = Math.max(1,
                 (int) Math.ceil((float) mFilteredApps.size() / (mCellCountX * mCellCountY)));
diff --git a/src/com/android/launcher2/AppsCustomizePagedView.java b/src/com/android/launcher2/AppsCustomizePagedView.java
index bd70463..401e8ad 100644
--- a/src/com/android/launcher2/AppsCustomizePagedView.java
+++ b/src/com/android/launcher2/AppsCustomizePagedView.java
@@ -28,8 +28,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.app.WallpaperManager;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -73,8 +71,7 @@
      */
     public enum ContentType {
         Applications,
-        Widgets,
-        Wallpapers
+        Widgets
     }
 
     // Refs
@@ -87,7 +84,6 @@
     private ContentType mContentType;
     private ArrayList<ApplicationInfo> mApps;
     private List<Object> mWidgets;
-    private List<ResolveInfo> mWallpapers;
 
     // Caching
     private Drawable mDefaultWidgetBackground;
@@ -100,7 +96,6 @@
     private int mMaxWidgetSpan, mMinWidgetSpan;
     private int mCellWidthGap, mCellHeightGap;
     private int mWidgetCountX, mWidgetCountY;
-    private int mWallpaperCountX, mWallpaperCountY;
     private final int mWidgetPreviewIconPaddedDimension;
     private final float sWidgetPreviewIconPaddingPercentage = 0.25f;
     private PagedViewCellLayout mWidgetSpacingLayout;
@@ -117,7 +112,6 @@
         mContentType = ContentType.Applications;
         mApps = new ArrayList<ApplicationInfo>();
         mWidgets = new ArrayList<Object>();
-        mWallpapers = new ArrayList<ResolveInfo>();
         mIconCache = ((LauncherApplication) context.getApplicationContext()).getIconCache();
         mWidgetPreviewCache = new LruCache<Object, Bitmap>(sWidgetPreviewCacheSize) {
             protected int sizeOf(Object key, Bitmap value) {
@@ -140,8 +134,6 @@
             a.getDimensionPixelSize(R.styleable.AppsCustomizePagedView_widgetCellHeightGap, 10);
         mWidgetCountX = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountX, 2);
         mWidgetCountY = a.getInt(R.styleable.AppsCustomizePagedView_widgetCountY, 2);
-        mWallpaperCountX = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountX, 2);
-        mWallpaperCountY = a.getInt(R.styleable.AppsCustomizePagedView_wallpaperCountY, 2);
         a.recycle();
 
         // Create a dummy page that we can use to approximate the cell dimensions of widgets and
@@ -196,27 +188,6 @@
         mWidgets.addAll(mPackageManager.queryIntentActivities(shortcutsIntent, 0));
         Collections.sort(mWidgets,
                 new LauncherModel.WidgetAndShortcutNameComparator(mPackageManager));
-
-        // Get the list of wallpapers
-        Intent wallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
-        mWallpapers = mPackageManager.queryIntentActivities(wallpapersIntent,
-                PackageManager.GET_META_DATA);
-        Collections.sort(mWallpapers,
-                new LauncherModel.ShortcutNameComparator(mPackageManager));
-        // Move Live Wallpapers to the front of the list
-        Context c = getContext();
-        ResolveInfo liveWallpapers = removeResolveInfoWithComponentName(mWallpapers,
-            new ComponentName(c.getString(R.string.live_wallpaper_picker_package_name),
-                c.getString(R.string.live_wallpaper_picker_class_name)));
-        if (liveWallpapers != null) {
-            mWallpapers.add(0, liveWallpapers);
-        }
-        // Move Wallpapers to the front of the list
-        ResolveInfo wallpapers = removeResolveInfoWithComponentName(mWallpapers,
-            new ComponentName(c.getPackageName(), WallpaperChooser.class.getName()));
-        if (wallpapers != null) {
-            mWallpapers.add(0, wallpapers);
-        }
     }
 
     /**
@@ -328,39 +299,31 @@
                 }
             });
         } else if (v instanceof PagedViewWidget) {
-            if (v.getTag() instanceof ResolveInfo) {
-                final ResolveInfo info = (ResolveInfo) v.getTag();
-                if (mWallpapers.contains(info)) {
-                    // Start the wallpaper picker
-                    animateClickFeedback(v, new Runnable() {
-                        @Override
-                        public void run() {
-                            // add the shortcut
-                            Intent createWallpapersIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
-                            ComponentName name = new ComponentName(info.activityInfo.packageName,
-                                    info.activityInfo.name);
-                            createWallpapersIntent.setComponent(name);
-                            mLauncher.processWallpaper(createWallpapersIntent);
+            // Add the widget to the current workspace screen
+            Workspace w = mLauncher.getWorkspace();
+            int currentWorkspaceScreen = mLauncher.getCurrentWorkspaceScreen();
+            final CellLayout cl = (CellLayout) w.getChildAt(currentWorkspaceScreen);
+            final View dragView = v.findViewById(R.id.widget_preview);
+            final ItemInfo itemInfo = (ItemInfo) v.getTag();
+            animateClickFeedback(v, new Runnable() {
+                @Override
+                public void run() {
+                    cl.calculateSpans(itemInfo);
+                    if (cl.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY)) {
+                        if (LauncherApplication.isScreenLarge()) {
+                            animateItemOntoScreen(dragView, cl, itemInfo);
+                        } else {
+                            mLauncher.addExternalItemToScreen(itemInfo, cl);
+                            itemInfo.dropPos = null;
                         }
-                    });
-                }
-            } else {
-                // Let the user know that they have to long press to add a widget
-                Toast.makeText(getContext(), R.string.long_press_widget_to_add,
-                        Toast.LENGTH_SHORT).show();
 
-                // Create a little animation to show that the widget can move
-                float offsetY = getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);
-                final ImageView p = (ImageView) v.findViewById(R.id.widget_preview);
-                AnimatorSet bounce = new AnimatorSet();
-                ValueAnimator tyuAnim = ObjectAnimator.ofFloat(p, "translationY", offsetY);
-                tyuAnim.setDuration(125);
-                ValueAnimator tydAnim = ObjectAnimator.ofFloat(p, "translationY", 0f);
-                tydAnim.setDuration(100);
-                bounce.play(tyuAnim).before(tydAnim);
-                bounce.setInterpolator(new AccelerateInterpolator());
-                bounce.start();
-            }
+                        // Hide the pane so we can see the workspace we dropped on
+                        mLauncher.showWorkspace(true);
+                    } else {
+                        mLauncher.showOutOfSpaceMessage();
+                    }
+                }
+            });
         }
     }
 
@@ -797,160 +760,6 @@
         }
     }
 
-    /*
-     * This method fetches an xml file specified in the manifest identified by
-     * WallpaperManager.WALLPAPER_PREVIEW_META_DATA). The xml file specifies
-     * an image which will be used as the wallpaper preview for an activity
-     * which responds to ACTION_SET_WALLPAPER. This image is returned and used
-     * in the customize drawer.
-     */
-    private Drawable parseWallpaperPreviewXml(ResolveInfo ri) {
-        ActivityInfo activityInfo = ri.activityInfo;
-        XmlResourceParser parser = null;
-        ComponentName component = new ComponentName(ri.activityInfo.packageName,
-                ri.activityInfo.name);
-        try {
-            parser = activityInfo.loadXmlMetaData(mPackageManager,
-                    WallpaperManager.WALLPAPER_PREVIEW_META_DATA);
-            if (parser == null) {
-                Slog.w(LOG_TAG, "No " + WallpaperManager.WALLPAPER_PREVIEW_META_DATA
-                        + " meta-data for " + "wallpaper provider '" + component + '\'');
-                return null;
-            }
-
-            AttributeSet attrs = Xml.asAttributeSet(parser);
-
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
-                    && type != XmlPullParser.START_TAG) {
-                // drain whitespace, comments, etc.
-            }
-
-            String nodeName = parser.getName();
-            if (!"wallpaper-preview".equals(nodeName)) {
-                Slog.w(LOG_TAG, "Meta-data does not start with wallpaper-preview tag for "
-                        + "wallpaper provider '" + component + '\'');
-                return null;
-            }
-
-            // If metaData was null, we would have returned earlier when getting
-            // the parser No need to do the check here
-            Resources res = mPackageManager.getResourcesForApplication(
-                    activityInfo.applicationInfo);
-
-            TypedArray sa = res.obtainAttributes(attrs,
-                    com.android.internal.R.styleable.WallpaperPreviewInfo);
-
-            TypedValue value = sa.peekValue(
-                    com.android.internal.R.styleable.WallpaperPreviewInfo_staticWallpaperPreview);
-            if (value == null) return null;
-
-            return res.getDrawable(value.resourceId);
-        } catch (Exception e) {
-            Slog.w(LOG_TAG, "XML parsing failed for wallpaper provider '" + component + '\'', e);
-            return null;
-        } finally {
-            if (parser != null) parser.close();
-        }
-    }
-    private FastBitmapDrawable getWallpaperPreview(ResolveInfo info, int cellWidth, int cellHeight){
-        // Return the cached version if necessary
-        Bitmap cachedBitmap = mWidgetPreviewCache.get(info);
-        if (cachedBitmap != null) {
-            return new FastBitmapDrawable(cachedBitmap);
-        }
-
-        // Get the preview
-        Resources resources = getContext().getResources();
-        Drawable wallpaperPreview = parseWallpaperPreviewXml(info);
-        Drawable wallpaperIcon = null;
-        int expectedWidth;
-        int expectedHeight;
-        if (wallpaperPreview != null) {
-            expectedWidth = wallpaperPreview.getIntrinsicWidth();
-            expectedHeight = wallpaperPreview.getIntrinsicHeight();
-        } else {
-            wallpaperPreview = mDefaultWidgetBackground;
-            expectedWidth = expectedHeight = Math.min(cellWidth, cellHeight);
-
-            // Draw the icon in the top left corner
-            String packageName = info.activityInfo.packageName;
-            try {
-                if (info.icon > 0) {
-                    wallpaperIcon = mPackageManager.getDrawable(packageName, info.icon, null);
-                }
-                if (wallpaperIcon == null) {
-                    wallpaperIcon = resources.getDrawable(R.drawable.ic_launcher_application);
-                }
-            } catch (Resources.NotFoundException e) {}
-        }
-
-        // Create the bitmap
-        Bitmap preview = Bitmap.createBitmap(expectedWidth, expectedHeight, Config.ARGB_8888);
-        renderDrawableToBitmap(wallpaperPreview, preview, 0, 0, expectedWidth, expectedHeight,
-                1f, 1f);
-        if (wallpaperIcon != null) {
-            int iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size);
-            int offset = (int) (iconSize * sWidgetPreviewIconPaddingPercentage);
-            renderDrawableToBitmap(wallpaperIcon, preview, offset, offset, iconSize, iconSize,
-                    1f, 1f);
-        }
-
-        FastBitmapDrawable previewDrawable = new FastBitmapDrawable(preview);
-        previewDrawable.setBounds(0, 0, expectedWidth, expectedHeight);
-        mWidgetPreviewCache.put(info, preview);
-        return previewDrawable;
-    }
-    /*
-     * Wallpapers PagedView implementation
-     */
-    public void syncWallpaperPages() {
-        // Ensure that we have the right number of pages
-        Context context = getContext();
-        int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
-        int numPages = (int) Math.ceil(mWallpapers.size() / (float) numWidgetsPerPage);
-        for (int i = 0; i < numPages; ++i) {
-            PagedViewGridLayout layout = new PagedViewGridLayout(context, mWallpaperCountX,
-                    mWallpaperCountY);
-            setupPage(layout);
-            addView(layout);
-        }
-    }
-    public void syncWallpaperPageItems(int page) {
-        PagedViewGridLayout layout = (PagedViewGridLayout) getChildAt(page);
-        layout.removeAllViews();
-
-        // Calculate the dimensions of each cell we are giving to each widget
-        int numWidgetsPerPage = mWallpaperCountX * mWallpaperCountY;
-        int offset = page * numWidgetsPerPage;
-        int cellWidth = ((mWidgetSpacingLayout.getContentWidth() - mPageLayoutWidthGap
-                - ((mWallpaperCountX - 1) * mCellWidthGap)) / mWallpaperCountX);
-        int cellHeight = ((mWidgetSpacingLayout.getContentHeight() - mPageLayoutHeightGap
-                - ((mWallpaperCountY - 1) * mCellHeightGap)) / mWallpaperCountY);
-        for (int i = 0; i < Math.min(numWidgetsPerPage, mWallpapers.size() - offset); ++i) {
-            ResolveInfo info = mWallpapers.get(offset + i);
-            PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
-                    R.layout.apps_customize_wallpaper, layout, false);
-
-            // Fill in the shortcuts information
-            FastBitmapDrawable preview = getWallpaperPreview(info, cellWidth, cellHeight);
-            widget.applyFromResolveInfo(mPackageManager, info, preview, null, false);
-            widget.setTag(info);
-            widget.setOnClickListener(this);
-            widget.setOnLongClickListener(this);
-            widget.setOnTouchListener(this);
-
-            // Layout each widget
-            int ix = i % mWallpaperCountX;
-            int iy = i / mWallpaperCountX;
-            PagedViewGridLayout.LayoutParams lp = new PagedViewGridLayout.LayoutParams(cellWidth,
-                    cellHeight);
-            lp.leftMargin = (ix * cellWidth) + (ix * mCellWidthGap);
-            lp.topMargin = (iy * cellHeight) + (iy * mCellHeightGap);
-            layout.addView(widget, lp);
-        }
-    }
-
     @Override
     public void syncPages() {
         removeAllViews();
@@ -961,9 +770,6 @@
         case Widgets:
             syncWidgetPages();
             break;
-        case Wallpapers:
-            syncWallpaperPages();
-            break;
         }
     }
     @Override
@@ -975,9 +781,6 @@
         case Widgets:
             syncWidgetPageItems(page);
             break;
-        case Wallpapers:
-            syncWallpaperPageItems(page);
-            break;
         }
     }
 
diff --git a/src/com/android/launcher2/AppsCustomizeTabHost.java b/src/com/android/launcher2/AppsCustomizeTabHost.java
index cd8e7ef..e40524d 100644
--- a/src/com/android/launcher2/AppsCustomizeTabHost.java
+++ b/src/com/android/launcher2/AppsCustomizeTabHost.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TabHost;
@@ -33,9 +34,9 @@
 
     private static final String APPS_TAB_TAG = "APPS";
     private static final String WIDGETS_TAB_TAG = "WIDGETS";
-    private static final String WALLPAPERS_TAB_TAG = "WALLPAPERS";
 
     private final LayoutInflater mLayoutInflater;
+    private AppsCustomizePagedView mAppsCustomizePane;
 
     public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -58,15 +59,16 @@
         setup();
 
         final ViewGroup tabs = (ViewGroup) findViewById(com.android.internal.R.id.tabs);
-        final AppsCustomizePagedView content = (AppsCustomizePagedView)
+        final AppsCustomizePagedView appsCustomizePane = (AppsCustomizePagedView)
                 findViewById(R.id.apps_customize_pane_content);
-        if (tabs == null || content == null) throw new Resources.NotFoundException();
+        mAppsCustomizePane = appsCustomizePane;
+        if (tabs == null || mAppsCustomizePane == null) throw new Resources.NotFoundException();
 
         // Configure the tabs content factory to return the same paged view (that we change the
         // content filter on)
         TabContentFactory contentFactory = new TabContentFactory() {
             public View createTabContent(String tag) {
-                return content;
+                return appsCustomizePane;
             }
         };
 
@@ -78,20 +80,25 @@
         tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
         tabView.setText(mContext.getString(R.string.widgets_tab_label));
         addTab(newTabSpec(WIDGETS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
-        tabView = (TextView) mLayoutInflater.inflate(R.layout.tab_widget_indicator, tabs, false);
-        tabView.setText(mContext.getString(R.string.wallpapers_tab_label));
-        addTab(newTabSpec(WALLPAPERS_TAB_TAG).setIndicator(tabView).setContent(contentFactory));
         setOnTabChangedListener(this);
 
         // Set the width of the tab bar to match the content (for now)
-        tabs.getLayoutParams().width = content.getPageContentWidth();
+        tabs.getLayoutParams().width = mAppsCustomizePane.getPageContentWidth();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // Intercept all touch events up to the bottom of the AppsCustomizePane so they do not fall
+        // through to the workspace and trigger showWorkspace()
+        if (event.getY() < mAppsCustomizePane.getBottom()) {
+            return true;
+        }
+        return super.onTouchEvent(event);
     }
 
     @Override
     public void onTabChanged(String tabId) {
-        final AppsCustomizePagedView content = (AppsCustomizePagedView)
-                findViewById(R.id.apps_customize_pane_content);
-        content.setContentType(getContentTypeForTabTag(tabId));
+        mAppsCustomizePane.setContentType(getContentTypeForTabTag(tabId));
     }
 
     /**
@@ -102,8 +109,6 @@
             return AppsCustomizePagedView.ContentType.Applications;
         } else if (tag.equals(WIDGETS_TAB_TAG)) {
             return AppsCustomizePagedView.ContentType.Widgets;
-        } else if (tag.equals(WALLPAPERS_TAB_TAG)) {
-            return AppsCustomizePagedView.ContentType.Wallpapers;
         }
         return AppsCustomizePagedView.ContentType.Applications;
     }
@@ -116,8 +121,6 @@
             return APPS_TAB_TAG;
         } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
             return WIDGETS_TAB_TAG;
-        } else if (type == AppsCustomizePagedView.ContentType.Wallpapers) {
-            return WALLPAPERS_TAB_TAG;
         }
         return APPS_TAB_TAG;
     }
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 5ac261f..e1256d0 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -151,6 +151,8 @@
 
     private AllAppsPagedView mAllAppsPagedView;
 
+    private boolean mWaitingToInitPages = true;
+
     public CustomizePagedView(Context context) {
         this(context, null, 0);
     }
@@ -208,6 +210,8 @@
             mPageContentWidth = layout.getContentWidth();
             mPageContentHeight = layout.getContentHeight();
             mMinPageWidth = layout.getWidthBeforeFirstLayout();
+            removeAllViews();
+            invalidatePageData();
         }
         if (mPageContentHeight > 0) {
             // Lock our height to the size of the page content
@@ -220,7 +224,8 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        if (mFirstLayout) {
+        if (mWaitingToInitPages) {
+            mWaitingToInitPages = false;
             invalidatePageData();
 
             // invalidatePageData() is what causes the child pages to be created. We need the
@@ -1138,12 +1143,17 @@
     }
 
     @Override
-    public void syncPages() {
-        if (mFirstMeasure) {
+    protected void invalidatePageData() {
+        if (mWaitingToInitPages || mCellCountX <= 0 || mCellCountY <= 0) {
             // We don't know our size yet, which means we haven't calculated cell count x/y;
             // onMeasure will call us once we figure out our size
             return;
         }
+        super.invalidatePageData();
+    }
+
+    @Override
+    public void syncPages() {
         boolean enforceMinimumPagedWidths = false;
         boolean centerPagedViewCellLayouts = false;
         switch (mCustomizationType) {
diff --git a/src/com/android/launcher2/FolderIcon.java b/src/com/android/launcher2/FolderIcon.java
index e97676d..952d704 100644
--- a/src/com/android/launcher2/FolderIcon.java
+++ b/src/com/android/launcher2/FolderIcon.java
@@ -78,10 +78,7 @@
     private int mOriginalWidth = -1;
     private int mOriginalHeight = -1;
 
-    private int mFolderLocX;
-    private int mFolderLocY;
-    private float mOuterRingScale;
-    private float mInnerRingScale;
+    FolderRingAnimator mFolderRingAnimator = null;
 
     public FolderIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -117,18 +114,107 @@
         folder.setFolderIcon(icon);
         folder.bind(folderInfo);
         icon.mFolder = folder;
-
+        icon.mFolderRingAnimator = new FolderRingAnimator(launcher, icon);
         folderInfo.addListener(icon);
-        if (sFolderOuterRingDrawable == null) {
-            sFolderOuterRingDrawable =
-                    launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
+
+        return icon;
+    }
+
+    public static class FolderRingAnimator {
+        public int mFolderLocX;
+        public int mFolderLocY;
+        public float mOuterRingScale;
+        public float mInnerRingScale;
+        public FolderIcon mFolderIcon = null;
+        private Launcher mLauncher;
+
+        public FolderRingAnimator(Launcher launcher, FolderIcon folderIcon) {
+            mLauncher = launcher;
+            mFolderIcon = folderIcon;
+            if (sFolderOuterRingDrawable == null) {
+                sFolderOuterRingDrawable =
+                        launcher.getResources().getDrawable(R.drawable.portal_ring_outer_holo);
+            }
+            if (sFolderInnerRingDrawable == null) {
+                sFolderInnerRingDrawable =
+                        launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
+            }
         }
 
-        if (sFolderInnerRingDrawable == null) {
-            sFolderInnerRingDrawable =
-                    launcher.getResources().getDrawable(R.drawable.portal_ring_inner_holo);
+        public void setLocation(int x, int y) {
+            mFolderLocX = x;
+            mFolderLocY = y;
         }
-        return icon;
+
+        public void animateToAcceptState() {
+            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+            va.setDuration(CONSUMPTION_ANIMATION_DURATION);
+            va.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final float percent = (Float) animation.getAnimatedValue();
+                    mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
+                    mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
+                    mLauncher.getWorkspace().invalidate();
+                    if (mFolderIcon != null) {
+                        mFolderIcon.invalidate();
+                    }
+                }
+            });
+            va.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // Instead of setting the background drawable to null, we set the color to
+                    // transparent. Setting the background drawable to null results in onDraw
+                    // not getting called.
+                    if (mFolderIcon != null) {
+                        mFolderIcon.setBackgroundColor(Color.TRANSPARENT);
+                        mFolderIcon.requestLayout();
+                    }
+                }
+            });
+            va.start();
+        }
+
+        public void animateToNaturalState() {
+            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
+            va.setDuration(CONSUMPTION_ANIMATION_DURATION);
+            va.addUpdateListener(new AnimatorUpdateListener() {
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final float percent = (Float) animation.getAnimatedValue();
+                    mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
+                            - percent * OUTER_RING_GROWTH_FACTOR;
+                    mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
+                            - percent * INNER_RING_GROWTH_FACTOR;
+                    mLauncher.getWorkspace().invalidate();
+                    if (mFolderIcon != null) {
+                        mFolderIcon.invalidate();
+                    }
+                }
+            });
+            va.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (mFolderIcon != null) {
+                        mFolderIcon.setBackgroundDrawable(sFolderInnerRingDrawable);
+                    }
+                    mLauncher.getWorkspace().hideFolderAccept(FolderRingAnimator.this);
+                }
+            });
+            va.start();
+        }
+
+        public void getLocation(int[] loc) {
+            loc[0] = mFolderLocX;
+            loc[1] = mFolderLocY;
+        }
+
+        public float getOuterRingScale() {
+            return mOuterRingScale;
+        }
+
+        public float getInnerRingScale() {
+            return mInnerRingScale;
+        }
     }
 
     private boolean willAcceptItem(ItemInfo item) {
@@ -166,69 +252,22 @@
         mOriginalHeight = lp.height;
     }
 
-    private void animateToAcceptState() {
-        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-        va.setDuration(CONSUMPTION_ANIMATION_DURATION);
-        va.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = (Float) animation.getAnimatedValue();
-                mOuterRingScale = OUTER_RING_BASELINE_SCALE + percent * OUTER_RING_GROWTH_FACTOR;
-                mInnerRingScale = INNER_RING_BASELINE_SCALE + percent * INNER_RING_GROWTH_FACTOR;
-                mLauncher.getWorkspace().invalidate();
-                invalidate();
-            }
-        });
-        va.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                // Instead of setting the background drawable to null, we set the color to
-                // transparent. Setting the background drawable to null results in onDraw
-                // not getting called.
-                setBackgroundColor(Color.TRANSPARENT);
-                requestLayout();
-            }
-        });
-        va.start();
-    }
-
-    private void animateToNaturalState() {
-        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
-        va.setDuration(CONSUMPTION_ANIMATION_DURATION);
-        va.addUpdateListener(new AnimatorUpdateListener() {
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float percent = (Float) animation.getAnimatedValue();
-                mOuterRingScale = OUTER_RING_BASELINE_SCALE + OUTER_RING_GROWTH_FACTOR
-                        - percent * OUTER_RING_GROWTH_FACTOR;
-                mInnerRingScale = INNER_RING_BASELINE_SCALE + INNER_RING_GROWTH_FACTOR
-                        - percent * INNER_RING_GROWTH_FACTOR;
-                mLauncher.getWorkspace().invalidate();
-                invalidate();
-            }
-        });
-        va.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                setBackgroundDrawable(sFolderInnerRingDrawable);
-                mLauncher.getWorkspace().hideFolderAccept(FolderIcon.this);
-            }
-        });
-        va.start();
-    }
-
     private void determineFolderLocationInWorkspace() {
         int tvLocation[] = new int[2];
         int wsLocation[] = new int[2];
         getLocationOnScreen(tvLocation);
         mLauncher.getWorkspace().getLocationOnScreen(wsLocation);
-        mFolderLocX = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
-        mFolderLocY = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
+
+        int x = tvLocation[0] - wsLocation[0] + getMeasuredWidth() / 2;
+        int y = tvLocation[1] - wsLocation[1] + getMeasuredHeight() / 2;
+        mFolderRingAnimator.setLocation(x, y);
     }
 
     public void onDragEnter(DragObject d) {
         if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
         determineFolderLocationInWorkspace();
-        mLauncher.getWorkspace().showFolderAccept(this);
-        animateToAcceptState();
+        mLauncher.getWorkspace().showFolderAccept(mFolderRingAnimator);
+        mFolderRingAnimator.animateToAcceptState();
     }
 
     public void onDragOver(DragObject d) {
@@ -236,26 +275,13 @@
 
     public void onDragExit(DragObject d) {
         if (!willAcceptItem((ItemInfo) d.dragInfo)) return;
-        animateToNaturalState();
+        mFolderRingAnimator.animateToNaturalState();
     }
 
     public DropTarget getDropTargetDelegate(DragObject d) {
         return null;
     }
 
-    public void getFolderLocation(int[] loc) {
-        loc[0] = mFolderLocX;
-        loc[1] = mFolderLocY;
-    }
-
-    public float getOuterRingScale() {
-        return mOuterRingScale;
-    }
-
-    public float getInnerRingScale() {
-        return mInnerRingScale;
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         if (mFolder == null) return;
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index c3d0eea..48869d3 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -3201,7 +3201,7 @@
         // Find the app market activity by resolving an intent.
         // (If multiple app markets are installed, it will return the ResolverActivity.)
         ComponentName activityName = intent.resolveActivity(getPackageManager());
-        if (activityName != null && LauncherApplication.isScreenLarge()) {
+        if (activityName != null) {
             mAppMarketIntent = intent;
             sAppMarketIcon = updateTextButtonWithIconFromExternalActivity(
                     R.id.market_button, activityName, R.drawable.app_market_generic);
diff --git a/src/com/android/launcher2/LauncherAppWidgetHostView.java b/src/com/android/launcher2/LauncherAppWidgetHostView.java
index 0dd1d83..670c8b6 100644
--- a/src/com/android/launcher2/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher2/LauncherAppWidgetHostView.java
@@ -18,6 +18,7 @@
 
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
+import android.content.res.Resources;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -39,8 +40,15 @@
     public LauncherAppWidgetHostView(Context context) {
         super(context);
         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        Resources r = context.getResources();
+        // We add necessary padding to the AppWidgetHostView
+        setPadding(r.getDimensionPixelSize(R.dimen.app_widget_padding_left),
+                r.getDimensionPixelSize(R.dimen.app_widget_padding_top),
+                r.getDimensionPixelSize(R.dimen.app_widget_padding_right),
+                r.getDimensionPixelSize(R.dimen.app_widget_padding_bottom));
     }
-    
+
     @Override
     protected View getErrorView() {
         return mInflater.inflate(R.layout.appwidget_error, this, false);
@@ -52,7 +60,7 @@
             mHasPerformedLongPress = false;
             return true;
         }
-            
+
         // Watch for longpress events at this level to make sure
         // users can always pick up this widget
         switch (ev.getAction()) {
@@ -60,7 +68,7 @@
                 postCheckForLongClick();
                 break;
             }
-            
+
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
                 mHasPerformedLongPress = false;
@@ -69,7 +77,7 @@
                 }
                 break;
         }
-        
+
         // Otherwise continue letting touch events fall through to children
         return false;
     }
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index bd41e02..79f647a 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -113,8 +113,8 @@
     protected int mPageLayoutWidthGap;
     protected int mPageLayoutHeightGap;
     protected int mPageLayoutMaxHeight;
-    protected int mCellCountX = -1;
-    protected int mCellCountY = -1;
+    protected int mCellCountX = 0;
+    protected int mCellCountY = 0;
     protected boolean mCenterPagesVertically;
     protected boolean mAllowOverScroll = true;
     protected int mUnboundedScrollX;
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index b05bd49..7d1ee19 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -67,6 +67,7 @@
 import android.widget.Toast;
 
 import com.android.launcher.R;
+import com.android.launcher2.FolderIcon.FolderRingAnimator;
 import com.android.launcher2.InstallWidgetReceiver.WidgetMimeTypeHandlerData;
 
 /**
@@ -219,7 +220,16 @@
     private int mLastDragXOffset;
     private int mLastDragYOffset;
 
-    private ArrayList<FolderIcon> mFolderOuterRings = new ArrayList<FolderIcon>();
+    private ArrayList<FolderRingAnimator> mFolderOuterRings = new ArrayList<FolderRingAnimator>();
+
+    // Variables relating to the creation of user folders by hovering shortcuts over shortcuts
+    private static final int FOLDER_CREATION_TIMEOUT = 400;
+    private final Alarm mFolderCreationAlarm = new Alarm();
+    private FolderRingAnimator mDragFolderRingAnimator = null;
+    private View mLastDragOverView = null;
+    private boolean mCreateUserFolderOnDrop = false;
+    private int mCellWidth = -1;
+    private int mCellHeight = -1;
 
     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)
     private float mXDown;
@@ -613,10 +623,15 @@
             if (mLauncher.isAllAppsVisible() && mShrinkState == ShrinkState.BOTTOM_HIDDEN) {
                 // Intercept this event so we can show the workspace in full view
                 // when it is clicked on and it is small
-                AllAppsPagedView allApps = (AllAppsPagedView)
-                        mLauncher.findViewById(R.id.all_apps_paged_view);
-                if (allApps != null) {
-                    allApps.onInterceptTouchEvent(ev);
+                PagedView appsPane = null;
+                if (LauncherApplication.isScreenLarge()) {
+                    appsPane = (PagedView) mLauncher.findViewById(R.id.all_apps_paged_view);
+                } else {
+                    appsPane = (PagedView) mLauncher.findViewById(R.id.apps_customize_pane_content);
+                }
+
+                if (appsPane != null) {
+                    appsPane.onInterceptTouchEvent(ev);
                 }
                 return true;
             }
@@ -896,7 +911,6 @@
             }
             float fractionToCatchUpIn1MsVertical = mVerticalCatchupConstant;
 
-
             fractionToCatchUpIn1MsHorizontal /= 33f;
             fractionToCatchUpIn1MsVertical /= 33f;
 
@@ -1184,14 +1198,15 @@
         }
     }
 
-    public void showFolderAccept(FolderIcon fi) {
-        mFolderOuterRings.add(fi);
+    public void showFolderAccept(FolderRingAnimator fra) {
+        mFolderOuterRings.add(fra);
     }
 
-    public void hideFolderAccept(FolderIcon fi) {
-        if (mFolderOuterRings.contains(fi)) {
-            mFolderOuterRings.remove(fi);
+    public void hideFolderAccept(FolderRingAnimator fra) {
+        if (mFolderOuterRings.contains(fra)) {
+            mFolderOuterRings.remove(fra);
         }
+        invalidate();
     }
 
     @Override
@@ -1234,24 +1249,28 @@
         for (int i = 0; i < mFolderOuterRings.size(); i++) {
 
             // Draw outer ring
-            FolderIcon fi = mFolderOuterRings.get(i);
+            FolderRingAnimator fra = mFolderOuterRings.get(i);
             Drawable d = FolderIcon.sFolderOuterRingDrawable;
-            int width = (int) (d.getIntrinsicWidth() * fi.getOuterRingScale());
-            int height = (int) (d.getIntrinsicHeight() * fi.getOuterRingScale());
-            fi.getFolderLocation(mTempLocation);
+            int width = (int) (d.getIntrinsicWidth() * fra.getOuterRingScale());
+            int height = (int) (d.getIntrinsicHeight() * fra.getOuterRingScale());
+            fra.getLocation(mTempLocation);
             int x = mTempLocation[0] + mScrollX - width / 2;
             int y = mTempLocation[1] + mScrollY - height / 2;
             d.setBounds(x, y, x + width, y + height);
             d.draw(canvas);
 
             // Draw inner ring
-            d = FolderIcon.sFolderInnerRingDrawable;
-            width = (int) (fi.getMeasuredWidth() * fi.getInnerRingScale());
-            height = (int) (fi.getMeasuredHeight() * fi.getInnerRingScale());
-            x = mTempLocation[0] + mScrollX - width / 2;
-            y = mTempLocation[1] + mScrollY - height / 2;
-            d.setBounds(x, y, x + width, y + height);
-            d.draw(canvas);
+            if (fra.mFolderIcon != null) {
+                int folderWidth = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellWidth;
+                int folderHeight = fra.mFolderIcon != null ? fra.mFolderIcon.getMeasuredWidth() : mCellHeight;
+                d = FolderIcon.sFolderInnerRingDrawable;
+                width = (int) (folderWidth * fra.getInnerRingScale());
+                height = (int) (folderHeight * fra.getInnerRingScale());
+                x = mTempLocation[0] + mScrollX - width / 2;
+                y = mTempLocation[1] + mScrollY - height / 2;
+                d.setBounds(x, y, x + width, y + height);
+                d.draw(canvas);
+            }
         }
         super.onDraw(canvas);
     }
@@ -2404,9 +2423,7 @@
     }
 
     boolean willCreateUserFolder(ItemInfo info, CellLayout target, int originX, int originY) {
-        mTargetCell = findNearestArea(originX, originY,
-                1, 1, target,
-                mTargetCell);
+        mTargetCell = findNearestArea(originX, originY, 1, 1, target, mTargetCell);
 
         View v = target.getChildAt(mTargetCell[0], mTargetCell[1]);
         boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
@@ -2437,8 +2454,8 @@
         boolean hasntMoved = mDragInfo != null && (mDragInfo.cellX == mTargetCell[0] &&
                 mDragInfo.cellY == mTargetCell[1]);
 
-        if (v == null || hasntMoved) return false;
-
+        if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
+        mCreateUserFolderOnDrop = false;
         final int screen = (mTargetCell == null) ?
                 mDragInfo.screen : indexOfChild(target);
 
@@ -3047,24 +3064,83 @@
                     mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);
                     ItemInfo info = (ItemInfo) d.dragInfo;
 
-                    if (!willCreateUserFolder(info, mDragTargetLayout,
-                            (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1])) {
+                    boolean willCreateUserFolder = willCreateUserFolder(info, mDragTargetLayout,
+                            (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1]);
+
+                    View newDropOver = null;
+                    if (willCreateUserFolder) {
+                        newDropOver = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
+                    }
+
+                    if (newDropOver != mLastDragOverView || !willCreateUserFolder) {
+                        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
+                            mDragFolderRingAnimator.animateToNaturalState();
+                        }
+                        mCreateUserFolderOnDrop = false;
+                        mFolderCreationAlarm.cancelAlarm();
                         mIsDraggingOverIcon = false;
+                    }
+
+                    if (willCreateUserFolder && !mIsDraggingOverIcon) {
+                        mIsDraggingOverIcon = true;
+
+                        mLastDragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
+                        mFolderCreationAlarm.setOnAlarmListener(new FolderCreationAlarmListener(mLastDragOverView));
+                        mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);
+
+                        mDragTargetLayout.clearDragOutlines();
+                    }
+
+                    if (!mCreateUserFolderOnDrop) {
                         mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
                                 (int) mDragViewVisualCenter[0],
                                 (int) mDragViewVisualCenter[1],
                                 item.spanX, item.spanY);
-                    } else if (!mIsDraggingOverIcon) {
-                        mIsDraggingOverIcon = true;
-                        mDragTargetLayout.clearDragOutlines();
                     }
                 }
             }
         }
     }
 
+    class FolderCreationAlarmListener implements OnAlarmListener {
+        View v;
+
+        public FolderCreationAlarmListener(View v) {
+            this.v = v;
+        }
+
+        public void onAlarm(Alarm alarm) {
+            int tvLocation[] = new int[2];
+            int wsLocation[] = new int[2];
+            v.getLocationOnScreen(tvLocation);
+            getLocationOnScreen(wsLocation);
+
+            if (mCellWidth < 0 || mCellHeight < 0) {
+                mCellWidth = mDragTargetLayout.getCellWidth();
+                mCellHeight = mDragTargetLayout.getCellHeight();
+            }
+            int x = tvLocation[0] - wsLocation[0] + mCellWidth / 2;
+            int y = tvLocation[1] - wsLocation[1] + mCellHeight / 2;
+
+            if (mDragFolderRingAnimator == null) {
+                mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);
+            }
+            mDragFolderRingAnimator.setLocation(x, y);
+            mDragFolderRingAnimator.animateToAcceptState();
+            showFolderAccept(mDragFolderRingAnimator);
+            mCreateUserFolderOnDrop = true;
+            mDragTargetLayout.clearDragOutlines();
+        }
+    }
+
     private void doDragExit() {
         mWasSpringLoadedOnDragExit = mShrinkState == ShrinkState.SPRING_LOADED;
+
+        if (mDragFolderRingAnimator != null && mCreateUserFolderOnDrop) {
+            mDragFolderRingAnimator.animateToNaturalState();
+        }
+        mFolderCreationAlarm.cancelAlarm();
+
         if (mDragTargetLayout != null) {
             mDragTargetLayout.onDragExit();
         }