Merge "Adding pressed state to overview mode buttons (issue 10926631)" into jb-ub-now-indigo-rose
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 22492ac..a114ec3 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -927,6 +927,8 @@
         return r;
     }
 
+    /** Return a rect that has the cellWidth/cellHeight (left, top), and
+     * widthGap/heightGap (right, bottom) */
     static void getMetrics(Rect metrics, int paddedMeasureWidth,
             int paddedMeasureHeight, int countX, int countY) {
         LauncherAppState app = LauncherAppState.getInstance();
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index 4c4f399..c630427 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -24,8 +24,8 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Vibrator;
 import android.util.Log;
+import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -51,7 +51,6 @@
 
     private static final int SCROLL_DELAY = 500;
     private static final int RESCROLL_DELAY = 750;
-    private static final int VIBRATE_DURATION = 15;
 
     private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
 
@@ -66,7 +65,6 @@
 
     private Launcher mLauncher;
     private Handler mHandler;
-    private final Vibrator mVibrator;
 
     // temporaries to avoid gc thrash
     private Rect mRectTemp = new Rect();
@@ -150,7 +148,6 @@
         mHandler = new Handler();
         mScrollZone = r.getDimensionPixelSize(R.dimen.scroll_zone);
         mVelocityTracker = VelocityTracker.obtain();
-        mVibrator = (Vibrator) launcher.getSystemService(Context.VIBRATOR_SERVICE);
 
         float density = r.getDisplayMetrics().density;
         mFlingToDeleteThresholdVelocity =
@@ -240,8 +237,6 @@
         mDragObject.dragSource = source;
         mDragObject.dragInfo = dragInfo;
 
-        mVibrator.vibrate(VIBRATE_DURATION);
-
         final DragView dragView = mDragObject.dragView = new DragView(mLauncher, b, registrationX,
                 registrationY, 0, 0, b.getWidth(), b.getHeight(), initialDragViewScale);
 
@@ -252,6 +247,7 @@
             dragView.setDragRegion(new Rect(dragRegion));
         }
 
+        mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
         dragView.show(mMotionDownX, mMotionDownY);
         handleMoveEvent(mMotionDownX, mMotionDownY);
     }
