Don't lose icons when migrating from different-sized hotseats.

Launcher2 on sw720dp devices had 8 hotseat slots; Launcher3
has only 6 on those same devices. When importing the old
hotseat, the empty slot (so technically there were 9)
occupied by the all apps button didn't line up with the new
all apps button, causing a hole on the hotseat. Furthermore,
the icon in old position 3 was clobbered by the new all apps
icon:

    0 1 2 3 (#) 4 5 6 7 ==> 0 1 2 (:) _ 4 5

In this CL we introduce a separate sort-and-place step for
hotseat icons so that any icon colliding with the new
all-apps slot can be moved to the right to find the next
nearest open slot. This works well for the 8->6 case; it
will probably do something reasonable, if not ideal, for
other grid migration scenarios.

But those are not covered by this bug.

Bug: 13015468
Change-Id: I7edb3f27addc78ad02bbfcd1c39175ca56220007
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index b952729..a080dd8 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -50,6 +50,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -1578,6 +1579,7 @@
 
                         final ArrayList<ContentValues> shortcuts = new ArrayList<ContentValues>();
                         final ArrayList<ContentValues> folders = new ArrayList<ContentValues>();
+                        final SparseArray<ContentValues> hotseat = new SparseArray<ContentValues>();
 
                         while (c.moveToNext()) {
                             final int itemType = c.getInt(itemTypeIndex);
@@ -1593,7 +1595,11 @@
                             int container = c.getInt(containerIndex);
                             final String intentStr = c.getString(intentIndex);
                             Launcher.addDumpLog(TAG, "migrating \""
-                                + c.getString(titleIndex) + "\": " + intentStr, true);
+                                + c.getString(titleIndex) + "\" ("
+                                + cellX + "," + cellY + "@"
+                                + LauncherSettings.Favorites.containerToString(container)
+                                + "/" + screen
+                                + "): " + intentStr, true);
 
                             if (itemType != Favorites.ITEM_TYPE_FOLDER) {
 
@@ -1654,11 +1660,8 @@
                             values.put(LauncherSettings.Favorites.DISPLAY_MODE,
                                     c.getInt(displayModeIndex));
 
-                            if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
-                                    && (screen >= hotseatWidth ||
-                                        screen == grid.hotseatAllAppsRank)) {
-                                // no room for you in the hotseat? it's off to the desktop with you
-                                container = Favorites.CONTAINER_DESKTOP;
+                            if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+                                hotseat.put(screen, values);
                             }
 
                             if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
@@ -1680,6 +1683,31 @@
                             }
                         }
 
+                        // Now that we have all the hotseat icons, let's go through them left-right
+                        // and assign valid locations for them in the new hotseat
+                        final int N = hotseat.size();
+                        for (int idx=0; idx<N; idx++) {
+                            int hotseatX = hotseat.keyAt(idx);
+                            ContentValues values = hotseat.valueAt(idx);
+
+                            if (hotseatX == grid.hotseatAllAppsRank) {
+                                // let's drop this in the next available hole in the hotseat
+                                while (++hotseatX < hotseatWidth) {
+                                    if (hotseat.get(hotseatX) == null) {
+                                        // found a spot! move it here
+                                        values.put(LauncherSettings.Favorites.SCREEN,
+                                                hotseatX);
+                                        break;
+                                    }
+                                }
+                            }
+                            if (hotseatX >= hotseatWidth) {
+                                // no room for you in the hotseat? it's off to the desktop with you
+                                values.put(LauncherSettings.Favorites.CONTAINER,
+                                           Favorites.CONTAINER_DESKTOP);
+                            }
+                        }
+
                         final ArrayList<ContentValues> allItems = new ArrayList<ContentValues>();
                         // Folders first
                         allItems.addAll(folders);
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index f4ee300..2a768a2 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -171,6 +171,14 @@
         static final int CONTAINER_DESKTOP = -100;
         static final int CONTAINER_HOTSEAT = -101;
 
+        static final String containerToString(int container) {
+            switch (container) {
+                case CONTAINER_DESKTOP: return "desktop";
+                case CONTAINER_HOTSEAT: return "hotseat";
+                default: return String.valueOf(container);
+            }
+        }
+
         /**
          * The screen holding the favorite (if container is CONTAINER_DESKTOP)
          * <P>Type: INTEGER</P>