Merge "Import revised translations."
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index 637d956..8bbf902 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -1602,7 +1602,9 @@
      * leak the previous Home screen on orientation change.
      */
     private void unbindWorkspaceAndHotseatItems() {
-        LauncherModel.unbindWorkspaceItems();
+        if (mModel != null) {
+            mModel.unbindWorkspaceItems();
+        }
     }
 
     /**
@@ -2754,9 +2756,6 @@
         if (mHotseat != null) {
             mHotseat.resetLayout();
         }
-
-        // This wasn't being called before which resulted in a leak of AppWidgetHostViews
-        unbindWorkspaceAndHotseatItems();
     }
 
     /**
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 239970e..e0b04da 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -155,10 +155,31 @@
         return Bitmap.createBitmap(mDefaultIcon);
     }
 
-    public static void unbindWorkspaceItems() {
-        for (ItemInfo item: sWorkspaceItems) {
-            item.unbind();
-        }
+    public void unbindWorkspaceItems() {
+        sWorker.post(new Runnable() {
+            @Override
+            public void run() {
+                unbindWorkspaceItemsOnMainThread();
+            }
+        });
+    }
+
+    /** Unbinds all the sWorkspaceItems on the main thread, and return a copy of sWorkspaceItems
+     * that is save to reference from the main thread. */
+    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);
+        mHandler.post(new Runnable() {
+           @Override
+            public void run() {
+               for (ItemInfo item : workspaceItems) {
+                   item.unbind();
+               }
+            }
+        });
+
+        return workspaceItems;
     }
 
     /**
@@ -867,17 +888,28 @@
         private boolean checkItemPlacement(ItemInfo occupied[][][], ItemInfo item) {
             int containerIndex = item.screen;
             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
-                // We use the last index to refer to the hotseat
-                containerIndex = Launcher.SCREEN_COUNT;
                 // Return early if we detect that an item is under the hotseat button
                 if (Hotseat.isAllAppsButtonRank(item.screen)) {
                     return false;
                 }
+
+                // We use the last index to refer to the hotseat and the screen as the rank, so
+                // test and update the occupied state accordingly
+                if (occupied[Launcher.SCREEN_COUNT][item.screen][0] != null) {
+                    Log.e(TAG, "Error loading shortcut into hotseat " + item
+                        + " into position (" + item.screen + ":" + item.cellX + "," + item.cellY
+                        + ") occupied by " + occupied[Launcher.SCREEN_COUNT][item.screen][0]);
+                    return false;
+                } else {
+                    occupied[Launcher.SCREEN_COUNT][item.screen][0] = item;
+                    return true;
+                }
             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
                 // Skip further checking if it is not the hotseat or workspace container
                 return true;
             }
 
+            // Check if any workspace icons overlap with each other
             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
                     if (occupied[containerIndex][x][y] != null) {
@@ -1165,8 +1197,12 @@
                     }
                 }
             });
+
+            // Unbind previously bound workspace items to prevent a leak of AppWidgetHostViews.
+            final ArrayList<ItemInfo> workspaceItems = unbindWorkspaceItemsOnMainThread();
+
             // Add the items to the workspace.
-            N = sWorkspaceItems.size();
+            N = workspaceItems.size();
             for (int i=0; i<N; i+=ITEMS_CHUNK) {
                 final int start = i;
                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);
@@ -1174,16 +1210,18 @@
                     public void run() {
                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                         if (callbacks != null) {
-                            callbacks.bindItems(sWorkspaceItems, start, start+chunkSize);
+                            callbacks.bindItems(workspaceItems, start, start+chunkSize);
                         }
                     }
                 });
             }
+            // 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);
             mHandler.post(new Runnable() {
                 public void run() {
                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
-                        callbacks.bindFolders(sFolders);
+                        callbacks.bindFolders(folders);
                     }
                 }
             });