added support for dragging widgets and app icons to mini screens

- gave mini screens a rounded rect background
- mini screens change color when dragged over
- added a way to specify the active region of dragged items, to allow for clipping of whitespace at borders
- fixed: feedback while dragging was often one cell off
- fixed: bug when adding to almost-full screen
- removed unused classes

Change-Id: I2fbd2aaaee6831b288cca8dec75e7b446068e8d1
diff --git a/res/drawable-xlarge/mini_home_screen_bg.9.png b/res/drawable-xlarge/mini_home_screen_bg.9.png
new file mode 100644
index 0000000..fd989c1
--- /dev/null
+++ b/res/drawable-xlarge/mini_home_screen_bg.9.png
Binary files differ
diff --git a/res/drawable-xlarge/mini_home_screen_bg_hover.9.png b/res/drawable-xlarge/mini_home_screen_bg_hover.9.png
new file mode 100644
index 0000000..331ad54
--- /dev/null
+++ b/res/drawable-xlarge/mini_home_screen_bg_hover.9.png
Binary files differ
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 72eeb22..be3135c 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -181,7 +181,6 @@
         app = new ApplicationInfo(app);
 
         mDragController.startDrag(v, this, app, DragController.DRAG_ACTION_COPY);
-        mLauncher.closeAllApps(true);
         return true;
     }
 
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index e86b305..4c08ca6 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
@@ -81,10 +82,15 @@
     private Bitmap mDimmedBitmap;
     private Canvas mDimmedBitmapCanvas;
     private float mDimmedBitmapAlpha;
-    private boolean mDimmedBitmapDirty;
+    private boolean mDimmedBitmapDirty = false;
     private final Paint mDimmedBitmapPaint = new Paint();
     private final Rect mLayoutRect = new Rect();
     private final Rect mDimmedBitmapRect = new Rect();
+    private Drawable mDimmedBitmapBackground;
+    private Drawable mDimmedBitmapBackgroundHover;
+    // If we're actively dragging something over this screen and it's small,
+    // mHover is true
+    private boolean mHover = false;
 
     private final RectF mDragRect = new RectF();
 
@@ -122,6 +128,14 @@
         mVacantDrawable = getResources().getDrawable(R.drawable.rounded_rect_green);
         mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
 
+        if (LauncherApplication.isScreenXLarge()) {
+            mDimmedBitmapBackground = getResources().getDrawable(
+                    R.drawable.mini_home_screen_bg);
+
+            mDimmedBitmapBackgroundHover = getResources().getDrawable(
+                    R.drawable.mini_home_screen_bg_hover);
+        }
+
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
 
         mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
@@ -148,8 +162,20 @@
         mDimmedBitmapPaint.setFilterBitmap(true);
     }
 
+    public void setHover(boolean value) {
+        if (mHover != value) {
+            invalidate();
+        }
+        mHover = value;
+    }
+
     @Override
     public void dispatchDraw(Canvas canvas) {
+        if (mDimmedBitmapAlpha > 0.0f) {
+            final Drawable bg = mHover ? mDimmedBitmapBackgroundHover : mDimmedBitmapBackground;
+            bg.setAlpha((int) (mDimmedBitmapAlpha * 255));
+            bg.draw(canvas);
+        }
         super.dispatchDraw(canvas);
     }
 
@@ -567,6 +593,12 @@
         super.onSizeChanged(w, h, oldw, oldh);
         mLayoutRect.set(0, 0, w, h);
         mDimmedBitmapRect.set(0, 0, (int) (DIMMED_BITMAP_SCALE * w), (int) (DIMMED_BITMAP_SCALE * h));
+        if (mDimmedBitmapBackground != null) {
+            mDimmedBitmapBackground.setBounds(mLayoutRect);
+        }
+        if (mDimmedBitmapBackgroundHover != null) {
+            mDimmedBitmapBackgroundHover.setBounds(mLayoutRect);
+        }
     }
 
     @Override
@@ -619,19 +651,12 @@
         // draw the screen into the bitmap
         // just for drawing to the bitmap, make all the items on the screen opaque
         setChildrenAlpha(1.0f);
-        dispatchDraw(mDimmedBitmapCanvas);
+        // call our superclass's dispatchdraw so we don't draw the background
+        super.dispatchDraw(mDimmedBitmapCanvas);
         setChildrenAlpha(1.0f - mDimmedBitmapAlpha);
 
