Trying to track down corrupt database / items disappearing

-> Adding logs for all database transactions
-> Adding sanity checks for items in folders, throwing exceptions
   if they are violated
-> Reducing database upates when re-arranging items, only
   update if values have changed
-> Removed some dead code from ItemInfo (isGesture?)

Change-Id: Ia5cd57d92082f633dbf4aa5d64612cbae2d82bb4
diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java
index 281d59c..a3040d4 100644
--- a/src/com/android/launcher2/ApplicationInfo.java
+++ b/src/com/android/launcher2/ApplicationInfo.java
@@ -34,11 +34,6 @@
     private static final String TAG = "Launcher2.ApplicationInfo";
 
     /**
-     * The application name.
-     */
-    CharSequence title;
-
-    /**
      * The intent used to start the application.
      */
     Intent intent;
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 284db1b..c993f0e 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -2148,6 +2148,10 @@
             // We do a null check here because the item info can be null in the case of the
             // AllApps button in the hotseat.
             if (info != null) {
+                if (info.cellX != lp.tmpCellX || info.cellY != lp.tmpCellY ||
+                        info.spanX != lp.cellHSpan || info.spanY != lp.cellVSpan) {
+                    info.requiresDbUpdate = true;
+                }
                 info.cellX = lp.cellX = lp.tmpCellX;
                 info.cellY = lp.cellY = lp.tmpCellY;
                 info.spanX = lp.cellHSpan;
diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java
index 84c815e..ae7ee6e 100644
--- a/src/com/android/launcher2/Folder.java
+++ b/src/com/android/launcher2/Folder.java
@@ -951,16 +951,6 @@
             public void run() {
                 CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container, mInfo.screen);
 
-                if (getItemCount() <= 1) {
-                    // Remove the folder
-                    LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
-                    cellLayout.removeView(mFolderIcon);
-                    if (mFolderIcon instanceof DropTarget) {
-                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
-                    }
-                    mLauncher.removeFolder(mInfo);
-                }
-
                 // Move the item from the folder to the workspace, in the position of the folder
                 if (getItemCount() == 1) {
                     ShortcutInfo finalItem = mInfo.contents.get(0);
@@ -973,6 +963,15 @@
                             mInfo.cellX, mInfo.cellY, mInfo.spanX, mInfo.spanY);
                 }
 
+                if (getItemCount() <= 1) {
+                    // Remove the folder
+                    LauncherModel.deleteItemFromDatabase(mLauncher, mInfo);
+                    cellLayout.removeView(mFolderIcon);
+                    if (mFolderIcon instanceof DropTarget) {
+                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
+                    }
+                    mLauncher.removeFolder(mInfo);
+                }
             }
         };
         View finalChild = getItemAt(0);
diff --git a/src/com/android/launcher2/FolderInfo.java b/src/com/android/launcher2/FolderInfo.java
index f597076..dbac90e 100644
--- a/src/com/android/launcher2/FolderInfo.java
+++ b/src/com/android/launcher2/FolderInfo.java
@@ -31,11 +31,6 @@
     boolean opened;
 
     /**
-     * The folder name.
-     */
-    CharSequence title;
-
-    /**
      * The apps and shortcuts
      */
     ArrayList<ShortcutInfo> contents = new ArrayList<ShortcutInfo>();
diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java
index dedc0f4..f9ae368 100644
--- a/src/com/android/launcher2/ItemInfo.java
+++ b/src/com/android/launcher2/ItemInfo.java
@@ -86,10 +86,16 @@
      * Indicates the minimum Y cell span.
      */
     int minSpanY = 1;
+
     /**
-     * Indicates whether the item is a gesture.
+     * Indicates that this item needs to be updated in the db
      */
