Ensuring that the db reflects all package added/removed/updated broadcasts.

- Also ensuring that newly added pages are added before the empty page

Change-Id: I97a01f791c438aa5c5b1fd770d3536b449a871bc
diff --git a/res/values/config.xml b/res/values/config.xml
index e65818f..6aaca1a 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -33,10 +33,6 @@
          AppsCustomize (y / x * 100%)  -->
     <integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
 
-    <!-- Batch loading for loading in LauncherModel -->
-    <integer name="config_allAppsBatchLoadDelay">0</integer>
-    <integer name="config_allAppsBatchSize">0</integer>
-
 <!-- Workspace -->
     <!-- Whether or not the drop targets drop down as opposed to fade in -->
     <bool name="config_useDropTargetDownTransition">true</bool>
diff --git a/src/com/android/launcher3/ApplicationInfo.java b/src/com/android/launcher3/ApplicationInfo.java
index 4659e7e..53801d6 100644
--- a/src/com/android/launcher3/ApplicationInfo.java
+++ b/src/com/android/launcher3/ApplicationInfo.java
@@ -114,7 +114,10 @@
 
     @Override
     public String toString() {
-        return "ApplicationInfo(title=" + title.toString() + ")";
+        return "ApplicationInfo(title=" + title.toString() + " id=" + this.id
+                + " type=" + this.itemType + " container=" + this.container
+                + " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY
+                + " spanX=" + spanX + " spanY=" + spanY + " dropPos=" + dropPos + ")";
     }
 
     public static void dumpApplicationInfoList(String tag, String label,
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index aa2d531..dafa9b4 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -1592,8 +1592,10 @@
         }
     }
     public void removeApps(ArrayList<ApplicationInfo> appInfos) {
-        removeAppsWithoutInvalidate(appInfos);
-        updatePageCountsAndInvalidateData();
+        if (!DISABLE_ALL_APPS) {
+            removeAppsWithoutInvalidate(appInfos);
+            updatePageCountsAndInvalidateData();
+        }
     }
     public void updateApps(ArrayList<ApplicationInfo> list) {
         // We remove and re-add the updated applications list because it's properties may have
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 6d45e59..bb5ae82 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -108,4 +108,12 @@
         public void onTitleChanged(CharSequence title);
         public void onItemsChanged();
     }
+
+    @Override
+    public String toString() {
+        return "FolderInfo(id=" + this.id + " type=" + this.itemType
+                + " container=" + this.container + " screen=" + screenId
+                + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
+                + " spanY=" + spanY + " dropPos=" + dropPos + ")";
+    }
 }
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 93f39ff..054ef2f 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -136,7 +137,7 @@
         for (ApplicationInfo info: allApps) {
             ComponentName cn = info.intent.getComponent();
             if (!onWorkspace.contains(cn)) {
-                System.out.println("Adding to all apps: " + info.intent);
+                Log.d(TAG, "Adding to all apps: " + info.intent);
                 ShortcutInfo si = info.makeShortcut();
                 fi.add(si);
             }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b8fce6d..95aefe6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -193,6 +193,7 @@
 
     // How long to wait before the new-shortcut animation automatically pans the workspace
     private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 10;
+    private static int NEW_APPS_ANIMATION_DELAY = 500;
 
     private final BroadcastReceiver mCloseSystemDialogsReceiver
             = new CloseSystemDialogsIntentReceiver();
@@ -407,11 +408,6 @@
             }
         }
 
-        if (!mModel.isAllAppsLoaded()) {
-            ViewGroup appsCustomizeContentParent = (ViewGroup) mAppsCustomizeContent.getParent();
-            mInflater.inflate(R.layout.apps_customize_progressbar, appsCustomizeContentParent);
-        }
-
         // For handling default keys
         mDefaultKeySsb = new SpannableStringBuilder();
         Selection.setSelection(mDefaultKeySsb, 0);
@@ -2479,17 +2475,10 @@
         return mWorkspace;
     }
 
-    // Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
-    @Override
     public boolean isAllAppsVisible() {
         return (mState == State.APPS_CUSTOMIZE) || (mOnResumeState == State.APPS_CUSTOMIZE);
     }
 
-    @Override
-    public boolean isAllAppsButtonRank(int rank) {
-        return mHotseat.isAllAppsButtonRank(rank);
-    }
-
     /**
      * Helper method for the cameraZoomIn/cameraZoomOut animations
      * @param view The view being animated
@@ -3453,11 +3442,16 @@
 
     @Override
     public void bindScreens(ArrayList<Long> orderedScreenIds) {
+        bindAddScreens(orderedScreenIds);
+        mWorkspace.addExtraEmptyScreen();
+    }
+
+    @Override
+    public void bindAddScreens(ArrayList<Long> orderedScreenIds) {
         int count = orderedScreenIds.size();
         for (int i = 0; i < count; i++) {
-            mWorkspace.insertNewWorkspaceScreenOnBind(orderedScreenIds.get(i));
+            mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(orderedScreenIds.get(i), false);
         }
-        mWorkspace.addExtraEmptyScreen();
     }
 
     /**
@@ -3465,10 +3459,11 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void bindItems(final ArrayList<ItemInfo> shortcuts, final int start, final int end) {
+    public void bindItems(final ArrayList<ItemInfo> shortcuts, final int start, final int end,
+                          final boolean forceAnimateIcons) {
         if (waitUntilResume(new Runnable() {
                 public void run() {
-                    bindItems(shortcuts, start, end);
+                    bindItems(shortcuts, start, end, forceAnimateIcons);
                 }
             })) {
             return;
@@ -3478,6 +3473,8 @@
         Set<String> newApps = new HashSet<String>();
         newApps = mSharedPrefs.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY, newApps);
 
+        final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+        final Collection<Animator> bounceAnims = new ArrayList<Animator>();
         Workspace workspace = mWorkspace;
         for (int i = start; i < end; i++) {
             final ItemInfo item = shortcuts.get(i);
@@ -3495,6 +3492,14 @@
                     String uri = info.intent.toUri(0).toString();
                     View shortcut = createShortcut(info);
 
+                    /*
+                     * TODO: FIX collision case
+                     */
+                    CellLayout cl = mWorkspace.getScreenWithId(item.screenId);
+                    if (cl != null && cl.isOccupied(item.cellX, item.cellY)) {
+                        throw new RuntimeException("OCCUPIED");
+                    }
+
                     workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX,
                             item.cellY, 1, 1);
                     boolean animateIconUp = false;