-        // make the bitmap 'dimmed' ie colored regions are dark grey,
-        // the rest is light grey
-        // We draw grey to the whole bitmap, but filter where we draw based on
-        // what regions are transparent or not (SRC_OUT), causing the intended effect
-
-        // First, draw light grey everywhere in the background (currently transparent) regions
-        // This will leave the regions with the widgets as mostly transparent
-        mDimmedBitmapCanvas.drawColor(0xCCCCCCCC, PorterDuff.Mode.SRC_OUT);
-        // Now, fill the the remaining transparent regions with dark grey
-        mDimmedBitmapCanvas.drawColor(0xCC333333, PorterDuff.Mode.SRC_OUT);
+        // replace all colored areas with a dark  (semi-transparent black)
+        mDimmedBitmapCanvas.drawColor(Color.argb(160, 0, 0, 0), PorterDuff.Mode.SRC_IN);
     }
 
     private boolean isVacant(int originX, int originY, int spanX, int spanY) {
@@ -683,9 +708,9 @@
         final int countX = mCountX;
         final int countY = mCountY;
 
-        // originX and originY give the top left of the cell, but pointToCellRounded
-        // compares center-to-center, so pass in the middle coordinates
-        pointToCellRounded(originX + (mCellWidth / 2), originY + (mCellHeight / 2), result);
+        // pointToCellRounded takes the top left of a cell but will pad that with
+        // cellWidth/2 and cellHeight/2 when finding the matching cell
+        pointToCellRounded(originX, originY, result);
 
         // If the item isn't fully on this screen, snap to the edges
         int rightOverhang = result[0] + spanX - countX;
@@ -798,6 +823,7 @@
         mDragCell[0] = -1;
         mDragCell[1] = -1;
 
+        setHover(false);
         mDragRect.setEmpty();
         invalidate();
     }
@@ -1104,12 +1130,12 @@
         private int mCountX;
         private int mCountY;
         View cell;
-        int cellX;
-        int cellY;
+        int cellX = -1;
+        int cellY = -1;
         // intersectX and intersectY constrain the results of findCellForSpan; any empty space
         // it results must include this point (unless intersectX and intersectY are -1)
-        int intersectX;
-        int intersectY;
+        int intersectX = -1;
+        int intersectY = -1;
         int spanX;
         int spanY;
         int screen;
@@ -1179,7 +1205,7 @@
                 endY = Math.min(endY, intersectY + (spanY - 1));
             }
 
-            for (int x = startX; x < endX + 1; x++) {
+            for (int x = startX; x < endX; x++) {
                 inner:
                 for (int y = startY; y < endY; y++) {
                     for (int i = 0; i < spanX; i++) {
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 4a955b2..ef619be 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -166,12 +166,26 @@
         final View animView = v;
         switch (mCustomizationType) {
         case WidgetCustomization:
+            // We assume that the view v is a TextView with a compound drawable on top, and that the
+            // whole text view is centered horizontally and top aligned. We get a more precise
+            // drag point using this information
+            final TextView textView = (TextView) animView;
+            final Drawable[] drawables = textView.getCompoundDrawables();
+            final Drawable icon = drawables[1];
+            int dragPointOffsetX = 0;
+            int dragPointOffsetY = 0;
+            Rect bounds = null;
+            if (icon != null) {
+                bounds = icon.getBounds();
+                bounds.left = (v.getWidth() - bounds.right) / 2;
+                bounds.right += bounds.left;
+            }
+
             AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo) v.getTag();
             LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(appWidgetInfo.provider);
             dragInfo.minWidth = appWidgetInfo.minWidth;
             dragInfo.minHeight = appWidgetInfo.minHeight;
-            mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY);
-            mLauncher.hideCustomizationDrawer();
+            mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY, bounds);
             return true;
         case FolderCustomization:
             // animate some feedback to the long press
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 651b6f0..e18470a 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -151,7 +151,7 @@
 
     /**
      * Starts a drag.
-     * 
+     *
      * @param v The view that is being dragged
      * @param source An object representing where the drag originated
      * @param dragInfo The data associated with the object that is being dragged
@@ -159,6 +159,22 @@
      *        {@link #DRAG_ACTION_COPY}
      */
     public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
+        startDrag(v, source, dragInfo, dragAction, null);
+    }
+
+    /**
+     * Starts a drag.
+     *
+     * @param v The view that is being dragged
+     * @param source An object representing where the drag originated
+     * @param dragInfo The data associated with the object that is being dragged
+     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+     *        {@link #DRAG_ACTION_COPY}
+     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
+     */
+    public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
+            Rect dragRegion) {
         mOriginator = v;
 
         Bitmap b = getViewBitmap(v);
@@ -174,7 +190,7 @@
         int screenY = loc[1];
 
         startDrag(b, screenX, screenY, 0, 0, b.getWidth(), b.getHeight(),
-                source, dragInfo, dragAction);
+                source, dragInfo, dragAction, dragRegion);
 
         b.recycle();
 