-    boolean isGesture = false;
+    boolean requiresDbUpdate = false;
+
+    /**
+     * Title of the item
+     */
+    CharSequence title;
 
     /**
      * The position of the item in a drag-and-drop operation.
@@ -132,14 +138,12 @@
      */
     void onAddToDatabase(ContentValues values) { 
         values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
-        if (!isGesture) {
-            values.put(LauncherSettings.Favorites.CONTAINER, container);
-            values.put(LauncherSettings.Favorites.SCREEN, screen);
-            values.put(LauncherSettings.Favorites.CELLX, cellX);
-            values.put(LauncherSettings.Favorites.CELLY, cellY);
-            values.put(LauncherSettings.Favorites.SPANX, spanX);
-            values.put(LauncherSettings.Favorites.SPANY, spanY);
-        }
+        values.put(LauncherSettings.Favorites.CONTAINER, container);
+        values.put(LauncherSettings.Favorites.SCREEN, screen);
+        values.put(LauncherSettings.Favorites.CELLX, cellX);
+        values.put(LauncherSettings.Favorites.CELLY, cellY);
+        values.put(LauncherSettings.Favorites.SPANX, spanX);
+        values.put(LauncherSettings.Favorites.SPANY, spanY);
     }
 
     void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) {
@@ -183,6 +187,6 @@
     public String toString() {
         return "Item(id=" + this.id + " type=" + this.itemType + " container=" + this.container
             + " screen=" + screen + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
-            + " spanY=" + spanY + " isGesture=" + isGesture + " dropPos=" + dropPos + ")";
+            + " spanY=" + spanY + " dropPos=" + dropPos + ")";
     }
 }
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 3e8c7aa..c3920ad 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -3743,6 +3743,17 @@
             writer.println("  " + sDumpLogs.get(i));
         }
     }