@@ -3503,7 +3508,13 @@
                             animateIconUp = newApps.remove(uri);
                         }
                     }
-                    if (animateIconUp) {
+                    if (forceAnimateIcons) {
+                        // Animate all the applications up now
+                        shortcut.setAlpha(0f);
+                        shortcut.setScaleX(0f);
+                        shortcut.setScaleY(0f);
+                        bounceAnims.add(createNewAppBounceAnimation(shortcut, i));
+                    } else if (animateIconUp) {
                         // Prepare the view to be animated up
                         shortcut.setAlpha(0f);
                         shortcut.setScaleX(0f);
@@ -3524,6 +3535,16 @@
             }
         }
 
+        if (forceAnimateIcons) {
+            // We post the animation slightly delayed to prevent slowdowns when we are loading
+            // right after we return to launcher.
+            mWorkspace.postDelayed(new Runnable() {
+                public void run() {
+                    anim.playTogether(bounceAnims);
+                    anim.start();
+                }
+            }, NEW_APPS_ANIMATION_DELAY);
+        }
         workspace.requestLayout();
     }
 
@@ -3595,7 +3616,6 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void finishBindingItems(final boolean upgradePath) {
-
         if (waitUntilResume(new Runnable() {
                 public void run() {
                     finishBindingItems(upgradePath);
@@ -3753,119 +3773,10 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void bindAllApplications(final ArrayList<ApplicationInfo> apps) {
-        Runnable setAllAppsRunnable = new Runnable() {
-            public void run() {
-                if (mAppsCustomizeContent != null) {
-                    mAppsCustomizeContent.setApps(apps);
-
-                    if (mIntentsOnWorkspaceFromUpgradePath != null) {
-                        getHotseat().addAllAppsFolder(mIconCache, apps,
-                                mIntentsOnWorkspaceFromUpgradePath, Launcher.this);
-                        mIntentsOnWorkspaceFromUpgradePath = null;
-                    }
-                }
-            }
-        };
-
-        // Remove the progress bar entirely; we could also make it GONE
-        // but better to remove it since we know it's not going to be used
-        View progressBar = mAppsCustomizeTabHost.
-            findViewById(R.id.apps_customize_progress_bar);
-        if (progressBar != null) {
-            ((ViewGroup)progressBar.getParent()).removeView(progressBar);
-
-            // We just post the call to setApps so the user sees the progress bar
-            // disappear-- otherwise, it just looks like the progress bar froze
-            // which doesn't look great
-            mAppsCustomizeTabHost.post(setAllAppsRunnable);
-        } else {
-            // If we did not initialize the spinner in onCreate, then we can directly set the
-            // list of applications without waiting for any progress bars views to be hidden.
-            setAllAppsRunnable.run();
-        }
-    }
-
-    /**
-     * A package was installed.
-     *
-     * Implementation of the method from LauncherModel.Callbacks.
-     */
-    public void bindAppsAdded(final ArrayList<ApplicationInfo> apps) {
-        if (waitUntilResume(new Runnable() {
-                public void run() {
-                    bindAppsAdded(apps);
-                }
-            })) {
-            return;
-        }
-
-        final Launcher launcher = this;
-        final Context context = this;
-        final ArrayList<ApplicationInfo> appsCopy = new ArrayList<ApplicationInfo>();
-        appsCopy.addAll(apps);
-
-        // Process newly added apps
-        mWorkspace.post(new Runnable() {
-            @Override
-            public void run() {
-                // Process newly added apps
-                LauncherModel model = getModel();
-                Iterator<ApplicationInfo> iter = appsCopy.iterator();
-                ArrayList<View> animatedShortcuts = new ArrayList<View>();
-
-                while (iter.hasNext()) {
-                    ApplicationInfo a = iter.next();
-                    Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,
-                            a.title.toString(), a.intent);
-                    if (coords == null) {
-                        // If we can't find a valid position, then just add a new screen.
-                        // This takes time so we need to re-queue the add until the new
-                        // page is added.
-                        long screenId = LauncherAppState.getInstance().getLauncherProvider()
-                                .generateNewScreenId();
-                        mWorkspace.insertNewWorkspaceScreen(screenId, false);
-                        model.updateWorkspaceScreenOrder(launcher, mWorkspace.getScreenOrder(),
-                            new Runnable() {
-                                @Override
-                                public void run() {
-                                    bindAppsAdded(appsCopy);
-                                }
-                            });
-                        return;
-                    } else {
-                        final ShortcutInfo shortcutInfo = a.makeShortcut();
-                        final View shortcut = createShortcut(shortcutInfo);
-                        // Add the view to the screen
-                        mWorkspace.addInScreenFromBind(shortcut,
-                                LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                                coords.first, coords.second[0], coords.second[1], 1, 1);
-                        // Add the shortcut to the db
-                        model.addItemToDatabase(context, shortcutInfo,
-                                LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                                coords.first, coords.second[0], coords.second[1], false);
-                        // Animate the shortcut
-                        animatedShortcuts.add(shortcut);
-                    }
-                    iter.remove();
-                }
-
-                // Animate all the applications up
-                AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
-                Collection<Animator> bounceAnims = new ArrayList<Animator>();
-                for (int i = 0; i < animatedShortcuts.size(); ++i) {
-                    View shortcut = animatedShortcuts.get(i);
-                    shortcut.setAlpha(0f);
-                    shortcut.setScaleX(0f);
-                    shortcut.setScaleY(0f);
-                    bounceAnims.add(createNewAppBounceAnimation(shortcut, i));
-                }
-                anim.playTogether(bounceAnims);
-                anim.start();
-            }
-        });
-
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.addApps(apps);
+        if (mIntentsOnWorkspaceFromUpgradePath != null) {
+            getHotseat().addAllAppsFolder(mIconCache, apps,
+                    mIntentsOnWorkspaceFromUpgradePath, Launcher.this);
+            mIntentsOnWorkspaceFromUpgradePath = null;
         }
     }
 
@@ -3886,10 +3797,6 @@
         if (mWorkspace != null) {
             mWorkspace.updateShortcuts(apps);
         }
-
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.updateApps(apps);
-        }
     }
 
     /**
@@ -3903,25 +3810,21 @@
      */
     public void bindComponentsRemoved(final ArrayList<String> packageNames,
                                       final ArrayList<ApplicationInfo> appInfos,
-                                      final boolean matchPackageNamesOnly) {
+                                      final boolean packageRemoved) {
         if (waitUntilResume(new Runnable() {
             public void run() {
-                bindComponentsRemoved(packageNames, appInfos, matchPackageNamesOnly);
+                bindComponentsRemoved(packageNames, appInfos, packageRemoved);
             }
         })) {
             return;
         }
 
-        if (matchPackageNamesOnly) {
+        if (packageRemoved) {
             mWorkspace.removeItemsByPackageName(packageNames);
         } else {
             mWorkspace.removeItemsByApplicationInfo(appInfos);
         }
 
-        if (mAppsCustomizeContent != null) {
-            mAppsCustomizeContent.removeApps(appInfos);
-        }
-
         // Notify the drag controller
         mDragController.onAppsRemoved(appInfos, this);
     }
@@ -3929,7 +3832,6 @@
     /**
      * A number of packages were updated.
      */
-
     private ArrayList<Object> mWidgetsAndShortcuts;
     private Runnable mBindPackagesUpdatedRunnable = new Runnable() {
             public void run() {
@@ -3944,6 +3846,7 @@
             return;
         }
 
+        // Update the widgets pane
         if (mAppsCustomizeContent != null) {
             mAppsCustomizeContent.onPackagesUpdated(widgetsAndShortcuts);
         }
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d098805..0b69a09 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -48,6 +48,7 @@
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -68,8 +69,6 @@
 
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
     private final boolean mAppsCanBeOnExternalStorage;
-    private int mBatchSize; // 0 is all apps at once
-    private int mAllAppsLoadDelay; // milliseconds between batches
 
     private final LauncherAppState mApp;
     private final Object mLock = new Object();
@@ -149,24 +148,27 @@
         public boolean setLoadOnResume();
         public int getCurrentWorkspaceScreen();
         public void startBinding();
-        public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);
+        public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,
+                              boolean forceAnimateIcons);
         public void bindScreens(ArrayList<Long> orderedScreenIds);
+        public void bindAddScreens(ArrayList<Long> orderedScreenIds);
         public void bindFolders(HashMap<Long,FolderInfo> folders);
         public void finishBindingItems(boolean upgradePath);
         public void bindAppWidget(LauncherAppWidgetInfo info);
         public void bindAllApplications(ArrayList<ApplicationInfo> apps);
-        public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
         public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
         public void bindComponentsRemoved(ArrayList<String> packageNames,
                         ArrayList<ApplicationInfo> appInfos,
                         boolean matchPackageNamesOnly);
         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);
-        public boolean isAllAppsVisible();
-        public boolean isAllAppsButtonRank(int rank);
         public void bindSearchablesChanged();
         public void onPageBoundSynchronously(int page);
     }
 