@@ -185,7 +201,7 @@
 
     /**
      * Starts a drag.
-     * 
+     *
      * @param b The bitmap to display as the drag image.  It will be re-scaled to the
      *          enlarged size.
      * @param screenX The x position on screen of the left-top of the bitmap.
@@ -202,6 +218,31 @@
     public void startDrag(Bitmap b, int screenX, int screenY,
             int textureLeft, int textureTop, int textureWidth, int textureHeight,
             DragSource source, Object dragInfo, int dragAction) {
+        startDrag(b, screenX, screenY, textureLeft, textureTop, textureWidth, textureHeight,
+                source, dragInfo, dragAction, null);
+    }
+
+    /**
+     * Starts a drag.
+     *
+     * @param b The bitmap to display as the drag image.  It will be re-scaled to the
+     *          enlarged size.
+     * @param screenX The x position on screen of the left-top of the bitmap.
+     * @param screenY The y position on screen of the left-top of the bitmap.
+     * @param textureLeft The left edge of the region inside b to use.
+     * @param textureTop The top edge of the region inside b to use.
+     * @param textureWidth The width of the region inside b to use.
+     * @param textureHeight The height of the region inside b to use.
+     * @param source An object representing where the drag originated
+     * @param dragInfo The data associated with the object that is being dragged
+     * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+     *        {@link #DRAG_ACTION_COPY}
+     * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+     *          Makes dragging feel more precise, e.g. you can clip out a transparent border
+     */
+    public void startDrag(Bitmap b, int screenX, int screenY,
+            int textureLeft, int textureTop, int textureWidth, int textureHeight,
+            DragSource source, Object dragInfo, int dragAction, Rect dragRegion) {
         if (PROFILE_DRAWING_DURING_DRAG) {
             android.os.Debug.startMethodTracing("Launcher");
         }
@@ -220,8 +261,10 @@
         int registrationX = ((int)mMotionDownX) - screenX;
         int registrationY = ((int)mMotionDownY) - screenY;
 
-        mTouchOffsetX = mMotionDownX - screenX;
-        mTouchOffsetY = mMotionDownY - screenY;
+        final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
+        final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
+        mTouchOffsetX = mMotionDownX - screenX - dragRegionLeft;
+        mTouchOffsetY = mMotionDownY - screenY - dragRegionTop;
 
         mDragging = true;
         mDragSource = source;
@@ -231,6 +274,12 @@
 
         DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY,
                 textureLeft, textureTop, textureWidth, textureHeight);
+
+        if (dragRegion != null) {
+            dragView.setDragRegion(dragRegionLeft, dragRegion.top,
+                    dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
+        }
+
         dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
     }
 
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index bae592c..41e76f0 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -39,6 +39,11 @@
     private int mRegistrationX;
     private int mRegistrationY;
 
+    private int mDragRegionLeft = 0;
+    private int mDragRegionTop = 0;
+    private int mDragRegionWidth;
+    private int mDragRegionHeight;
+
     SymmetricalLinearTween mTween;
     private float mScale;
     private float mAnimationScale = 1.0f;
@@ -71,12 +76,37 @@
         scale.setScale(scaleFactor, scaleFactor);
 
         mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
+        mDragRegionWidth = width;
+        mDragRegionHeight = height;
 
         // The point in our scaled bitmap that the touch events are located
         mRegistrationX = registrationX + (DRAG_SCALE / 2);
         mRegistrationY = registrationY + (DRAG_SCALE / 2);
     }
 
