Merge "Fixing issue where toasts were getting queued. (Bug 6572269)"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dbeb7bc..de4a434 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -65,7 +65,7 @@
         android:name="com.android.launcher2.LauncherApplication"
         android:label="@string/application_name"
         android:icon="@drawable/ic_launcher_home"
-        android:hardwareAccelerated="@bool/config_hardwareAccelerated"
+        android:hardwareAccelerated="true"
         android:largeHeap="@bool/config_largeHeap">
         <activity
             android:name="com.android.launcher2.Launcher"
diff --git a/res/values/config.xml b/res/values/config.xml
index 423a3a9..7f95931 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -1,5 +1,4 @@
 <resources>
-    <bool name="config_hardwareAccelerated">true</bool>
     <bool name="config_largeHeap">false</bool>
     <bool name="is_large_screen">false</bool>
     <bool name="allow_rotation">false</bool>
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 ccc842e..aa8c132 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -159,6 +159,7 @@
 
     private final static PorterDuffXfermode sAddBlendMode =
             new PorterDuffXfermode(PorterDuff.Mode.ADD);
+    private final static Paint sPaint = new Paint();
 
     public CellLayout(Context context) {
         this(context, null);
@@ -302,7 +303,15 @@
     }
 
     public void enableHardwareLayers() {
-        mShortcutsAndWidgets.enableHardwareLayers();
+        mShortcutsAndWidgets.setLayerType(LAYER_TYPE_HARDWARE, sPaint);
+    }
+
+    public void disableHardwareLayers() {
+        mShortcutsAndWidgets.setLayerType(LAYER_TYPE_NONE, sPaint);
+    }
+
+    public void buildHardwareLayer() {
+        mShortcutsAndWidgets.buildLayer();
     }
 
     public void setGridSize(int x, int y) {
@@ -2140,6 +2149,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/DragView.java b/src/com/android/launcher2/DragView.java
index d7ac97d..389421d 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -244,9 +244,6 @@
     public void show(int touchX, int touchY) {
         mDragLayer.addView(this);
 
-        // Enable hw-layers on this view
-        setLayerType(View.LAYER_TYPE_HARDWARE, null);
-
         // Start the pick-up animation
         DragLayer.LayoutParams lp = new DragLayer.LayoutParams(0, 0);
         lp.width = mBitmap.getWidth();
@@ -255,7 +252,12 @@
         setLayoutParams(lp);
         setTranslationX(touchX - mRegistrationX);
         setTranslationY(touchY - mRegistrationY);
-        mAnim.start();
+        // Post the animation to skip other expensive work happening on the first frame
+        post(new Runnable() {
+                public void run() {
+                    mAnim.start();
+                }
+            });
     }
 
     public void cancelAnimation() {
@@ -282,9 +284,6 @@
 
     void remove() {
         if (getParent() != null) {
-            // Disable hw-layers on this view
-            setLayerType(View.LAYER_TYPE_NONE, null);
-
             mDragLayer.removeView(DragView.this);
         }
     }
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/LauncherAnimUtils.java b/src/com/android/launcher2/LauncherAnimUtils.java
index 182adf5..8a4633e 100644
--- a/src/com/android/launcher2/LauncherAnimUtils.java
+++ b/src/com/android/launcher2/LauncherAnimUtils.java
@@ -26,7 +26,7 @@
 
 public class LauncherAnimUtils {
     static HashSet<Animator> sAnimators = new HashSet<Animator>();
-    Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
+    static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
         public void onAnimationStart(Animator animation) {
         }
 
@@ -44,6 +44,7 @@
 
     public static void cancelOnDestroyActivity(Animator a) {
         sAnimators.add(a);
+        a.addListener(sEndAnimListener);
     }
 
     public static void onDestroyActivity() {
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 6080411..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
@@ -1722,24 +1784,6 @@
     }
 
     /**
-     * Returns all the Workspace ShortcutInfos associated with a particular package.
-     * @param intent
-     * @return
-     */
-    ArrayList<ShortcutInfo> getShortcutInfosForPackage(String packageName) {
-        ArrayList<ShortcutInfo> infos = new ArrayList<ShortcutInfo>();
-        for (ItemInfo i : sWorkspaceItems) {
-            if (i instanceof ShortcutInfo) {
-                ShortcutInfo info = (ShortcutInfo) i;
-                if (packageName.equals(info.getPackageName())) {
-                    infos.add(info);
-                }
-            }
-        }
-        return infos;
-    }
-
-    /**
      * This is called from the code that adds shortcuts from the intent receiver.  This
      * doesn't have a Cursor, but
      */
@@ -2189,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/ShortcutAndWidgetContainer.java b/src/com/android/launcher2/ShortcutAndWidgetContainer.java
index 8bebdcd..8daf395 100644
--- a/src/com/android/launcher2/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher2/ShortcutAndWidgetContainer.java
@@ -44,10 +44,6 @@
         mWallpaperManager = WallpaperManager.getInstance(context);
     }
 
-    public void enableHardwareLayers() {
-        setLayerType(LAYER_TYPE_HARDWARE, null);
-    }
-
     public void setCellDimensions(int cellWidth, int cellHeight, int widthGap, int heightGap ) {
         mCellWidth = cellWidth;
         mCellHeight = cellHeight;
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 7248950..21c7889 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -170,6 +170,7 @@
     private Bitmap mDragOutline = null;
     private final Rect mTempRect = new Rect();
     private final int[] mTempXY = new int[2];
+    private int[] mTempVisiblePagesRange = new int[2];
     private float mOverscrollFade = 0;
     private boolean mOverscrollTransformsSet;
     public static final int DRAG_BITMAP_PADDING = 2;
@@ -427,7 +428,6 @@
         CellLayout cl = ((CellLayout) child);
         cl.setOnInterceptTouchListener(this);
         cl.setClickable(true);
-        cl.enableHardwareLayers();
         cl.setContentDescription(getContext().getString(
                 R.string.workspace_description_format, getChildCount()));
     }
@@ -1221,6 +1221,7 @@
         super.screenScrolled(screenCenter);
 
         updatePageAlphaValues(screenCenter);
+        enableHwLayersOnVisiblePages();
 
         if (mOverScrollX < 0 || mOverScrollX > mMaxScrollX) {
             int index = mOverScrollX < 0 ? 0 : getChildCount() - 1;
@@ -1368,10 +1369,42 @@
 
         if (enableChildrenLayers != mChildrenLayersEnabled) {
             mChildrenLayersEnabled = enableChildrenLayers;
-            for (int i = 0; i < getPageCount(); i++) {
-                CellLayout cl = (CellLayout) getChildAt(i);
-                cl.getShortcutsAndWidgets().setLayerType(
-                        mChildrenLayersEnabled ? LAYER_TYPE_HARDWARE : LAYER_TYPE_NONE, null);
+            if (mChildrenLayersEnabled) {
+                enableHwLayersOnVisiblePages();
+            } else {
+                for (int i = 0; i < getPageCount(); i++) {
+                    final CellLayout cl = (CellLayout) getChildAt(i);
+                    cl.disableHardwareLayers();
+                }
+            }
+        }
+    }
+
+    private void enableHwLayersOnVisiblePages() {
+        if (mChildrenLayersEnabled) {
+            final int screenCount = getChildCount();
+            getVisiblePages(mTempVisiblePagesRange);
+            int leftScreen = mTempVisiblePagesRange[0];
+            int rightScreen = mTempVisiblePagesRange[1];
+            if (leftScreen == rightScreen) {
+                // make sure we're caching at least two pages always
+                if (rightScreen < screenCount - 1) {
+                    rightScreen++;
+                } else if (leftScreen > 0) {
+                    leftScreen--;
+                }
+            }
+            for (int i = 0; i < screenCount; i++) {
+                final CellLayout layout = (CellLayout) getChildAt(i);
+                if (!(leftScreen <= i && i <= rightScreen && shouldDrawChild(layout))) {
+                    layout.disableHardwareLayers();
+                }
+            }
+            for (int i = 0; i < screenCount; i++) {
+                final CellLayout layout = (CellLayout) getChildAt(i);
+                if (leftScreen <= i && i <= rightScreen && shouldDrawChild(layout)) {
+                    layout.enableHardwareLayers();
+                }
             }
         }
     }
@@ -1383,7 +1416,7 @@
             final int childCount = getChildCount();
             for (int i = 0; i < childCount; i++) {
                 CellLayout cl = (CellLayout) getChildAt(i);
-                cl.getShortcutsAndWidgets().buildLayer();
+                cl.buildHardwareLayer();
             }
         }
         updateChildrenLayersEnabled(false);
@@ -3350,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);
             }