+    public interface ItemInfoFilter {
+        public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);
+    }
+
     LauncherModel(LauncherAppState app, IconCache iconCache) {
         final Context context = app.getContext();
 
@@ -179,8 +181,6 @@
                 mIconCache.getFullResDefaultActivityIcon(), context);
 
         final Resources res = context.getResources();
-        mAllAppsLoadDelay = res.getInteger(R.integer.config_allAppsBatchLoadDelay);
-        mBatchSize = res.getInteger(R.integer.config_allAppsBatchSize);
         Configuration config = res.getConfiguration();
         mPreviousConfigMcc = config.mcc;
     }
@@ -243,12 +243,13 @@
         LauncherModel model = app.getModel();
         boolean found = false;
         synchronized (app) {
-            // Flush the LauncherModel worker thread, so that if we just did another
-            // processInstallShortcut, we give it time for its shortcut to get added to the
-            // database (getItemsInLocalCoordinates reads the database)
-            model.flushWorkerThread();
+            if (sWorkerThread.getThreadId() != Process.myTid()) {
+                // Flush the LauncherModel worker thread, so that if we just did another
+                // processInstallShortcut, we give it time for its shortcut to get added to the
+                // database (getItemsInLocalCoordinates reads the database)
+                model.flushWorkerThread();
+            }
             final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);
-            final boolean shortcutExists = LauncherModel.shortcutExists(context, name, launchIntent);
 
             // Try adding to the workspace screens incrementally, starting at the default or center
             // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))
@@ -265,6 +266,74 @@
         return null;
     }
 