+    public void setDragRegion(int left, int top, int width, int height) {
+        mDragRegionLeft = left;
+        mDragRegionTop = top;
+        mDragRegionWidth = width;
+        mDragRegionHeight = height;
+    }
+
+    public int getDragRegionLeft() {
+        return mDragRegionLeft;
+    }
+
+    public int getDragRegionTop() {
+        return mDragRegionTop;
+    }
+
+    public int getDragRegionWidth() {
+        return mDragRegionWidth;
+    }
+
+    public int getDragRegionHeight() {
+        return mDragRegionHeight;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
diff --git a/src/com/android/launcher2/FolderListAdapter.java b/src/com/android/launcher2/FolderListAdapter.java
deleted file mode 100644
index ebb3332..0000000
--- a/src/com/android/launcher2/FolderListAdapter.java
+++ /dev/null
@@ -1,36 +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.launcher2;
-
-import com.android.launcher.R;
-
-import android.content.Context;
-import android.content.pm.ResolveInfo;
-
-public class FolderListAdapter extends IntentListAdapter {
-
-    public FolderListAdapter(Context context, String actionFilter) {
-        super(context, actionFilter);
-
-        // Manually create a separate entry for creating a folder in Launcher
-        ResolveInfo folder = new ResolveInfo();
-        folder.icon = R.drawable.ic_launcher_folder;
-        folder.labelRes = R.string.group_folder;
-        folder.resolvePackageName = context.getPackageName();
-        mIntentList.add(0, folder);
-    }
-}
diff --git a/src/com/android/launcher2/IntentListAdapter.java b/src/com/android/launcher2/IntentListAdapter.java
deleted file mode 100644
index f844738..0000000
--- a/src/com/android/launcher2/IntentListAdapter.java
+++ /dev/null
@@ -1,83 +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.launcher2;
-
-import com.android.launcher.R;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.provider.LiveFolders;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class IntentListAdapter extends BaseAdapter {
-    private LayoutInflater mLayoutInflater;
-    private PackageManager mPackageManager;
-    protected List<ResolveInfo> mIntentList;
-
-    public IntentListAdapter(Context context, String actionFilter) {
-        mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mPackageManager = context.getPackageManager();
-
-        Intent createLiveFolderIntent = new Intent(actionFilter);
-        mIntentList = mPackageManager.queryIntentActivities(createLiveFolderIntent, 0);
-    }
-
-    public int getCount() {
-        return mIntentList.size();
-    }
-
-    public Object getItem(int position) {
-        return mIntentList.get(position);
-    }
-
-    public long getItemId(int position) {
-        return position;
-    }
-
-    public View getView(int position, View convertView, ViewGroup parent) {
-        TextView textView;
-
-        if (convertView == null) {
-            textView = (TextView) mLayoutInflater.inflate(
-                    R.layout.home_customization_drawer_item, parent, false);
-        } else {
-            textView = (TextView) convertView;
-        }
-
-        ResolveInfo info = mIntentList.get(position);
-        Drawable image = info.loadIcon(mPackageManager);
-        image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
-        textView.setCompoundDrawables(null, image, null, null);
-
-        CharSequence label = info.loadLabel(mPackageManager);
-        textView.setText(label);
-
-        return textView;
-    }
-}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index c4bb69e..ee70b5e 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -205,6 +205,7 @@
     private LauncherAppWidgetHost mAppWidgetHost;
 
     private CellLayout.CellInfo mAddItemCellInfo;
+    private int[] mAddItemCoordinates;
     private CellLayout.CellInfo mMenuAddInfo;
     private final int[] mCellCoordinates = new int[2];
     private FolderInfo mFolderInfo;
@@ -791,6 +792,7 @@
 
         final int addScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
         if (addScreen > -1) {
+            mAddItemCoordinates = null;
             mAddItemCellInfo = new CellLayout.CellInfo();
             final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo;
             addItemCellInfo.valid = true;
@@ -818,7 +820,7 @@
      * Finds all the views we need and configure them properly.
      */
     private void setupViews() {
-        DragController dragController = mDragController;
+        final DragController dragController = mDragController;
 
         DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer);
         dragLayer.setDragController(dragController);
@@ -1040,8 +1042,26 @@
         int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight, null);
 
         // Try finding open space on Launcher screen
+        // We have saved the position to which the widget was dragged-- this really only matters
+        // if we are placing widgets on a "spring-loaded" screen
         final int[] xy = mCellCoordinates;
-        if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
+
+        // For now, we don't save the coordinate where we dropped the icon because we're not
+        // supporting spring-loaded mini-screens; however, leaving the ability to directly place
+        // a widget on the home screen in case we want to add it in the future
+        final int[] xyTouch = null;
+        //final int[] xyTouch = mAddItemCoordinates;
+        boolean findNearestVacantAreaFailed = false;
+        if (xyTouch != null) {
+            CellLayout screen = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
+            int[] result = screen.findNearestVacantArea(
+                    mAddItemCoordinates[0], mAddItemCoordinates[1],
+                    spans[0], spans[1], cellInfo, xy);
+            findNearestVacantAreaFailed = (result == null);
+        }
+
+        if (findNearestVacantAreaFailed ||
+                (xyTouch == null && !findSlot(cellInfo, xy, spans[0], spans[1]))) {
             if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
             return;
         }
@@ -1053,7 +1073,7 @@
 
         LauncherModel.addItemToDatabase(this, launcherInfo,
                 LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
+                cellInfo.screen, xy[0], xy[1], false);
 
         if (!mRestoring) {
             mDesktopItems.add(launcherInfo);
@@ -1064,7 +1084,7 @@
             launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
             launcherInfo.hostView.setTag(launcherInfo);
 
-            mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
+            mWorkspace.addInScreen(launcherInfo.hostView, cellInfo.screen, xy[0], xy[1],
                     launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
         }
     }
@@ -1307,7 +1327,7 @@
 
         // Disable add if the workspace is full.
         if (visible) {
-            mMenuAddInfo = mWorkspace.updateOccupiedCells(null);
+            mMenuAddInfo = mWorkspace.updateOccupiedCellsForCurrentScreen(null);
             menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid);
         }
 