diff --git a/src/com/android/launcher3/DynamicGrid.java b/src/com/android/launcher3/DynamicGrid.java
index 495e930..0756c88 100644
--- a/src/com/android/launcher3/DynamicGrid.java
+++ b/src/com/android/launcher3/DynamicGrid.java
@@ -290,7 +290,8 @@
 
     Rect getWorkspacePadding(int orientation) {
         Rect padding = new Rect();
-        if (isVerticalBarLayout()) {
+        if (orientation == CellLayout.LANDSCAPE &&
+                transposeLayoutWithOrientation) {
             // Pad the left and right of the workspace with search/hotseat bar sizes
             padding.set(searchBarSpaceHeightPx, edgeMarginPx,
                     hotseatBarHeightPx, edgeMarginPx);
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index fd58008..b4d6ea5 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -102,6 +102,35 @@
         }
     }
 
+    public static void removeFromInstallQueue(SharedPreferences sharedPrefs,
+                                              ArrayList<String> packageNames) {
+        synchronized(sLock) {
+            Set<String> strings = sharedPrefs.getStringSet(APPS_PENDING_INSTALL, null);
+            if (strings != null) {
+                Set<String> newStrings = new HashSet<String>(strings);
+                for (String json : newStrings) {
+                    try {
+                        JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
+                        Intent launchIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
+                        String pn = launchIntent.getPackage();
+                        if (pn == null) {
+                            pn = launchIntent.getComponent().getPackageName();
+                        }
+                        if (packageNames.contains(pn)) {
+                            newStrings.remove(json);
+                        }
+                    } catch (org.json.JSONException e) {
+                        Log.d("InstallShortcutReceiver", "Exception reading shortcut to remove: " + e);
+                    } catch (java.net.URISyntaxException e) {
+                        Log.d("InstallShortcutReceiver", "Exception reading shortcut to remove: " + e);
+                    }
+                }
+                sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL,
+                        new HashSet<String>(newStrings)).commit();
+            }
+        }
+    }
+
     private static ArrayList<PendingInstallShortcutInfo> getAndClearInstallQueue(
             SharedPreferences sharedPrefs) {
         synchronized(sLock) {
@@ -115,7 +144,8 @@
                 try {
                     JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
                     Intent data = Intent.parseUri(object.getString(DATA_INTENT_KEY), 0);
-                    Intent launchIntent = Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
+                    Intent launchIntent =
+                            Intent.parseUri(object.getString(LAUNCH_INTENT_KEY), 0);
                     String name = object.getString(NAME_KEY);
                     String iconBase64 = object.optString(ICON_KEY);
                     String iconResourceName = object.optString(ICON_RESOURCE_NAME_KEY);
@@ -137,9 +167,11 @@
                         new PendingInstallShortcutInfo(data, name, launchIntent);
                     infos.add(info);
                 } catch (org.json.JSONException e) {
-                    Log.d("InstallShortcutReceiver", "Exception reading shortcut to add: " + e);
+                    Log.d("InstallShortcutReceiver",
+                            "Exception reading shortcut to add: " + e);
                 } catch (java.net.URISyntaxException e) {
-                    Log.d("InstallShortcutReceiver", "Exception reading shortcut to add: " + e);
+                    Log.d("InstallShortcutReceiver",
+                            "Exception reading shortcut to add: " + e);
                 }
             }
             sharedPrefs.edit().putStringSet(APPS_PENDING_INSTALL, new HashSet<String>()).commit();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5bb4f75..149a523 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -834,9 +834,6 @@
         // Background was set to gradient in onPause(), restore to black if in all apps.
         setWorkspaceBackground(mState == State.WORKSPACE);
 
-        // Process any items that were added while Launcher was away
-        InstallShortcutReceiver.disableAndFlushInstallQueue(this);
-
         mPaused = false;
         sPausedFromUserAction = false;
         if (mRestoring || mOnResumeNeedsLoad) {
@@ -885,12 +882,19 @@
             // Resets the previous all apps icon press state
             mAppsCustomizeContent.resetDrawableState();
         }
+        // Reset AllApps to its initial state
+        if (mAppsCustomizeTabHost != null) {
+            mAppsCustomizeTabHost.reset();
+        }
         // It is possible that widgets can receive updates while launcher is not in the foreground.
         // Consequently, the widgets will be inflated in the orientation of the foreground activity
         // (framework issue). On resuming, we ensure that any widgets are inflated for the current
         // orientation.
         getWorkspace().reinflateWidgetsIfNecessary();
 
+        // Process any items that were added while Launcher was away.
+        InstallShortcutReceiver.disableAndFlushInstallQueue(this);
+
         // Again, as with the above scenario, it's possible that one or more of the global icons
         // were updated in the wrong orientation.
         updateGlobalIcons();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index eead085..f8644b1 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -2477,7 +2477,7 @@
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
                         mBgAllAppsList.updatePackage(context, packages[i]);
-                        WidgetPreviewLoader.removeFromDb(
+                        WidgetPreviewLoader.removePackageFromDb(
                                 mApp.getWidgetPreviewCacheDb(), packages[i]);
                     }
                     break;
@@ -2486,7 +2486,7 @@
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
                         mBgAllAppsList.removePackage(packages[i]);
-                        WidgetPreviewLoader.removeFromDb(
+                        WidgetPreviewLoader.removePackageFromDb(
                                 mApp.getWidgetPreviewCacheDb(), packages[i]);
                     }
                     break;
@@ -2565,6 +2565,12 @@
                             deleteItemFromDatabase(context, i);
                         }
                     }