+    public void addAndBindAddedApps(final Context context, final ArrayList<ApplicationInfo> added,
+                                    final Callbacks callbacks) {
+        // Process the newly added applications and add them to the database first
+        Runnable r = new Runnable() {
+            public void run() {
+                final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();
+                final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();
+
+                synchronized(sBgLock) {
+                    Iterator<ApplicationInfo> iter = added.iterator();
+                    while (iter.hasNext()) {
+                        ApplicationInfo a = iter.next();
+                        final String name = a.title.toString();
+                        final Intent launchIntent = a.intent;
+
+                        // Short-circuit this logic if the icon exists somewhere on the workspace
+                        if (LauncherModel.shortcutExists(context, name, launchIntent)) {
+                            continue;
+                        }
+
+                        // Add this icon to the db, creating a new page if necessary
+                        Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,
+                                name, launchIntent);
+                        if (coords == null) {
+                            // If we can't find a valid position, then just add a new screen.
+                            // This takes time so we need to re-queue the add until the new
+                            // page is added.
+                            LauncherAppState appState = LauncherAppState.getInstance();
+                            LauncherProvider lp = appState.getLauncherProvider();
+                            long screenId = lp.generateNewScreenId();
+                            // Update the model
+                            sBgWorkspaceScreens.add(screenId);
+                            updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);
+                            // Save the screen id for binding in the workspace
+                            addedWorkspaceScreensFinal.add(screenId);
+                            // Find the coordinate again
+                            coords = LauncherModel.findNextAvailableIconSpace(context,
+                                    a.title.toString(), a.intent);
+                        }
+                        if (coords == null) {
+                            throw new RuntimeException("Coordinates should not be null");
+                        }
+
+                        final ShortcutInfo shortcutInfo = a.makeShortcut();
+                        // Add the shortcut to the db
+                        addItemToDatabase(context, shortcutInfo,
+                                LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                coords.first, coords.second[0], coords.second[1], false);
+                        // Save the ShortcutInfo for binding in the workspace
+                        addedShortcutsFinal.add(shortcutInfo);
+                    }
+                }
+
+                runOnMainThread(new Runnable() {
+                    public void run() {
+                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                        if (callbacks == cb && cb != null) {
+                            callbacks.bindAddScreens(addedWorkspaceScreensFinal);
+                            callbacks.bindItems(addedShortcutsFinal, 0,
+                                    addedShortcutsFinal.size(), true);
+                        }
+                    }
+                });
+            }
+        };
+        runOnWorkerThread(r);
+    }
+
     public Bitmap getFallbackIcon() {
         return Bitmap.createBitmap(mDefaultIcon);
     }
@@ -868,14 +937,12 @@
      * a list of screen ids in the order that they should appear.
      */
     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {
-        updateWorkspaceScreenOrder(context, screens, null);
-    }
-    void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens, final Runnable mainThreadCb) {
+        final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);
         final ContentResolver cr = context.getContentResolver();
         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;
 
         // Remove any negative screen ids -- these aren't persisted
