Merge branch 'master' into honeycomb-release
diff --git a/res/anim/paged_view_click_feedback.xml b/res/anim/paged_view_click_feedback.xml
index 786d974..d1e6e23 100644
--- a/res/anim/paged_view_click_feedback.xml
+++ b/res/anim/paged_view_click_feedback.xml
@@ -16,8 +16,8 @@
 
 <alpha xmlns:android="http://schemas.android.com/apk/res/android"
     android:fromAlpha="1.0"
-    android:toAlpha="0.65"
-    android:duration="100"
+    android:toAlpha="0.5"
+    android:duration="75"
     android:fillAfter="true"
     android:repeatCount="1"
     android:repeatMode="reverse" />
diff --git a/res/values-xlarge/config.xml b/res/values-xlarge/config.xml
index 6a56679..a54528e 100644
--- a/res/values-xlarge/config.xml
+++ b/res/values-xlarge/config.xml
@@ -5,6 +5,10 @@
     <!-- NB: This should be less than the workspaceShrinkTime as they happen together. -->
     <integer name="config_allAppsZoomInTime">350</integer>
 
+    <!-- Duration in milliseconds of the transition between tabs in the all apps/customize
+         tray -->
+    <integer name="config_tabTransitionTime">100</integer>
+
     <!-- Duration in milliseconds of the all apps zoom-out animation -->
     <!-- NB: This should be less than the workspaceUnshrinkTime as they happen together. -->
     <integer name="config_allAppsZoomOutTime">350</integer>
