Merge "Use the icon bounds for all calculations." into jb-ub-now-jolly-elf
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 7fe83c5..1d234ff 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -119,6 +119,11 @@
     private int DRAG_MODE_REORDER = 1;
     private int mDragMode = DRAG_MODE_NONE;
 
+    // We avoid measuring the scroll view with a 0 width or height, as this
+    // results in CellLayout being measured as UNSPECIFIED, which it does
+    // not support.
+    private static final int MIN_CONTENT_DIMEN = 5;
+
     private boolean mDestroyed;
 
     private AutoScrollHelper mAutoScrollHelper;
@@ -966,8 +971,13 @@
         int maxContentAreaHeight = grid.availableHeightPx -
                 workspacePadding.top - workspacePadding.bottom -
                 mFolderNameHeight;
-        return Math.min(maxContentAreaHeight,
+        int height = Math.min(maxContentAreaHeight,
                 mContent.getDesiredHeight());
+        return Math.max(height, MIN_CONTENT_DIMEN);
+    }
+
+    private int getContentAreaWidth() {
+        return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
     }
 
     private int getFolderHeight() {
@@ -979,11 +989,12 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
         int height = getFolderHeight();
-        int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
+        int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
                 MeasureSpec.EXACTLY);
         int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
                 MeasureSpec.EXACTLY);
-        mContent.setFixedSize(mContent.getDesiredWidth(), mContent.getDesiredHeight());
+
+        mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
         mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
         mFolderName.measure(contentAreaWidthSpec,
                 MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0c14ed9..cfc5c48 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,7 +45,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -113,6 +112,7 @@
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Default launcher application.
@@ -181,8 +181,10 @@
     private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
     // Type: parcelable
     private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
- // Type: parcelable
+    // Type: parcelable
     private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_ID = "launcher.add_widget_id";
+    // Type: int[]
+    private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids";
 
     private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
     private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
@@ -207,6 +209,9 @@
     private static final Object sLock = new Object();
     private static int sScreen = DEFAULT_SCREEN;
 
+    private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
+    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+
     // How long to wait before the new-shortcut animation automatically pans the workspace
     private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@@ -671,6 +676,34 @@
     }
 
     /**
+     * Copied from View -- the View version of the method isn't called
+     * anywhere else in our process and only exists for API level 17+,
+     * so it's ok to keep our own version with no API requirement.
+     */
+    public static int generateViewId() {
+        for (;;) {
+            final int result = sNextGeneratedId.get();
+            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+            int newValue = result + 1;
+            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
+            if (sNextGeneratedId.compareAndSet(result, newValue)) {
+                return result;
+            }
+        }
+    }
+
+    public int getViewIdForItem(ItemInfo info) {
+        // This cast is safe given the > 2B range for int.
+        int itemId = (int) info.id;
+        if (mItemIdToViewId.containsKey(itemId)) {
+            return mItemIdToViewId.get(itemId);
+        }
+        int viewId = generateViewId();
+        mItemIdToViewId.put(itemId, viewId);
+        return viewId;
+    }
+
+    /**
      * Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
      * a configuration step, this allows the proper animations to run after other transitions.
      */
@@ -1108,6 +1141,7 @@
      *
      * @param savedState The previous state.
      */
+    @SuppressWarnings("unchecked")
     private void restoreState(Bundle savedState) {
         if (savedState == null) {
             return;
@@ -1160,6 +1194,8 @@
             int currentIndex = savedState.getInt("apps_customize_currentIndex");
             mAppsCustomizeContent.restorePageForIndex(currentIndex);
         }
+        mItemIdToViewId = (HashMap<Integer, Integer>)
+                savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
     }
 
     /**
@@ -1704,7 +1740,7 @@
             // In all these cases, only animate if we're already on home
             mWorkspace.exitWidgetResizeMode();
             if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
-                    openFolder == null) {
+                    openFolder == null && shouldMoveToDefaultScreenOnHomeIntent()) {
                 mWorkspace.moveToDefaultScreen(true);
             }
 
@@ -1730,6 +1766,8 @@
             if (mAppsCustomizeTabHost != null) {
                 mAppsCustomizeTabHost.reset();
             }
+
+            onHomeIntent();
         }
 
         if (DEBUG_RESUME_TIME) {
@@ -1737,6 +1775,21 @@
         }
     }
 
+    /**
+     * Override point for subclasses to prevent movement to the default screen when the home
+     * button is pressed. Used (for example) in GEL, to prevent movement during a search.
+     */
+    protected boolean shouldMoveToDefaultScreenOnHomeIntent() {
+        return true;
+    }
+
+    /**
+     * Override point for subclasses to provide custom behaviour for when a home intent is fired.
+     */
+    protected void onHomeIntent() {
+        // Do nothing
+    }
+
     @Override
     public void onRestoreInstanceState(Bundle state) {
         super.onRestoreInstanceState(state);
@@ -1784,6 +1837,7 @@
             int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
             outState.putInt("apps_customize_currentIndex", currentIndex);
         }
+        outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
     }
 
     @Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 9f4f9d9..8ef0ff2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -949,7 +949,9 @@
         }
 
         // Get the canonical child id to uniquely represent this view in this screen
-        int childId = LauncherModel.getCellLayoutChildId(container, screenId, x, y, spanX, spanY);
+        ItemInfo info = (ItemInfo) child.getTag();
+        int childId = mLauncher.getViewIdForItem(info);
+
         boolean markCellsAsOccupied = !(child instanceof Folder);
         if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
             // TODO: This branch occurs when the workspace is adding views
@@ -2108,7 +2110,8 @@
             if (stateIsSmall) {
                 finalAlpha = 0f;
             } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
-                finalAlpha = i == getNextPage() ? 1f : 0f;
+
+                finalAlpha = (i == getNextPage() || i < numCustomPages()) ? 1f : 0f;
             } else {
                 finalAlpha = 1f;
             }
@@ -2349,6 +2352,11 @@
                 final CellLayout cl = (CellLayout) getChildAt(i);
                 cl.setShortcutAndWidgetAlpha(1f);
             }
+        } else {
+            for (int i = 0; i < numCustomPages(); i++) {
+                final CellLayout cl = (CellLayout) getChildAt(i);
+                cl.setShortcutAndWidgetAlpha(1f);
+            }
         }
         showCustomContentIfNecessary();
     }
@@ -2536,6 +2544,13 @@
             icon.clearPressedOrFocusedBackground();
         }
 
+        if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
+            String msg = "Drag started with a view that has no tag set. This "
+                    + "will cause a crash (issue 11627249) down the line. "
+                    + "View: " + child + "  tag: " + child.getTag();
+            throw new IllegalStateException(msg);
+        }
+
         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
                 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
@@ -2884,8 +2899,6 @@
                     lp.cellHSpan = item.spanX;
                     lp.cellVSpan = item.spanY;
                     lp.isLockedToGrid = true;
-                    cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId,
-                            mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
 
                     if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
                             cell instanceof LauncherAppWidgetHostView) {
@@ -4567,6 +4580,7 @@
                 child.requestFocus();
             }
          }
+        exitWidgetResizeMode();
     }
 
     @Override