-        Iterator<Long> iter = screens.iterator();
+        Iterator<Long> iter = screensCopy.iterator();
         while (iter.hasNext()) {
             long id = iter.next();
             if (id < 0) {
@@ -886,8 +953,6 @@
         Runnable r = new Runnable() {
             @Override
             public void run() {
-                final ArrayList<Long> screensCopy = new ArrayList<Long>();
-
                 // Clear the table
                 cr.delete(uri, null, null);
                 int count = screens.size();
@@ -897,7 +962,6 @@
                     long screenId = screens.get(i);
                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
-                    screensCopy.add(screenId);
                     values[i] = v;
                 }
                 cr.bulkInsert(uri, values);
@@ -906,14 +970,6 @@
             }
         };
         runOnWorkerThread(r);
-        if (mainThreadCb != null) {
-            runOnWorkerThread(new Runnable() {
-                @Override
-                public void run() {
-                    runOnMainThread(mainThreadCb);
-                }
-            });
-        }
     }
 
     /**
@@ -1279,8 +1335,6 @@
             // All Apps interface in the foreground, load All Apps first. Otherwise, load the
             // workspace first (default).
             final Callbacks cbk = mCallbacks.get();
-            final boolean loadWorkspaceFirst = cbk != null ? (!cbk.isAllAppsVisible()) : true;
-
             keep_running: {
                 // Elevate priority when Home launches for the first time to avoid
                 // starving at boot time. Staring at a blank home is not cool.
@@ -1290,13 +1344,8 @@
                     android.os.Process.setThreadPriority(mIsLaunching
                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);
                 }
-                if (loadWorkspaceFirst) {
-                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
-                    loadAndBindWorkspace();
-                } else {
-                    if (DEBUG_LOADERS) Log.d(TAG, "step 1: special: loading all apps");
-                    loadAndBindAllApps();
-                }
+                if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");
+                loadAndBindWorkspace();
 
                 if (mStopped) {
                     break keep_running;
@@ -1313,13 +1362,8 @@
                 waitForIdle();
 
                 // second step
-                if (loadWorkspaceFirst) {
-                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
-                    loadAndBindAllApps();
-                } else {
-                    if (DEBUG_LOADERS) Log.d(TAG, "step 2: special: loading workspace");
-                    loadAndBindWorkspace();
-                }
+                if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");
+                loadAndBindAllApps();
 
                 // Restore the default thread priority after we are done loading items
                 synchronized (mLock) {
@@ -1952,7 +1996,8 @@
                     public void run() {
                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                         if (callbacks != null) {
-                            callbacks.bindItems(workspaceItems, start, start+chunkSize);
+                            callbacks.bindItems(workspaceItems, start, start+chunkSize,
+                                    false);
                         }
                     }
                 };
@@ -2119,7 +2164,7 @@
                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);
             }
             if (!mAllAppsLoaded) {
-                loadAllAppsByBatch();
+                loadAllApps();
                 synchronized (LoaderTask.this) {
                     if (mStopped) {
                         return;
@@ -2157,124 +2202,84 @@
                 }
             };
             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());
-            if (oldCallbacks.isAllAppsVisible() && isRunningOnMainThread) {
+            if (isRunningOnMainThread) {
                 r.run();
             } else {
                 mHandler.post(r);
             }
         }
 
-        private void loadAllAppsByBatch() {
-            final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+        private void loadAllApps() {
+            final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
 
             // Don't use these two variables in any of the callback runnables.
             // Otherwise we hold a reference to them.
             final Callbacks oldCallbacks = mCallbacks.get();
             if (oldCallbacks == null) {
                 // This launcher has exited and nobody bothered to tell us.  Just bail.
-                Log.w(TAG, "LoaderTask running with no launcher (loadAllAppsByBatch)");
+                Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");
                 return;
             }
 
+            final PackageManager packageManager = mContext.getPackageManager();
             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
 
-            final PackageManager packageManager = mContext.getPackageManager();
-            List<ResolveInfo> apps = null;
+            // Clear the list of apps
+            mBgAllAppsList.clear();
 
-            int N = Integer.MAX_VALUE;
-
-            int startIndex;
-            int i=0;
-            int batchSize = -1;
-            while (i < N && !mStopped) {
-                if (i == 0) {
-                    mBgAllAppsList.clear();
-                    final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-                    apps = packageManager.queryIntentActivities(mainIntent, 0);
-                    if (DEBUG_LOADERS) {
-                        Log.d(TAG, "queryIntentActivities took "
-                                + (SystemClock.uptimeMillis()-qiaTime) + "ms");
-                    }
-                    if (apps == null) {
-                        return;
-                    }
-                    N = apps.size();
-                    if (DEBUG_LOADERS) {
-                        Log.d(TAG, "queryIntentActivities got " + N + " apps");
-                    }
-                    if (N == 0) {
-                        // There are no apps?!?
-                        return;
-                    }
-                    if (mBatchSize == 0) {
-                        batchSize = N;
-                    } else {
-                        batchSize = mBatchSize;
-                    }
-
-                    final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-                    Collections.sort(apps,
-                            new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
-                    if (DEBUG_LOADERS) {
-                        Log.d(TAG, "sort took "
-                                + (SystemClock.uptimeMillis()-sortTime) + "ms");
-                    }
-                }
-
-                final long t2 = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
-
-                startIndex = i;
-                for (int j=0; i<N && j<batchSize; j++) {
-                    // This builds the icon bitmaps.
-                    mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
-                            mIconCache, mLabelCache));
-                    i++;
-                }
-
-                final boolean first = i <= batchSize;
-                final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
-                final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;
-                mBgAllAppsList.added = new ArrayList<ApplicationInfo>();
-
-                mHandler.post(new Runnable() {
-                    public void run() {
-                        final long t = SystemClock.uptimeMillis();
-                        if (callbacks != null) {
-                            if (first) {
-                                callbacks.bindAllApplications(added);
-                            } else {
-                                callbacks.bindAppsAdded(added);
-                            }
-                            if (DEBUG_LOADERS) {
-                                Log.d(TAG, "bound " + added.size() + " apps in "
-                                    + (SystemClock.uptimeMillis() - t) + "ms");
-                            }
-                        } else {
-                            Log.i(TAG, "not binding apps: no Launcher activity");
-                        }
-                    }
-                });
-
-                if (DEBUG_LOADERS) {
-                    Log.d(TAG, "batch of " + (i-startIndex) + " icons processed in "
-                            + (SystemClock.uptimeMillis()-t2) + "ms");
-                }
-
-                if (mAllAppsLoadDelay > 0 && i < N) {
-                    try {
-                        if (DEBUG_LOADERS) {
-                            Log.d(TAG, "sleeping for " + mAllAppsLoadDelay + "ms");
-                        }
-                        Thread.sleep(mAllAppsLoadDelay);
-                    } catch (InterruptedException exc) { }
-                }
+            // Query for the set of apps
+            final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+            List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
+            if (DEBUG_LOADERS) {
+                Log.d(TAG, "queryIntentActivities took "
+                        + (SystemClock.uptimeMillis()-qiaTime) + "ms");
+                Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");
+            }
+            // Fail if we don't have any apps
+            if (apps == null || apps.isEmpty()) {
+                return;
+            }
+            // Sort the applications by name
+            final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+            Collections.sort(apps,
+                    new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));
+            if (DEBUG_LOADERS) {
+                Log.d(TAG, "sort took "
+                        + (SystemClock.uptimeMillis()-sortTime) + "ms");
             }
 
+            // Create the ApplicationInfos
+            final long addTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
+            for (int i = 0; i < apps.size(); i++) {
+                // This builds the icon bitmaps.
+                mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
+                        mIconCache, mLabelCache));
+            }
+
+            final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
+            final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;
+            mBgAllAppsList.added = new ArrayList<ApplicationInfo>();
+
+            // Post callback on main thread
+            mHandler.post(new Runnable() {
+                public void run() {
+                    final long bindTime = SystemClock.uptimeMillis();
+                    if (callbacks != null) {
+                        callbacks.bindAllApplications(added);
+                        if (DEBUG_LOADERS) {
+                            Log.d(TAG, "bound " + added.size() + " apps in "
+                                + (SystemClock.uptimeMillis() - bindTime) + "ms");
+                        }
+                    } else {
+                        Log.i(TAG, "not binding apps: no Launcher activity");
+                    }
+                }
+            });
+
             if (DEBUG_LOADERS) {
-                Log.d(TAG, "cached all " + N + " apps in "
-                        + (SystemClock.uptimeMillis()-t) + "ms"
-                        + (mAllAppsLoadDelay > 0 ? " (including delay)" : ""));
+                Log.d(TAG, "Icons processed in "
+                        + (SystemClock.uptimeMillis() - loadTime) + "ms");
             }
         }
 
@@ -2364,18 +2369,26 @@
             }
 
             if (added != null) {
-                final ArrayList<ApplicationInfo> addedFinal = added;
-                mHandler.post(new Runnable() {
-                    public void run() {
-                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
-                        if (callbacks == cb && cb != null) {
-                            callbacks.bindAppsAdded(addedFinal);
-                        }
-                    }
-                });
+                // Ensure that we add all the workspace applications to the db
+                Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
+                addAndBindAddedApps(context, added, cb);
             }
             if (modified != null) {
                 final ArrayList<ApplicationInfo> modifiedFinal = modified;
+
+                // Update the launcher db to reflect the changes
+                for (ApplicationInfo a : modifiedFinal) {
+                    ArrayList<ItemInfo> infos =
+                            getItemInfoForComponentName(a.componentName);
+                    for (ItemInfo i : infos) {
+                        if (isShortcutInfoUpdateable(i)) {
+                            ShortcutInfo info = (ShortcutInfo) i;
+                            info.title = a.title.toString();
+                            updateItemInDatabase(context, info);
+                        }
+                    }
+                }
+
                 mHandler.post(new Runnable() {
                     public void run() {
                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
@@ -2388,16 +2401,34 @@
             // If a package has been removed, or an app has been removed as a result of
             // an update (for example), make the removed callback.
             if (mOp == OP_REMOVE || !removedApps.isEmpty()) {
-                final boolean permanent = (mOp == OP_REMOVE);
+                final boolean packageRemoved = (mOp == OP_REMOVE);
                 final ArrayList<String> removedPackageNames =
                         new ArrayList<String>(Arrays.asList(packages));
 
+                // Update the launcher db to reflect the removal of apps
+                if (packageRemoved) {
+                    for (String pn : removedPackageNames) {
+                        ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);
+                        for (ItemInfo i : infos) {
+                            deleteItemFromDatabase(context, i);
+                        }
+                    }
+                } else {
+                    for (ApplicationInfo a : removedApps) {
+                        ArrayList<ItemInfo> infos =
+                                getItemInfoForComponentName(a.componentName);
+                        for (ItemInfo i : infos) {
+                            deleteItemFromDatabase(context, i);
+                        }
+                    }
+                }
+
                 mHandler.post(new Runnable() {
                     public void run() {
                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
                         if (callbacks == cb && cb != null) {
                             callbacks.bindComponentsRemoved(removedPackageNames,
-                                    removedApps, permanent);
+                                    removedApps, packageRemoved);
                         }
                     }
                 });
@@ -2532,22 +2563,71 @@
         return info;
     }
 
-    /**
-     * Returns the set of workspace ShortcutInfos with the specified intent.
-     */
-    static ArrayList<ItemInfo> getWorkspaceShortcutItemInfosWithIntent(Intent intent) {
-        ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
-        synchronized (sBgLock) {
-            for (ItemInfo info : sBgWorkspaceItems) {
-                if (info instanceof ShortcutInfo) {
-                    ShortcutInfo shortcut = (ShortcutInfo) info;
-                    if (shortcut.intent.toUri(0).equals(intent.toUri(0))) {
-                        items.add(shortcut);
+    static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,
+            ItemInfoFilter f) {
+        HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
+        for (ItemInfo i : infos) {
+            if (i instanceof ShortcutInfo) {
+                ShortcutInfo info = (ShortcutInfo) i;
+                ComponentName cn = info.intent.getComponent();
+                if (cn != null && f.filterItem(null, info, cn)) {
+                    filtered.add(info);
+                }
+            } else if (i instanceof FolderInfo) {
+                FolderInfo info = (FolderInfo) i;
+                for (ShortcutInfo s : info.contents) {
+                    ComponentName cn = s.intent.getComponent();
+                    if (cn != null && f.filterItem(info, s, cn)) {
+                        filtered.add(s);
                     }
                 }
+            } else if (i instanceof LauncherAppWidgetInfo) {
+                LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
+                ComponentName cn = info.providerName;
+                if (cn != null && f.filterItem(null, info, cn)) {
+                    filtered.add(info);
+                }
             }
         }
-        return items;
+        return new ArrayList<ItemInfo>(filtered);
+    }
+
+    private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {
+        HashSet<ItemInfo> infos = new HashSet<ItemInfo>();
+        ItemInfoFilter filter  = new ItemInfoFilter() {
+            @Override
+            public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
+                return cn.getPackageName().equals(pn);
+            }
+        };
+        return filterItemInfos(sBgItemsIdMap.values(), filter);
+    }
+
+    private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {
+        HashSet<ItemInfo> infos = new HashSet<ItemInfo>();
+        ItemInfoFilter filter  = new ItemInfoFilter() {
+            @Override
+            public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {
+                return cn.equals(cname);
+            }
+        };
+        return filterItemInfos(sBgItemsIdMap.values(), filter);
+    }
+
+    public static boolean isShortcutInfoUpdateable(ItemInfo i) {
+        if (i instanceof ShortcutInfo) {
+            ShortcutInfo info = (ShortcutInfo) i;
+            // We need to check for ACTION_MAIN otherwise getComponent() might
+            // return null for some shortcuts (for instance, for shortcuts to
+            // web pages.)
+            Intent intent = info.intent;
+            ComponentName name = intent.getComponent();
+            if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
+                    Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 20d7e5e..0a20724 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1680,7 +1680,6 @@
             break;
         }
 
-        System.out.println("onTouch, return true");
         return true;
     }
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 851cce5..37ef3c4 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -474,22 +474,31 @@
     }
 
     public long insertNewWorkspaceScreen(long screenId) {
-        return insertNewWorkspaceScreen(screenId, true);
+        return insertNewWorkspaceScreen(screenId, getChildCount(), true);
     }
 
-    public long insertNewWorkspaceScreenOnBind(long screenId) {
-        return insertNewWorkspaceScreen(screenId, false);
+    public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId, boolean updateDb) {
+        // Find the index to insert this view into.  If the empty screen exists, then
+        // insert it before that.
+        int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
+        if (insertIndex < 0) {
+            insertIndex = mScreenOrder.size();
+        }
+        return insertNewWorkspaceScreen(screenId, insertIndex, updateDb);
     }
 
     public long insertNewWorkspaceScreen(long screenId, boolean updateDb) {
+        return insertNewWorkspaceScreen(screenId, getChildCount(), updateDb);
+    }
+
+    public long insertNewWorkspaceScreen(long screenId, int insertIndex, boolean updateDb) {
         CellLayout newScreen = (CellLayout)
                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);
 
-
         newScreen.setOnLongClickListener(mLongClickListener);
         mWorkspaceScreens.put(screenId, newScreen);
-        mScreenOrder.add(screenId);
-        addView(newScreen, getChildCount());
+        mScreenOrder.add(insertIndex, screenId);
+        addView(newScreen, insertIndex);
         if (updateDb) {
             // On bind we don't need to update the screens in the database.
             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
@@ -533,6 +542,10 @@
         mScreenOrder.add(newId);
 
         addExtraEmptyScreen();
+
+        // Update the model for the new screen
+        mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
+
         return newId;
     }
 
@@ -588,6 +601,11 @@
             removeView(cl);
         }
         setCurrentPage(mCurrentPage - pageShift);
+
+        if (!removeScreens.isEmpty()) {
+            // Update the model if we have changed any screens
+            mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);
+        }
     }
 
     // See implementation for parameter definition.