+
+                    // Remove any queued items from the install queue
+                    String spKey = LauncherAppState.getSharedPreferencesKey();
+                    SharedPreferences sp =
+                            context.getSharedPreferences(spKey, Context.MODE_PRIVATE);
+                    InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);
                 } else {
                     for (AppInfo a : removedApps) {
                         ArrayList<ItemInfo> infos =
@@ -3062,7 +3068,8 @@
         final Collator collator = Collator.getInstance();
         return new Comparator<AppInfo>() {
             public final int compare(AppInfo a, AppInfo b) {
-                int result = collator.compare(a.title.toString(), b.title.toString());
+                int result = collator.compare(a.title.toString().trim(),
+                        b.title.toString().trim());
                 if (result == 0) {
                     result = a.componentName.compareTo(b.componentName);
                 }
@@ -3082,7 +3089,7 @@
         final Collator collator = Collator.getInstance();
         return new Comparator<AppWidgetProviderInfo>() {
             public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {
-                return collator.compare(a.label.toString(), b.label.toString());
+                return collator.compare(a.label.toString().trim(), b.label.toString().trim());
             }
         };
     }
@@ -3114,14 +3121,14 @@
             if (mLabelCache.containsKey(keyA)) {
                 labelA = mLabelCache.get(keyA);
             } else {
-                labelA = a.loadLabel(mPackageManager).toString();
+                labelA = a.loadLabel(mPackageManager).toString().trim();
 
                 mLabelCache.put(keyA, labelA);
             }
             if (mLabelCache.containsKey(keyB)) {
                 labelB = mLabelCache.get(keyB);
             } else {
-                labelB = b.loadLabel(mPackageManager).toString();
+                labelB = b.loadLabel(mPackageManager).toString().trim();
 
                 mLabelCache.put(keyB, labelB);
             }
@@ -3144,7 +3151,7 @@
             } else {
                 labelA = (a instanceof AppWidgetProviderInfo) ?
                     ((AppWidgetProviderInfo) a).label :
-                    ((ResolveInfo) a).loadLabel(mPackageManager).toString();
+                    ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();
                 mLabelCache.put(a, labelA);
             }
             if (mLabelCache.containsKey(b)) {
@@ -3152,7 +3159,7 @@
             } else {
                 labelB = (b instanceof AppWidgetProviderInfo) ?
                     ((AppWidgetProviderInfo) b).label :
-                    ((ResolveInfo) b).loadLabel(mPackageManager).toString();
+                    ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();
                 mLabelCache.put(b, labelB);
             }
             return mCollator.compare(labelA, labelB);
diff --git a/src/com/android/launcher3/PackageChangedReceiver.java b/src/com/android/launcher3/PackageChangedReceiver.java
index 75a1e09..e59f6d8 100644
--- a/src/com/android/launcher3/PackageChangedReceiver.java
+++ b/src/com/android/launcher3/PackageChangedReceiver.java
@@ -16,6 +16,6 @@
         // in rare cases the receiver races with the application to set up LauncherAppState
         LauncherAppState.setApplicationContext(context.getApplicationContext());
         LauncherAppState app = LauncherAppState.getInstance();
-        WidgetPreviewLoader.removeFromDb(app.getWidgetPreviewCacheDb(), packageName);
+        WidgetPreviewLoader.removePackageFromDb(app.getWidgetPreviewCacheDb(), packageName);
     }
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 42f3cac..8cdd8e2 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -925,6 +925,12 @@
             mFirstLayout = false;
         }
 