+
+    public static void dumpDebugLogsToConsole() {
+        Log.d(TAG, "");
+        Log.d(TAG, "*********************");
+        Log.d(TAG, "Launcher debug logs: ");
+        for (int i = 0; i < sDumpLogs.size(); i++) {
+            Log.d(TAG, "  " + sDumpLogs.get(i));
+        }
+        Log.d(TAG, "*********************");
+        Log.d(TAG, "");
+    }
 }
 
 interface LauncherTransitionable {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 1657a50..1890e74 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -93,27 +93,26 @@
     private WeakReference<Callbacks> mCallbacks;
 
     // < only access in worker thread >
-    private AllAppsList mAllAppsList;
+    private AllAppsList mBgAllAppsList;
 
-    // sItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
+    // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
     // LauncherModel to their ids
-    static final HashMap<Long, ItemInfo> sItemsIdMap = new HashMap<Long, ItemInfo>();
+    static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
 
-    // sItems is passed to bindItems, which expects a list of all folders and shortcuts created by
-    //       LauncherModel that are directly on the home screen (however, no widgets or shortcuts
-    //       within folders).
-    static final ArrayList<ItemInfo> sWorkspaceItems = new ArrayList<ItemInfo>();
+    // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
+    //       created by LauncherModel that are directly on the home screen (however, no widgets or
+    //       shortcuts within folders).
+    static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();
 
-    // sAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
-    static final ArrayList<LauncherAppWidgetInfo> sAppWidgets =
+    // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
+    static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =
         new ArrayList<LauncherAppWidgetInfo>();
 
-    // sFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
-    static final HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+    // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
+    static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
 
-    // sDbIconCache is the set of ItemInfos that need to have their icons updated in the database
-    static final HashMap<Object, byte[]> sDbIconCache = new HashMap<Object, byte[]>();
-
+    // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database
+    static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();
     // </ only access in worker thread >
 
     private IconCache mIconCache;
@@ -145,7 +144,7 @@
     LauncherModel(LauncherApplication app, IconCache iconCache) {
         mAppsCanBeOnExternalStorage = !Environment.isExternalStorageEmulated();
         mApp = app;
-        mAllAppsList = new AllAppsList(iconCache);
+        mBgAllAppsList = new AllAppsList(iconCache);
         mIconCache = iconCache;
 
         mDefaultIcon = Utilities.createIconBitmap(
@@ -176,8 +175,8 @@
     private ArrayList<ItemInfo> unbindWorkspaceItemsOnMainThread() {
         // Ensure that we don't use the same workspace items data structure on the main thread
         // by making a copy of workspace items first.
-        final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>(sWorkspaceItems);
-        final ArrayList<ItemInfo> appWidgets = new ArrayList<ItemInfo>(sAppWidgets);
+        final ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>(sBgWorkspaceItems);
+        final ArrayList<ItemInfo> appWidgets = new ArrayList<ItemInfo>(sBgAppWidgets);
         mHandler.post(new Runnable() {
             @Override
             public void run() {
@@ -213,7 +212,7 @@
         final long itemId = item.id;
         Runnable r = new Runnable() {
                 public void run() {
-                    ItemInfo modelItem = sItemsIdMap.get(itemId);
+                    ItemInfo modelItem = sBgItemsIdMap.get(itemId);
                     if (modelItem != null && item != modelItem) {
                         // the modelItem needs to match up perfectly with item if our model is to be
                         // consistent with the database-- for now, just require modelItem == item
@@ -241,11 +240,12 @@
         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);
         final ContentResolver cr = context.getContentResolver();
 
+        final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
         Runnable r = new Runnable() {
             public void run() {
                 cr.update(uri, values, null, null);
 
-                ItemInfo modelItem = sItemsIdMap.get(itemId);
+                ItemInfo modelItem = sBgItemsIdMap.get(itemId);
                 if (item != modelItem) {
                     // the modelItem needs to match up perfectly with item if our model is to be
                     // consistent with the database-- for now, just require modelItem == item
@@ -255,16 +255,31 @@
                     throw new RuntimeException(msg);
                 }
 
+                if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+                        item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+                    // Item is in a folder, make sure this folder exists
+                    if (!sBgFolders.containsKey(item.container)) {
+                        // An items container is being set to a that of an item which is not in the
+                        // list of Folders.
+                        String msg = "item: " + item + " container being set to: " +
+                                item.container + ", not in the list of folders";
+                        RuntimeException e = new RuntimeException(msg);
+                        e.setStackTrace(stackTrace);
+                        Launcher.dumpDebugLogsToConsole();
+                        throw e;
+                    }
+                }
+
                 // Items are added/removed from the corresponding FolderInfo elsewhere, such
                 // as in Workspace.onDrop. Here, we just add/remove them from the list of items
                 // that are on the desktop, as appropriate
                 if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
                         modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
-                    if (!sWorkspaceItems.contains(modelItem)) {
-                        sWorkspaceItems.add(modelItem);
+                    if (!sBgWorkspaceItems.contains(modelItem)) {
+                        sBgWorkspaceItems.add(modelItem);
                     }
                 } else {
-                    sWorkspaceItems.remove(modelItem);
+                    sBgWorkspaceItems.remove(modelItem);
                 }
             }
         };
@@ -281,6 +296,11 @@
      */
     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
             final int screen, final int cellX, final int cellY) {
+        String transaction = "DbDebug    Modify item (" + item.title + ") in db, id: " + item.id + 
+                " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + 
+                ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")";
+        Launcher.sDumpLogs.add(transaction);
+        Log.d(TAG, transaction);
         item.container = container;
         item.cellX = cellX;
         item.cellY = cellY;
@@ -308,7 +328,11 @@
      */
     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,
             final int screen, final int cellX, final int cellY, final int spanX, final int spanY) {
-        item.container = container;
+        String transaction = "DbDebug    Modify item (" + item.title + ") in db, id: " + item.id + 
+                " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY + 
+                ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")";
+        Launcher.sDumpLogs.add(transaction);
+        Log.d(TAG, transaction);
         item.cellX = cellX;
         item.cellY = cellY;
         item.spanX = spanX;
@@ -473,30 +497,48 @@
         values.put(LauncherSettings.Favorites._ID, item.id);
         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
 
+        final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+
         Runnable r = new Runnable() {
             public void run() {
+                String transaction = "DbDebug    Add item (" + item.title + ") to db, id: "
+                        + item.id + " (" + container + ", " + screen + ", " + cellX + ", "
+                        + cellY + ")";
+                Launcher.sDumpLogs.add(transaction);
+                Log.d(TAG, transaction);
+
                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
 
-                if (sItemsIdMap.containsKey(item.id)) {
+                if (sBgItemsIdMap.containsKey(item.id)) {
                     // we should not be adding new items in the db with the same id
                     throw new RuntimeException("Error: ItemInfo id (" + item.id + ") passed to " +
                         "addItemToDatabase already exists." + item.toString());
                 }
-                sItemsIdMap.put(item.id, item);
+                sBgItemsIdMap.put(item.id, item);
                 switch (item.itemType) {
                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                        sFolders.put(item.id, (FolderInfo) item);
+                        sBgFolders.put(item.id, (FolderInfo) item);
                         // Fall through
                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
                                 item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
-                            sWorkspaceItems.add(item);
+                            sBgWorkspaceItems.add(item);
+                        } else {
+                            if (!sBgFolders.containsKey(item.container)) {
+                                // Adding an item to a folder that doesn't exist.
+                                String msg = "adding item: " + item + " to a folder that " +
+                                        " doesn't exist";
+                                RuntimeException e = new RuntimeException(msg);
+                                e.setStackTrace(stackTrace);
+                                Launcher.dumpDebugLogsToConsole();
+                                throw e;
+                            }
                         }
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        sAppWidgets.add((LauncherAppWidgetInfo) item);
+                        sBgAppWidgets.add((LauncherAppWidgetInfo) item);
                         break;
                 }
             }
@@ -543,24 +585,44 @@
     static void deleteItemFromDatabase(Context context, final ItemInfo item) {
         final ContentResolver cr = context.getContentResolver();
         final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);
+        final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+
         Runnable r = new Runnable() {
             public void run() {
+                String transaction = "DbDebug    Delete item (" + item.title + ") from db, id: "
+                        + item.id + " (" + item.container + ", " + item.screen + ", " + item.cellX +
+                        ", " + item.cellY + ")";
+                Launcher.sDumpLogs.add(transaction);
+                Log.d(TAG, transaction);
+
                 cr.delete(uriToDelete, null, null);
                 switch (item.itemType) {
                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                        sFolders.remove(item.id);
-                        sWorkspaceItems.remove(item);
+                        sBgFolders.remove(item.id);
+                        for (ItemInfo info: sBgItemsIdMap.values()) {
+                            if (info.container == item.id) {
+                                // We are deleting a folder which still contains items that
+                                // think they are contained by that folder.
+                                String msg = "deleting a folder (" + item + ") which still " +
+                                        "contains items (" + info + ")";
+                                RuntimeException e = new RuntimeException(msg);
+                                e.setStackTrace(stackTrace);
+                                Launcher.dumpDebugLogsToConsole();
+                                throw e;
+                            }
+                        }
+                        sBgWorkspaceItems.remove(item);
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        sWorkspaceItems.remove(item);
+                        sBgWorkspaceItems.remove(item);
                         break;
                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                        sAppWidgets.remove((LauncherAppWidgetInfo) item);
+                        sBgAppWidgets.remove((LauncherAppWidgetInfo) item);
                         break;
                 }
-                sItemsIdMap.remove(item.id);
-                sDbIconCache.remove(item);
+                sBgItemsIdMap.remove(item.id);
+                sBgDbIconCache.remove(item);
             }
         };
         if (sWorkerThread.getThreadId() == Process.myTid()) {
@@ -579,16 +641,16 @@
         Runnable r = new Runnable() {
             public void run() {
                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
-                sItemsIdMap.remove(info.id);
-                sFolders.remove(info.id);
-                sDbIconCache.remove(info);
-                sWorkspaceItems.remove(info);
+                sBgItemsIdMap.remove(info.id);
+                sBgFolders.remove(info.id);
+                sBgDbIconCache.remove(info);
+                sBgWorkspaceItems.remove(info);
 
                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,
                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
                 for (ItemInfo childInfo : info.contents) {
-                    sItemsIdMap.remove(childInfo.id);
-                    sDbIconCache.remove(childInfo);
+                    sBgItemsIdMap.remove(childInfo.id);
+                    sBgDbIconCache.remove(childInfo);
                 }
             }
         };
@@ -922,10 +984,10 @@
 
             // Update the saved icons if necessary
             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");
-            for (Object key : sDbIconCache.keySet()) {
-                updateSavedIcon(mContext, (ShortcutInfo) key, sDbIconCache.get(key));
+            for (Object key : sBgDbIconCache.keySet()) {
+                updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));
             }
-            sDbIconCache.clear();
+            sBgDbIconCache.clear();
 
             // Clear out this reference, otherwise we end up holding it until all of the
             // callback runnables are done.
@@ -1035,11 +1097,11 @@
             // Make sure the default workspace is loaded, if needed
             mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary();
 
-            sWorkspaceItems.clear();
-            sAppWidgets.clear();
-            sFolders.clear();
-            sItemsIdMap.clear();
-            sDbIconCache.clear();
+            sBgWorkspaceItems.clear();
+            sBgAppWidgets.clear();
+            sBgFolders.clear();
+            sBgItemsIdMap.clear();
+            sBgDbIconCache.clear();
 
             final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
 
@@ -1143,20 +1205,20 @@
                                 switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
                                 case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
-                                    sWorkspaceItems.add(info);
+                                    sBgWorkspaceItems.add(info);
                                     break;
                                 default:
                                     // Item is in a user folder
                                     FolderInfo folderInfo =
-                                            findOrMakeFolder(sFolders, container);
+                                            findOrMakeFolder(sBgFolders, container);
                                     folderInfo.add(info);
                                     break;
                                 }
-                                sItemsIdMap.put(info.id, info);
+                                sBgItemsIdMap.put(info.id, info);
 
                                 // now that we've loaded everthing re-save it with the
                                 // icon in case it disappears somehow.
-                                queueIconToBeChecked(sDbIconCache, info, c, iconIndex);
+                                queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);
                             } else {
                                 // Failed to load the shortcut, probably because the
                                 // activity manager couldn't resolve it (maybe the app
@@ -1171,7 +1233,7 @@
 
                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                             id = c.getLong(idIndex);
-                            FolderInfo folderInfo = findOrMakeFolder(sFolders, id);
+                            FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
 
                             folderInfo.title = c.getString(titleIndex);
                             folderInfo.id = id;
@@ -1188,12 +1250,12 @@
                             switch (container) {
                                 case LauncherSettings.Favorites.CONTAINER_DESKTOP:
                                 case LauncherSettings.Favorites.CONTAINER_HOTSEAT:
-                                    sWorkspaceItems.add(folderInfo);
+                                    sBgWorkspaceItems.add(folderInfo);
                                     break;
                             }
 
-                            sItemsIdMap.put(folderInfo.id, folderInfo);
-                            sFolders.put(folderInfo.id, folderInfo);
+                            sBgItemsIdMap.put(folderInfo.id, folderInfo);
+                            sBgFolders.put(folderInfo.id, folderInfo);
                             break;
 
                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -1237,8 +1299,8 @@
                                 if (!checkItemPlacement(occupied, appWidgetInfo)) {
                                     break;
                                 }
-                                sItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
-                                sAppWidgets.add(appWidgetInfo);
+                                sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);
+                                sBgAppWidgets.add(appWidgetInfo);
                             }
                             break;
                         }
@@ -1359,7 +1421,7 @@
                 });
             }
             // Ensure that we don't use the same folders data structure on the main thread
-            final HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>(sFolders);
+            final HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>(sBgFolders);
             mHandler.post(new Runnable() {
                 public void run() {
                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);
@@ -1381,10 +1443,10 @@
             // but since getCurrentScreen() just returns the int, we should be okay.  This
             // is just a hint for the order, and if it's wrong, we'll be okay.
             // TODO: instead, we should have that push the current screen into here.
-            N = sAppWidgets.size();
+            N = sBgAppWidgets.size();
             // once for the current screen
             for (int i=0; i<N; i++) {
-                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
+                final LauncherAppWidgetInfo widget = sBgAppWidgets.get(i);
                 if (widget.screen == currentScreen) {
                     mHandler.post(new Runnable() {
                         public void run() {
@@ -1398,7 +1460,7 @@
             }
             // once for the other screens
             for (int i=0; i<N; i++) {
-                final LauncherAppWidgetInfo widget = sAppWidgets.get(i);
+                final LauncherAppWidgetInfo widget = sBgAppWidgets.get(i);
                 if (widget.screen != currentScreen) {
                     mHandler.post(new Runnable() {
                         public void run() {
@@ -1461,7 +1523,7 @@
             // shallow copy
             @SuppressWarnings("unchecked")
             final ArrayList<ApplicationInfo> list
-                    = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone();
+                    = (ArrayList<ApplicationInfo>) mBgAllAppsList.data.clone();
             mHandler.post(new Runnable() {
                 public void run() {
                     final long t = SystemClock.uptimeMillis();
@@ -1503,7 +1565,7 @@
             int batchSize = -1;
             while (i < N && !mStopped) {
                 if (i == 0) {
-                    mAllAppsList.clear();
+                    mBgAllAppsList.clear();
                     final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
                     apps = packageManager.queryIntentActivities(mainIntent, 0);
                     if (DEBUG_LOADERS) {
@@ -1541,15 +1603,15 @@
                 startIndex = i;
                 for (int j=0; i<N && j<batchSize; j++) {
                     // This builds the icon bitmaps.
-                    mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
+                    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 = mAllAppsList.added;
-                mAllAppsList.added = new ArrayList<ApplicationInfo>();
+                final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;
+                mBgAllAppsList.added = new ArrayList<ApplicationInfo>();
 
                 mHandler.post(new Runnable() {
                     public void run() {
@@ -1598,7 +1660,7 @@
             Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);
             Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);
             Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);
-            Log.d(TAG, "mItems size=" + sWorkspaceItems.size());
+            Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());
         }
     }
 
@@ -1631,20 +1693,20 @@
                 case OP_ADD:
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
-                        mAllAppsList.addPackage(context, packages[i]);
+                        mBgAllAppsList.addPackage(context, packages[i]);
                     }
                     break;
                 case OP_UPDATE:
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
-                        mAllAppsList.updatePackage(context, packages[i]);
+                        mBgAllAppsList.updatePackage(context, packages[i]);
                     }
                     break;
                 case OP_REMOVE:
                 case OP_UNAVAILABLE:
                     for (int i=0; i<N; i++) {
                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
-                        mAllAppsList.removePackage(packages[i]);
+                        mBgAllAppsList.removePackage(packages[i]);
                     }
                     break;
             }
@@ -1652,13 +1714,13 @@
             ArrayList<ApplicationInfo> added = null;
             ArrayList<ApplicationInfo> modified = null;
 
-            if (mAllAppsList.added.size() > 0) {
-                added = mAllAppsList.added;
-                mAllAppsList.added = new ArrayList<ApplicationInfo>();
+            if (mBgAllAppsList.added.size() > 0) {
+                added = mBgAllAppsList.added;
+                mBgAllAppsList.added = new ArrayList<ApplicationInfo>();
             }
-            if (mAllAppsList.modified.size() > 0) {
-                modified = mAllAppsList.modified;
-                mAllAppsList.modified = new ArrayList<ApplicationInfo>();
+            if (mBgAllAppsList.modified.size() > 0) {
+                modified = mBgAllAppsList.modified;
+                mBgAllAppsList.modified = new ArrayList<ApplicationInfo>();
             }
 
             // We may be removing packages that have no associated launcher application, so we
@@ -2171,10 +2233,10 @@
 
     public void dumpState() {
         Log.d(TAG, "mCallbacks=" + mCallbacks);
-        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mAllAppsList.data);
-        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
-        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
-        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
+        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);
+        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);
+        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);
+        ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);
         if (mLoaderTask != null) {
             mLoaderTask.dumpState();
         } else {
diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java
index 533059f..968d3b8 100644
--- a/src/com/android/launcher2/ShortcutInfo.java
+++ b/src/com/android/launcher2/ShortcutInfo.java
@@ -30,11 +30,6 @@
 class ShortcutInfo extends ItemInfo {
 
     /**
-     * The application name.
-     */
-    CharSequence title;
-
-    /**
      * The intent used to start the application.
      */
     Intent intent;
@@ -158,7 +153,7 @@
         return "ShortcutInfo(title=" + title.toString() + "intent=" + intent + "id=" + this.id
                 + " type=" + this.itemType + " container=" + this.container + " screen=" + screen
                 + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX + " spanY=" + spanY
-                + " isGesture=" + isGesture + " dropPos=" + dropPos + ")";
+                + " dropPos=" + dropPos + ")";
     }
 
     public static void dumpShortcutInfoList(String tag, String label,
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 829ac20..21c7889 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -3383,7 +3383,8 @@
             View v = cl.getShortcutsAndWidgets().getChildAt(i);
             ItemInfo info = (ItemInfo) v.getTag();
             // Null check required as the AllApps button doesn't have an item info
-            if (info != null) {
+            if (info != null && info.requiresDbUpdate) {
+                info.requiresDbUpdate = false;
                 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX,
                         info.cellY, info.spanX, info.spanY);
             }