@@ -1317,8 +1337,9 @@
     // we need to initialize mAddItemCellInfo before adding something to the homescreen -- when
     // using the settings menu to add an item, something similar happens in showAddDialog
     public void prepareAddItemFromHomeCustomizationDrawer() {
-        mMenuAddInfo = mWorkspace.updateOccupiedCells(null);
+        mMenuAddInfo = mWorkspace.updateOccupiedCellsForCurrentScreen(null);
         mAddItemCellInfo = mMenuAddInfo;
+        mAddItemCellInfo = null;
     }
 
     @Override
@@ -1369,8 +1390,12 @@
         }
     }
 
-    void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) {
+    void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo,
+            int[] position) {
         mAddItemCellInfo = cellInfo;
+
+        // only set mAddItemCoordinates if we dropped on home screen in "spring-loaded" manner
+        mAddItemCoordinates = position;
         int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
         AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, appWidgetProvider);
         addAppWidgetImpl(appWidgetId);
@@ -1523,9 +1548,8 @@
 
     private boolean findSlot(CellLayout.CellInfo cellInfo, int[] xy, int spanX, int spanY) {
         if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
-            boolean[] occupied = mSavedState != null ?
-                    mSavedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS) : null;
-            cellInfo = mWorkspace.updateOccupiedCells(occupied);
+            CellLayout targetLayout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
+            cellInfo = targetLayout.updateOccupiedCells(null, null);
             if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
                 Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show();
                 return false;
@@ -2034,6 +2058,7 @@
 
     private void showAddDialog(CellLayout.CellInfo cellInfo) {
         mAddItemCellInfo = cellInfo;
+        mAddItemCoordinates = null;
         mWaitingForResult = true;
         showDialog(DIALOG_CREATE_SHORTCUT);
     }