diff --git a/src/com/android/launcher2/AllAppsTabbed.java b/src/com/android/launcher2/AllAppsTabbed.java
index e0ff1a8..a6e21b9 100644
--- a/src/com/android/launcher2/AllAppsTabbed.java
+++ b/src/com/android/launcher2/AllAppsTabbed.java
@@ -76,7 +76,8 @@
         setOnTabChangedListener(new OnTabChangeListener() {
             public void onTabChanged(String tabId) {
                 // animate the changing of the tab content by fading pages in and out
-                final int duration = 150;
+                final Resources res = getResources();
+                final int duration = res.getInteger(R.integer.config_tabTransitionTime);
                 final float alpha = mAllApps.getAlpha();
                 ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mAllApps, "alpha", alpha, 0.0f).
                         setDuration(duration);
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 11c0c18..e340101 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -839,6 +839,10 @@
         mBackgroundAlphaMultiplier = multiplier;
     }
 
+    public float getBackgroundAlphaMultiplier() {
+        return mBackgroundAlphaMultiplier;
+    }
+
     public void setBackgroundAlpha(float alpha) {
         mBackgroundAlpha = alpha;
         invalidate();
@@ -1034,15 +1038,15 @@
         final int countY = mCountY;
         final boolean[][] occupied = mOccupied;
 
-        for (int x = 0; x < countX - (spanX - 1); x++) {
+        for (int y = 0; y < countY - (spanY - 1); y++) {
             inner:
-            for (int y = 0; y < countY - (spanY - 1); y++) {
+            for (int x = 0; x < countX - (spanX - 1); x++) {
                 for (int i = 0; i < spanX; i++) {
                     for (int j = 0; j < spanY; j++) {
                         if (occupied[x + i][y + j]) {
-                            // small optimization: we can skip to below the row we just found
+                            // small optimization: we can skip to after the column we just found
                             // an occupied cell
-                            y += j;
+                            x += i;
                             continue inner;
                         }
                     }
@@ -1150,15 +1154,15 @@
                 endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
             }
 
-            for (int x = startX; x < endX; x++) {
+            for (int y = startY; y < endY && !foundCell; y++) {
                 inner:
-                for (int y = startY; y < endY; y++) {
+                for (int x = startX; x < endX; x++) {
                     for (int i = 0; i < spanX; i++) {
                         for (int j = 0; j < spanY; j++) {
                             if (mOccupied[x + i][y + j]) {
-                                // small optimization: we can skip to below the row we just found
+                                // small optimization: we can skip to after the column we just found
                                 // an occupied cell
-                                y += j;
+                                x += i;
                                 continue inner;
                             }
                         }
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 14b2429..1763a00 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -289,6 +289,7 @@
     public void setCustomizationFilter(CustomizationType filterType) {
         mCustomizationType = filterType;
         setCurrentPage(0);
+        updateCurrentPageScroll();
         invalidatePageData();
 
         // End the current choice mode so that we don't carry selections across tabs
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 81e1847..37c2b41 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -316,7 +316,8 @@
             mHomeCustomizationDrawer.setOnTabChangedListener(new OnTabChangeListener() {
                 public void onTabChanged(String tabId) {
                     // animate the changing of the tab content by fading pages in and out
-                    final int duration = 150;
+                    final Resources res = getResources();
+                    final int duration = res.getInteger(R.integer.config_tabTransitionTime);
                     final float alpha = mCustomizePagedView.getAlpha();
                     ValueAnimator alphaAnim = ObjectAnimator.ofFloat(mCustomizePagedView,
                             "alpha", alpha, 0.0f);
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index 70746b3..109696c 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -245,6 +245,17 @@
     }
 
     /**
+     * Updates the scroll of the current page immediately to its final scroll position.  We use this
+     * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
+     * the previous tab page.
+     */
+    protected void updateCurrentPageScroll() {
+        int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
+        scrollTo(newX, 0);
+        mScroller.setFinalX(newX);
+    }
+
+    /**
      * Sets the current page.
      */
     void setCurrentPage(int currentPage) {
@@ -256,9 +267,7 @@
         }
 
         mCurrentPage = Math.max(0, Math.min(currentPage, getPageCount() - 1));
-        int newX = getChildOffset(mCurrentPage) - getRelativeChildOffset(mCurrentPage);
-        scrollTo(newX, 0);
-        mScroller.setFinalX(newX);
+        updateCurrentPageScroll();
 
         invalidate();
         notifyPageSwitchListener();
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index e068a76..3823cc1 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -20,9 +20,9 @@
 import java.util.HashSet;
 import java.util.List;
 
+import android.R.integer;
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
@@ -55,6 +55,7 @@
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.DragEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -558,12 +559,11 @@
                 int delta = screenCenter - (getChildOffset(i) -
                         getRelativeChildOffset(i) + halfScreenSize);
 
-                float scrollProgress = delta/(totalDistance*1.0f);
+                float scrollProgress = delta / (totalDistance * 1.0f);
                 scrollProgress = Math.min(scrollProgress, 1.0f);
                 scrollProgress = Math.max(scrollProgress, -1.0f);
 
-                float mult =  mInDragMode ? 1.0f : Math.abs(scrollProgress);
-                cl.setBackgroundAlphaMultiplier(mult);
+                cl.setBackgroundAlphaMultiplier(Math.abs(scrollProgress));
 
                 float rotation = WORKSPACE_ROTATION * scrollProgress;
                 cl.setRotationY(rotation);
@@ -779,6 +779,9 @@
         mActivePointerId = INVALID_POINTER;
 
         CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
+        if (currentPage.getBackgroundAlphaMultiplier() < 1.0f) {
+            currentPage.setBackgroundAlpha(0.0f);
+        }
         currentPage.setBackgroundAlphaMultiplier(1.0f);
 
         final Resources res = getResources();
@@ -1043,8 +1046,8 @@
 
         // For a TextView, adjust the clip rect so that we don't include the text label
         if (v instanceof TextView) {
-            final int iconHeight = ((TextView)v).getCompoundPaddingTop() - v.getPaddingTop();
-            clipRect.bottom = clipRect.top + iconHeight;
+            final TextView tv = (TextView) v;
+            clipRect.bottom = clipRect.top + tv.getCompoundPaddingTop() - 1;
         }
 
         // Draw the View into the bitmap.
@@ -1351,8 +1354,6 @@
             mDragTargetLayout.onDragEnter();
             showOutlines();
             mInDragMode = true;
-            CellLayout cl = (CellLayout) getChildAt(mCurrentPage);
-            cl.setBackgroundAlphaMultiplier(1.0f);
         }
     }
 
@@ -1398,6 +1399,30 @@
     }
 
     /**
+     * Tests to see if the drop will be accepted by Launcher, and if so, includes additional data
+     * in the returned structure related to the widgets that match the drop (or a null list if it is
+     * a shortcut drop).  If the drop is not accepted then a null structure is returned.
+     */
+    private Pair<Integer, List<WidgetMimeTypeHandlerData>> validateDrag(DragEvent event) {
+        final LauncherModel model = mLauncher.getModel();
+        final ClipDescription desc = event.getClipDescription();
+        final int mimeTypeCount = desc.getMimeTypeCount();
+        for (int i = 0; i < mimeTypeCount; ++i) {
+            final String mimeType = desc.getMimeType(i);
+            if (mimeType.equals(InstallShortcutReceiver.SHORTCUT_MIMETYPE)) {
+                return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, null);
+            } else {
+                final List<WidgetMimeTypeHandlerData> widgets =
+                    model.resolveWidgetsForMimeType(mContext, mimeType);
+                if (widgets.size() > 0) {
+                    return new Pair<Integer, List<WidgetMimeTypeHandlerData>>(i, widgets);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Global drag and drop handler
      */
     @Override
@@ -1411,10 +1436,22 @@
         final int y = (int) event.getY() - pos[1];
 
         switch (event.getAction()) {
-        case DragEvent.ACTION_DRAG_STARTED:
-            // Check if we have enough space on this screen to add a new shortcut
-            if (!layout.findCellForSpan(pos, 1, 1)) {
-                Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
+        case DragEvent.ACTION_DRAG_STARTED: {
+            // Validate this drag
+            Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event);
+            if (test != null) {
+                boolean isShortcut = (test.second == null);
+                if (isShortcut) {
+                    // Check if we have enough space on this screen to add a new shortcut
+                    if (!layout.findCellForSpan(pos, 1, 1)) {
+                        Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
+                                Toast.LENGTH_SHORT).show();
+                        return false;
+                    }
+                }
+            } else {
+                // Show error message if we couldn't accept any of the items
+                Toast.makeText(mContext, mContext.getString(R.string.external_drop_widget_error),
                         Toast.LENGTH_SHORT).show();
                 return false;
             }
@@ -1432,18 +1469,12 @@
             layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1);
 
             return true;
+        }
         case DragEvent.ACTION_DRAG_LOCATION:
             // Visualize the drop location
             layout.visualizeDropLocation(null, mDragOutline, x, y, 1, 1);
             return true;
-        case DragEvent.ACTION_DROP:
-            // Check if we have enough space on this screen to add a new shortcut
-            if (!layout.findCellForSpan(pos, 1, 1)) {
-                Toast.makeText(mContext, mContext.getString(R.string.out_of_space),
-                        Toast.LENGTH_SHORT).show();
-                return false;
-            }
-
+        case DragEvent.ACTION_DROP: {
             // Try and add any shortcuts
             int newDropCount = 0;
             final LauncherModel model = mLauncher.getModel();
@@ -1455,29 +1486,25 @@
             // representation will be handled.
             pos[0] = x;
             pos[1] = y;
-            final int mimeTypeCount = desc.getMimeTypeCount();
-            for (int j = 0; j < mimeTypeCount; ++j) {
-                final String mimeType = desc.getMimeType(j);
-
-                if (mimeType.equals(InstallShortcutReceiver.SHORTCUT_MIMETYPE)) {
-                    final Intent intent = data.getItem(j).getIntent();
+            Pair<Integer, List<WidgetMimeTypeHandlerData>> test = validateDrag(event);
+            if (test != null) {
+                final int index = test.first;
+                final List<WidgetMimeTypeHandlerData> widgets = test.second;
+                final boolean isShortcut = (widgets == null);
+                final String mimeType = desc.getMimeType(index);
+                if (isShortcut) {
+                    final Intent intent = data.getItem(index).getIntent();
                     Object info = model.infoFromShortcutIntent(mContext, intent, data.getIcon());
                     onDropExternal(x, y, info, layout);
                 } else {
-                    final List<WidgetMimeTypeHandlerData> widgets =
-                        model.resolveWidgetsForMimeType(mContext, mimeType);
-                    final int numWidgets = widgets.size();
-
-                    if (numWidgets == 0) {
-                        continue;
-                    } else if (numWidgets == 1) {
+                    if (widgets.size() == 1) {
                         // If there is only one item, then go ahead and add and configure
                         // that widget
                         final AppWidgetProviderInfo widgetInfo = widgets.get(0).widgetInfo;
                         final PendingAddWidgetInfo createInfo =
                                 new PendingAddWidgetInfo(widgetInfo, mimeType, data);
                         mLauncher.addAppWidgetFromDrop(createInfo, mCurrentPage, pos);
-                    } else if (numWidgets > 1) {
+                    } else {
                         // Show the widget picker dialog if there is more than one widget
                         // that can handle this data type
                         final InstallWidgetReceiver.WidgetListAdapter adapter =
@@ -1493,17 +1520,9 @@
                         builder.show();
                     }
                 }
-                newDropCount++;
-                break;
             }
-
-            // Show error message if we couldn't accept any of the items
-            if (newDropCount <= 0) {
-                Toast.makeText(mContext, mContext.getString(R.string.external_drop_widget_error),
-                        Toast.LENGTH_SHORT).show();
-            }
-
             return true;
+        }
         case DragEvent.ACTION_DRAG_ENDED:
             // Hide the page outlines after the drop
             layout.setHover(false);
@@ -1825,7 +1844,8 @@
         if (view == null) {
             cellLayout.onDragExit();
         } else {
-            mTargetCell = findNearestVacantArea(x, y, 1, 1, null, cellLayout, mTargetCell);
+            mTargetCell = new int[]{x, y};
+            cellLayout.findCellForSpan(mTargetCell, 1, 1);
             addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
                     mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
             cellLayout.onDropChild(view);