@@ -3635,11 +3669,7 @@
             });
         }
 
-        // It is no longer the case the BubbleTextViews correspond 1:1 with the workspace items in
-        // the database (and LauncherModel) since shortcuts are not added and animated in until
-        // the user returns to launcher.  As a result, we really should be cleaning up the Db
-        // regardless of whether the item was added or not (unlike the logic above).  This is only
-        // relevant for direct workspace items.
+        // Clean up new-apps animation list
         post(new Runnable() {
             @Override
             public void run() {
@@ -3649,26 +3679,18 @@
                 Set<String> newApps = sp.getStringSet(InstallShortcutReceiver.NEW_APPS_LIST_KEY,
                         null);
 
-                for (String packageName: packageNames) {
-                    // Remove all items that have the same package, but were not removed above
-                    ArrayList<ShortcutInfo> infos =
-                            mLauncher.getModel().getShortcutInfosForPackage(packageName);
-                    for (ShortcutInfo info : infos) {
-                        LauncherModel.deleteItemFromDatabase(mLauncher, info);
-                    }
-                    // Remove all queued items that match the same package
-                    if (newApps != null) {
-                        synchronized (newApps) {
-                            Iterator<String> iter = newApps.iterator();
-                            while (iter.hasNext()) {
-                                try {
-                                    Intent intent = Intent.parseUri(iter.next(), 0);
-                                    String pn = ItemInfo.getPackageName(intent);
-                                    if (packageNames.contains(pn)) {
-                                        iter.remove();
-                                    }
-                                } catch (URISyntaxException e) {}
-                            }
+                // Remove all queued items that match the same package
+                if (newApps != null) {
+                    synchronized (newApps) {
+                        Iterator<String> iter = newApps.iterator();
+                        while (iter.hasNext()) {
+                            try {
+                                Intent intent = Intent.parseUri(iter.next(), 0);
+                                String pn = ItemInfo.getPackageName(intent);
+                                if (packageNames.contains(pn)) {
+                                    iter.remove();
+                                }
+                            } catch (URISyntaxException e) {}
                         }
                     }
                 }