diff --git a/src/com/android/launcher2/WidgetListAdapter.java b/src/com/android/launcher2/WidgetListAdapter.java
deleted file mode 100644
index 61e7c89..0000000
--- a/src/com/android/launcher2/WidgetListAdapter.java
+++ /dev/null
@@ -1,135 +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.launcher2;
-
-import com.android.launcher.R;
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Region.Op;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class WidgetListAdapter extends BaseAdapter {
-    private final Launcher mLauncher;
-    private List<AppWidgetProviderInfo> mWidgets;
-    private final Canvas mCanvas = new Canvas();
-
-    private final int[] mTempSize = new int[2];
-    private final Rect mTempRect = new Rect();
-
-    private static final String TAG = "Launcher.WidgetGalleryAdapter";
-
-    WidgetListAdapter(Launcher launcher) {
-        mLauncher = launcher;
-        mWidgets = AppWidgetManager.getInstance(launcher).getInstalledProviders();
-    }
-
-    public int getCount() {
-        return mWidgets.size();
-    }
-
-    public Object getItem(int position) {
-        return mWidgets.get(position);
-    }
-
-    public long getItemId(int position) {
-        return position;
-    }
-
-    public View getView(int position, View convertView, ViewGroup parent) {
-        TextView textView;
-
-        if (convertView == null) {
-            LayoutInflater inflater =
-                (LayoutInflater)mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            textView = (TextView) inflater.inflate(
-                    R.layout.home_customization_drawer_widget, parent, false);
-        } else {
-            textView = (TextView) convertView;
-        }
-
-        AppWidgetProviderInfo info = mWidgets.get(position);
-        PackageManager packageManager = mLauncher.getPackageManager();
-        String packageName = info.provider.getPackageName();
-        Drawable drawable = null;
-        if (info.previewImage != 0) {
-            drawable = packageManager.getDrawable(packageName, info.previewImage, null);
-            if (drawable == null) {
-                Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
-                        + " for provider: " + info.provider);
-            }
-        }
-        // If we don't have a preview image, create a default one
-        if (drawable == null) {
-            Resources resources = mLauncher.getResources();
-
-            // Determine the size the widget will take in the layout
-            mLauncher.getWorkspace().estimateChildSize(info.minWidth, info.minHeight, mTempSize);
-
-            // Create a new bitmap to hold the widget preview
-            final int width = mTempSize[0];
-            final int height = mTempSize[1];
-            Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
-            mCanvas.setBitmap(bitmap);
-            // For some reason, we must re-set the clip rect here, otherwise it will be wrong
-            mCanvas.clipRect(0, 0, width, height, Op.REPLACE);
-
-            Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
-            background.setBounds(0, 0, width, height);
-            background.draw(mCanvas);
-
-            // Draw the icon vertically centered, flush left
-            try {
-                Drawable icon = packageManager.getDrawable(packageName, info.icon, null);
-                background.getPadding(mTempRect);
-
-                final int left = mTempRect.left;
-                final int top = (height - icon.getIntrinsicHeight()) / 2;
-                icon.setBounds(
-                        left, top, left + icon.getIntrinsicWidth(), top + icon.getIntrinsicHeight());
-                icon.draw(mCanvas);
-            } catch (Resources.NotFoundException e) {
-                // if we can't find the icon, then just don't draw it
-            }
-
-            drawable = new BitmapDrawable(resources, bitmap);
-        }
-        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
-        textView.setCompoundDrawables(null, drawable, null, null);
-        textView.setText(info.label);
-        // Store the widget info on the associated view so we can easily fetch it later
-        textView.setTag(info);
-
-        return textView;
-    }
-}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 73eaeab..fc505c7 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -34,6 +34,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -124,6 +125,8 @@
 
     private int[] mTempCell = new int[2];
     private int[] mTempEstimate = new int[2];
+    private float[] mTempDragCoordinates = new float[2];
+    private float[] mTempDragBottomRightCoordinates = new float[2];
 
     private boolean mAllowLongPress = true;
 
@@ -459,7 +462,7 @@
         }
     }
 