+        if (isPageMoving()) {
+            // If the page is moving, then snap it to the final position to ensure we don't get
+            // stuck between pages
+            snapToDestination();
+        }
+
         if (childCount > 0) {
             final int index = isLayoutRtl() ? 0 : childCount - 1;
             mMaxScrollX = getScrollForPage(index);
diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java
index 11c12f8..1910ab7 100644
--- a/src/com/android/launcher3/WidgetPreviewLoader.java
+++ b/src/com/android/launcher3/WidgetPreviewLoader.java
@@ -159,11 +159,12 @@
     }
 
     public Bitmap getPreview(final Object o) {
-        String name = getObjectName(o);
+        final String name = getObjectName(o);
+        final String packageName = getObjectPackage(o);
         // check if the package is valid
         boolean packageValid = true;
         synchronized(sInvalidPackages) {
-            packageValid = !sInvalidPackages.contains(getObjectPackage(o));
+            packageValid = !sInvalidPackages.contains(packageName);
         }
         if (!packageValid) {
             return null;
@@ -334,7 +335,7 @@
         db.insert(CacheDb.TABLE_NAME, null, values);
     }
 
-    public static void removeFromDb(final CacheDb cacheDb, final String packageName) {
+    public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) {
         synchronized(sInvalidPackages) {
             sInvalidPackages.add(packageName);
         }
@@ -356,6 +357,18 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
     }
 
+    public static void removeItemFromDb(final CacheDb cacheDb, final String objectName) {
+        new AsyncTask<Void, Void, Void>() {
+            public Void doInBackground(Void ... args) {
+                SQLiteDatabase db = cacheDb.getWritableDatabase();
+                db.delete(CacheDb.TABLE_NAME,
+                        CacheDb.COLUMN_NAME + " = ? ", // SELECT query
+                        new String[] { objectName }); // args to SELECT query
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+    }
+
     private Bitmap readFromDb(String name, Bitmap b) {
         if (mCachedSelectQuery == null) {
             mCachedSelectQuery = CacheDb.COLUMN_NAME + " = ? AND " +
@@ -377,8 +390,12 @@
             final BitmapFactory.Options opts = mCachedBitmapFactoryOptions.get();
             opts.inBitmap = b;
             opts.inSampleSize = 1;
-            Bitmap out = BitmapFactory.decodeByteArray(blob, 0, blob.length, opts);
-            return out;
+            try {
+                return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts);
+            } catch (IllegalArgumentException e) {
+                removeItemFromDb(mDb, name);
+                return null;
+            }
         } else {
             result.close();
             return null;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 1425f7f..0eca3af 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2747,6 +2747,8 @@
         }
     }
 
+    /** Return a rect that has the cellWidth/cellHeight (left, top), and
+     * widthGap/heightGap (right, bottom) */
     static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {
         LauncherAppState app = LauncherAppState.getInstance();
         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -2758,24 +2760,28 @@
         display.getCurrentSizeRange(smallestSize, largestSize);
         int countX = (int) grid.numColumns;
         int countY = (int) grid.numRows;
+        int constrainedLongEdge = largestSize.y;
+        int constrainedShortEdge = smallestSize.y;
         if (orientation == CellLayout.LANDSCAPE) {
             if (mLandscapeCellLayoutMetrics == null) {
                 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);
-                int width = largestSize.x - padding.left - padding.right;
-                int height = smallestSize.y - padding.top - padding.bottom;
+                int width = constrainedLongEdge - padding.left - padding.right;
+                int height = constrainedShortEdge - padding.top - padding.bottom;
                 mLandscapeCellLayoutMetrics = new Rect();
-                CellLayout.getMetrics(mLandscapeCellLayoutMetrics, width, height,
-                        countX, countY);
+                mLandscapeCellLayoutMetrics.set(
+                        grid.calculateCellWidth(width, countX),
+                        grid.calculateCellHeight(height, countY), 0, 0);
             }
             return mLandscapeCellLayoutMetrics;
         } else if (orientation == CellLayout.PORTRAIT) {
             if (mPortraitCellLayoutMetrics == null) {
                 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);
-                int width = smallestSize.x - padding.left - padding.right;
-                int height = largestSize.y - padding.top - padding.bottom;
+                int width = constrainedShortEdge - padding.left - padding.right;
+                int height = constrainedLongEdge - padding.top - padding.bottom;
                 mPortraitCellLayoutMetrics = new Rect();
-                CellLayout.getMetrics(mPortraitCellLayoutMetrics, width, height,
-                        countX, countY);
+                mPortraitCellLayoutMetrics.set(
+                        grid.calculateCellWidth(width, countX),
+                        grid.calculateCellHeight(height, countY), 0, 0);
             }
             return mPortraitCellLayoutMetrics;
         }