@@ -3741,44 +3759,35 @@
     // has been removed and we want to remove all components (widgets, shortcuts, apps) that
     // belong to that package.
     void removeItemsByPackageName(final ArrayList<String> packages) {
-        HashSet<String> packageNames = new HashSet<String>();
+        final HashSet<String> packageNames = new HashSet<String>();
         packageNames.addAll(packages);
 
-        // Just create a hash table of all the specific components that this will affect
-        HashSet<ComponentName> cns = new HashSet<ComponentName>();
+        // Filter out all the ItemInfos that this is going to affect
+        final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();
+        final HashSet<ComponentName> cns = new HashSet<ComponentName>();
         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();
         for (CellLayout layoutParent : cellLayouts) {
             ViewGroup layout = layoutParent.getShortcutsAndWidgets();
             int childCount = layout.getChildCount();
             for (int i = 0; i < childCount; ++i) {
                 View view = layout.getChildAt(i);
-                Object tag = view.getTag();
-
-                if (tag instanceof ShortcutInfo) {
-                    ShortcutInfo info = (ShortcutInfo) tag;
-                    ComponentName cn = info.intent.getComponent();
-                    if ((cn != null) && packageNames.contains(cn.getPackageName())) {
-                        cns.add(cn);
-                    }
-                } else if (tag instanceof FolderInfo) {
-                    FolderInfo info = (FolderInfo) tag;
-                    for (ShortcutInfo s : info.contents) {
-                        ComponentName cn = s.intent.getComponent();
-                        if ((cn != null) && packageNames.contains(cn.getPackageName())) {
-                            cns.add(cn);
-                        }
-                    }
-                } else if (tag instanceof LauncherAppWidgetInfo) {
-                    LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
-                    ComponentName cn = info.providerName;
-                    if ((cn != null) && packageNames.contains(cn.getPackageName())) {
-                        cns.add(cn);
-                    }
-                }
+                infos.add((ItemInfo) view.getTag());
             }
         }
+        LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
+            @Override
+            public boolean filterItem(ItemInfo parent, ItemInfo info,
+                                      ComponentName cn) {
+                if (packageNames.contains(cn.getPackageName())) {
+                    cns.add(cn);
+                    return true;
+                }
+                return false;
+            }
+        };
+        LauncherModel.filterItemInfos(infos, filter);
 