-    CellLayout.CellInfo updateOccupiedCells(boolean[] occupied) {
+    CellLayout.CellInfo updateOccupiedCellsForCurrentScreen(boolean[] occupied) {
         CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
         if (group != null) {
             return group.updateOccupiedCells(occupied, null);
@@ -1309,9 +1312,31 @@
 
     public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
-        final CellLayout cellLayout = getCurrentDropLayout();
+        CellLayout cellLayout = getCurrentDropLayout();
+        int originX = x - xOffset;
+        int originY = y - yOffset;
+        if (mIsSmall) {
+            // find out which target layout is over
+            final float[] localXY = mTempDragCoordinates;
+            localXY[0] = originX;
+            localXY[1] = originY;
+            final float[] localBottomRightXY = mTempDragBottomRightCoordinates;
+            // we need to subtract left/top here because DragController already adds
+            // dragRegionLeft/Top to xOffset and yOffset
+            localBottomRightXY[0] = originX + dragView.getDragRegionWidth();
+            localBottomRightXY[1] = originY + dragView.getDragRegionHeight();
+            cellLayout =  findMatchingScreenForDragOver(localXY, localBottomRightXY);
+            if (cellLayout == null) {
+                // cancel the drag if we're not over a mini-screen at time of drop
+                // TODO: maybe add a nice fade here?
+                return;
+            }
+            // localXY will be transformed into the local screen's coordinate space; save that info
+            originX = (int)localXY[0];
+            originY = (int)localXY[1];
+        }
         if (source != this) {
-            onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
+            onDropExternal(originX, originY, dragInfo, cellLayout);
         } else {
             // Move internally
             if (mDragInfo != null) {
@@ -1323,7 +1348,8 @@
                     addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY,
                             mDragInfo.spanX, mDragInfo.spanY);
                 }
-                mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
+
+                mTargetCell = estimateDropCell(originX, originY,
                         mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout,
                         mTargetCell);
                 cellLayout.onDropChild(cell);
@@ -1381,11 +1407,87 @@
         return null;
     }
 
+    // xy = upper left corner of item being dragged
+    // bottomRightXy = lower right corner of item being dragged
+    // This method will see which mini-screen is most overlapped by the item being dragged, and
+    // return it. It will also transform the parameters xy and bottomRightXy into the local
+    // coordinate space of the returned screen
+    private CellLayout findMatchingScreenForDragOver(float[] xy, float[] bottomRightXy) {
+        float x = xy[0];
+        float y = xy[1];
+        float right = bottomRightXy[0];
+        float bottom = bottomRightXy[1];
+
+        float bestX = 0;
+        float bestY = 0;
+        float bestRight = 0;
+        float bestBottom = 0;
+
+        Matrix inverseMatrix = new Matrix();
+
+        // We loop through all the screens (ie CellLayouts) and see which one overlaps the most
+        // with the item being dragged.
+        final int screenCount = getChildCount();
+        CellLayout bestMatchingScreen = null;
+        float bestOverlapSoFar = 0;
+        for (int i = 0; i < screenCount; i++) {
+            CellLayout cl = (CellLayout)getChildAt(i);
+            // Transform the coordinates of the item being dragged to the CellLayout's coordinates
+            float left = cl.getLeft();
+            float top = cl.getTop();
+            xy[0] = x + mScrollX - left;
+            xy[1] = y + mScrollY - top;
+            cl.getMatrix().invert(inverseMatrix);
+
+            bottomRightXy[0] = right + mScrollX - left;
+            bottomRightXy[1] = bottom + mScrollY - top;
+
+            inverseMatrix.mapPoints(xy);
+            inverseMatrix.mapPoints(bottomRightXy);
+
+            float dragRegionX = xy[0];
+            float dragRegionY = xy[1];
+            float dragRegionRight = bottomRightXy[0];
+            float dragRegionBottom = bottomRightXy[1];
+
+            // Find the overlapping region
+            float overlapLeft = Math.max(0f, dragRegionX);
+            float overlapTop = Math.max(0f, dragRegionY);
+            float overlapBottom = Math.min(cl.getHeight(), dragRegionBottom);
+            float overlapRight = Math.min(cl.getWidth(), dragRegionRight);
+
+            if (overlapRight >= 0 && overlapLeft <= cl.getWidth() &&
+                    overlapTop >= 0 && overlapBottom <= cl.getHeight()) {
+                // Calculate the size of the overlapping region
+                float overlap = (overlapRight - overlapLeft) * (overlapBottom - overlapTop);
+                if (overlap > bestOverlapSoFar) {
+                    bestOverlapSoFar = overlap;
+                    bestMatchingScreen = cl;
+                    bestX = xy[0];
+                    bestY = xy[1];
+                    bestRight = bottomRightXy[0];
+                    bestBottom = bottomRightXy[1];
+                }
+             }
+        }
+        if (bestMatchingScreen != null && bestMatchingScreen != mDragTargetLayout) {
+            if (mDragTargetLayout != null) {
+                mDragTargetLayout.onDragComplete();
+            }
+            mDragTargetLayout = bestMatchingScreen;
+        }
+        xy[0] = bestX;
+        xy[1] = bestY;
+        bottomRightXy[0] = bestRight;
+        bottomRightXy[1] = bestBottom;
+        return bestMatchingScreen;
+    }
+
     public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
             DragView dragView, Object dragInfo) {
 
         final ItemInfo item = (ItemInfo)dragInfo;
-        final CellLayout currentLayout = getCurrentDropLayout();
+        CellLayout currentLayout = getCurrentDropLayout();
 
         if (dragInfo instanceof LauncherAppWidgetInfo) {
             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
@@ -1397,6 +1499,39 @@
                 item.spanY = spans[1];
             }
         }
+        int originX = x - xOffset;
+        int originY = y - yOffset;
+        if (mIsSmall) {
+            // find out which mini screen the dragged item is over
+            final float[] localXY = mTempDragCoordinates;
+            localXY[0] = originX;
+            localXY[1] = originY;
+            final float[] localBottomRightXY = mTempDragBottomRightCoordinates;
+
+            localBottomRightXY[0] = originX + dragView.getDragRegionWidth();
+            localBottomRightXY[1] = originY + dragView.getDragRegionHeight();
+            currentLayout = findMatchingScreenForDragOver(localXY, localBottomRightXY);
+            if (currentLayout != null) {
+                currentLayout.setHover(true);
+            }
+
+            originX = (int)localXY[0];
+            originY = (int)localXY[1];
+        }
+
+        if (source != this) {
+            // This is a hack to fix the point used to determine which cell an icon from the all
+            // apps screen is over
+            if (item != null && item.spanX == 1 && currentLayout != null) {
+                int dragRegionLeft = (dragView.getWidth() - currentLayout.getCellWidth()) / 2;
+
+                originX += dragRegionLeft - dragView.getDragRegionLeft();
+                if (dragView.getDragRegionWidth() != currentLayout.getCellWidth()) {
+                    dragView.setDragRegion(dragView.getDragRegionLeft(), dragView.getDragRegionTop(),
+                            currentLayout.getCellWidth(), dragView.getDragRegionHeight());
+                }
+            }
+        }
         if (currentLayout != mDragTargetLayout) {
             if (mDragTargetLayout != null) {
                 mDragTargetLayout.onDragComplete();
@@ -1404,23 +1539,14 @@
             mDragTargetLayout = currentLayout;
         }
 
-        // Find the top left corner of the item
-        int originX = x - xOffset;
-        int originY = y - yOffset;
-
-        // If not dragging from the Workspace, the size of dragView might not match the cell size
-        if (!source.equals(this)) {
-            // Break the drag view up into evenly sized chunks based on its spans
-            int chunkWidth = dragView.getWidth() / item.spanX;
-            int chunkHeight = dragView.getHeight() / item.spanY;
-
-            // Adjust the origin for a cell centered at the top left chunk
-            originX += (chunkWidth - currentLayout.getCellWidth()) / 2;
-            originY += (chunkHeight - currentLayout.getCellHeight()) / 2;
+        // only visualize the drop locations for moving icons within the home screen on tablet
+        // on phone, we also visualize icons dragged in from All Apps
+        if ((!LauncherApplication.isScreenXLarge() || source == this)
+                && mDragTargetLayout != null) {
+            final View child = (mDragInfo == null) ? null : mDragInfo.cell;
+            mDragTargetLayout.visualizeDropLocation(
+                    child, originX, originY, item.spanX, item.spanY);
         }
-
-        final View child = (mDragInfo == null) ? null : mDragInfo.cell;
-        currentLayout.visualizeDropLocation(child, originX, originY, item.spanX, item.spanY);
     }
 
     public void onDragExit(DragSource source, int x, int y, int xOffset,
@@ -1460,7 +1586,11 @@
             break;
         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
             cellLayout.setTagToCellInfoForPoint(x, y);
-            mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag());
+            int[] position = new int[2];
+            position[0] = x;
+            position[1] = y;
+            mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName,
+                    cellLayout.getTag(), position);
             break;
         default:
             throw new IllegalStateException("Unknown item type: "