-        // Remove all the things
+        // Remove the affected components
         removeItemsByComponentName(cns);
     }
 
@@ -3801,81 +3810,70 @@
         for (final CellLayout layoutParent: cellLayouts) {
             final ViewGroup layout = layoutParent.getShortcutsAndWidgets();
 
-            // Avoid ANRs by treating each screen separately
-            post(new Runnable() {
-                public void run() {
-                    final ArrayList<View> childrenToRemove = new ArrayList<View>();
-                    childrenToRemove.clear();
+            final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();
+            for (int j = 0; j < layout.getChildCount(); j++) {
+                final View view = layout.getChildAt(j);
+                children.put((ItemInfo) view.getTag(), view);
+            }
 
-                    int childCount = layout.getChildCount();
-                    for (int j = 0; j < childCount; j++) {
-                        final View view = layout.getChildAt(j);
-                        Object tag = view.getTag();
-
-                        if (tag instanceof ShortcutInfo) {
-                            final ShortcutInfo info = (ShortcutInfo) tag;
-                            final Intent intent = info.intent;
-                            final ComponentName name = intent.getComponent();
-
-                            if (name != null) {
-                                if (componentNames.contains(name)) {
-                                    LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                                    childrenToRemove.add(view);
-                                }
+            final ArrayList<View> childrenToRemove = new ArrayList<View>();
+            final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =
+                    new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();
+            LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {
+                @Override
+                public boolean filterItem(ItemInfo parent, ItemInfo info,
+                                          ComponentName cn) {
+                    if (parent instanceof FolderInfo) {
+                        if (componentNames.contains(cn)) {
+                            FolderInfo folder = (FolderInfo) parent;
+                            ArrayList<ShortcutInfo> appsToRemove;
+                            if (folderAppsToRemove.containsKey(folder)) {
+                                appsToRemove = folderAppsToRemove.get(folder);
+                            } else {
+                                appsToRemove = new ArrayList<ShortcutInfo>();
+                                folderAppsToRemove.put(folder, appsToRemove);
                             }
-                        } else if (tag instanceof FolderInfo) {
-                            final FolderInfo info = (FolderInfo) tag;
-                            final ArrayList<ShortcutInfo> contents = info.contents;
-                            final int contentsCount = contents.size();
-                            final ArrayList<ShortcutInfo> appsToRemoveFromFolder =
-                                    new ArrayList<ShortcutInfo>();
-
-                            for (int k = 0; k < contentsCount; k++) {
-                                final ShortcutInfo appInfo = contents.get(k);
-                                final Intent intent = appInfo.intent;
-                                final ComponentName name = intent.getComponent();
-
-                                if (name != null) {
-                                    if (componentNames.contains(name)) {
-                                        appsToRemoveFromFolder.add(appInfo);
-                                    }
-                                }
-                            }
-                            for (ShortcutInfo item: appsToRemoveFromFolder) {
-                                info.remove(item);
-                                LauncherModel.deleteItemFromDatabase(mLauncher, item);
-                            }
-                        } else if (tag instanceof LauncherAppWidgetInfo) {
-                            final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) tag;
-                            final ComponentName provider = info.providerName;
-                            if (provider != null) {
-                                if (componentNames.contains(provider)) {
-                                    LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                                    childrenToRemove.add(view);
-                                }
-                            }
+                            appsToRemove.add((ShortcutInfo) info);
+                            return true;
+                        }
+                    } else {
+                        if (componentNames.contains(cn)) {
+                            childrenToRemove.add(children.get(info));
+                            return true;
                         }
                     }
-
-                    childCount = childrenToRemove.size();
-                    for (int j = 0; j < childCount; j++) {
-                        View child = childrenToRemove.get(j);
-                        // Note: We can not remove the view directly from CellLayoutChildren as this
-                        // does not re-mark the spaces as unoccupied.
-                        layoutParent.removeViewInLayout(child);
-                        if (child instanceof DropTarget) {
-                            mDragController.removeDropTarget((DropTarget)child);
-                        }
-                    }
-
-                    if (childCount > 0) {
-                        layout.requestLayout();
-                        layout.invalidate();
-                    }
+                    return false;
                 }
-            });
+            };
+            LauncherModel.filterItemInfos(children.keySet(), filter);
+
+            // Remove all the apps from their folders
+            for (FolderInfo folder : folderAppsToRemove.keySet()) {
+                ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);
+                for (ShortcutInfo info : appsToRemove) {
+                    folder.remove(info);
+                }
+            }
+
+            // Remove all the other children
+            for (View child : childrenToRemove) {
+                // Note: We can not remove the view directly from CellLayoutChildren as this
+                // does not re-mark the spaces as unoccupied.
+                layoutParent.removeViewInLayout(child);
+                if (child instanceof DropTarget) {
+                    mDragController.removeDropTarget((DropTarget) child);
+                }
+            }
+
+            if (childrenToRemove.size() > 0) {
+                layout.requestLayout();
+                layout.invalidate();
+            }
         }
 
+        // Strip all the empty screens
+        stripEmptyScreens();
+
         // Clean up new-apps animation list
         final Context context = getContext();
         post(new Runnable() {
@@ -3897,15 +3895,6 @@
                                 if (componentNames.contains(intent.getComponent())) {
                                     iter.remove();
                                 }
-
-                                // It is possible that we've queued an item to be loaded, yet it has
-                                // not been added to the workspace, so remove those items as well.
-                                ArrayList<ItemInfo> shortcuts;
-                                shortcuts = LauncherModel.getWorkspaceShortcutItemInfosWithIntent(
-                                        intent);
-                                for (ItemInfo info : shortcuts) {
-                                    LauncherModel.deleteItemFromDatabase(context, info);
-                                }
                             } catch (URISyntaxException e) {}
                         }
                     }
@@ -3921,24 +3910,20 @@
             for (int j = 0; j < childCount; j++) {
                 final View view = layout.getChildAt(j);
                 Object tag = view.getTag();
-                if (tag instanceof ShortcutInfo) {
+
+                if (LauncherModel.isShortcutInfoUpdateable((ItemInfo) tag)) {
                     ShortcutInfo info = (ShortcutInfo) tag;
-                    // We need to check for ACTION_MAIN otherwise getComponent() might
-                    // return null for some shortcuts (for instance, for shortcuts to
-                    // web pages.)
+
                     final Intent intent = info.intent;
                     final ComponentName name = intent.getComponent();
-                    if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
-                            Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {
-                        final int appCount = apps.size();
-                        for (int k = 0; k < appCount; k++) {
-                            ApplicationInfo app = apps.get(k);
-                            if (app.componentName.equals(name)) {
-                                BubbleTextView shortcut = (BubbleTextView) view;
-                                info.updateIcon(mIconCache);
-                                info.title = app.title.toString();
-                                shortcut.applyFromShortcutInfo(info, mIconCache);
-                            }
+                    final int appCount = apps.size();
+                    for (int k = 0; k < appCount; k++) {
+                        ApplicationInfo app = apps.get(k);
+                        if (app.componentName.equals(name)) {
+                            BubbleTextView shortcut = (BubbleTextView) view;
+                            info.updateIcon(mIconCache);
+                            info.title = app.title.toString();
+                            shortcut.applyFromShortcutInfo(info, mIconCache);
                         }
                     }
                 }
@@ -3954,7 +3939,10 @@
                 setCurrentPage(mDefaultPage);
             }
         }
-        getChildAt(mDefaultPage).requestFocus();
+        View child = getChildAt(mDefaultPage);
+        if (child != null) {
+            child.requestFocus();
+        }
     }
 
     @Override