HACK: temporary upgrade path from com.android.launcher2

-> load old provider
-> permute pages
-> strip all duplicates from workspace
-> add [allapps minus workspaceapps] to apps folder

Change-Id: Id319d532c6bf1d78370ecc736e95a9475d831de8
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e205fea..fa9938f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -56,6 +56,8 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
+    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
     <uses-permission android:name="com.android.launcher3.permission.WRITE_SETTINGS" />
 
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index df55f04..7faa706 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -1565,13 +1565,13 @@
             }
         }
     }
-
     public void addApps(ArrayList<ApplicationInfo> list) {
         if (!DISABLE_ALL_APPS) {
             addAppsWithoutInvalidate(list);
             updatePageCountsAndInvalidateData();
         } else {
             // TODO: Maybe put them somewhere else?
+            mLauncher.getHotseat().addAppsToAllAppsFolder(list);
         }
     }
     private int findAppByComponent(List<ApplicationInfo> list, ApplicationInfo item) {
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index 1214806..07c9400 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -841,6 +841,16 @@
         LauncherModel.moveItemsInDatabase(mLauncher, items, mInfo.id, 0);
     }
 
+    public void addItemLocationsInDatabase() {
+        ArrayList<View> list = getItemsInReadingOrder();
+        for (int i = 0; i < list.size(); i++) {
+            View v = list.get(i);
+            ItemInfo info = (ItemInfo) v.getTag();
+            LauncherModel.addItemToDatabase(mLauncher, info, mInfo.id, 0,
+                        info.cellX, info.cellY, false);
+        }
+    }
+
     public void notifyDrop() {
         if (mDragInProgress) {
             mItemAddedBackToSelfViaIcon = true;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6a625eb..50f7efd 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -16,7 +16,9 @@
 
 package com.android.launcher3;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -28,6 +30,8 @@
 
 import com.android.launcher3.R;
 
+import java.util.ArrayList;
+
 public class Hotseat extends FrameLayout {
     @SuppressWarnings("unused")
     private static final String TAG = "Hotseat";
@@ -108,4 +112,52 @@
     void resetLayout() {
         mContent.removeAllViewsInLayout();
     }
+
+    void addAllAppsFolder(IconCache iconCache, ArrayList<ApplicationInfo> allApps,
+            ArrayList<ComponentName> onWorkspace, Launcher launcher) {
+        FolderInfo fi = new FolderInfo();
+
+        fi.cellX = getCellXFromOrder(mAllAppsButtonRank);
+        fi.cellY = getCellYFromOrder(mAllAppsButtonRank);
+        fi.spanX = 1;
+        fi.spanY = 1;
+        fi.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+        fi.screen = mAllAppsButtonRank;
+        fi.itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
+        fi.title = "All Apps";
+        LauncherModel.addItemToDatabase(launcher, fi, fi.container, fi.screen, fi.cellX,
+                fi.cellY, false);
+        FolderIcon folder = FolderIcon.fromXml(R.layout.folder_icon, launcher,
+                getLayout(), fi, iconCache);
+
+        CellLayout.LayoutParams lp = new CellLayout.LayoutParams(fi.cellX,fi.cellY,1,1);
+        mContent.addViewToCellLayout(folder, -1, 0, lp, true);
+
+        for (ApplicationInfo info: allApps) {
+            ComponentName cn = info.intent.getComponent();
+            if (!onWorkspace.contains(cn)) {
+                System.out.println("Adding to all apps: " + info.intent);
+                ShortcutInfo si = info.makeShortcut();
+                fi.add(si);
+            }
+        }
+    }
+
+    void addAppsToAllAppsFolder(ArrayList<ApplicationInfo> apps) {
+        View v = mContent.getChildAt(getCellXFromOrder(mAllAppsButtonRank), getCellYFromOrder(mAllAppsButtonRank));
+        FolderIcon fi = null;
+
+        if (v instanceof FolderIcon) {
+            fi = (FolderIcon) v;
+        } else {
+            return;
+        }
+
+        FolderInfo info = fi.getFolderInfo();
+        for (ApplicationInfo a: apps) {
+            ComponentName cn = a.intent.getComponent();
+            ShortcutInfo si = a.makeShortcut();
+            info.add(si);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 664b763..8526905 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -296,6 +296,8 @@
     // it from the context.
     private SharedPreferences mSharedPrefs;
 
+    private static ArrayList<ComponentName> mIntentsOnWorkspaceFromUpgradePath = null;
+
     // Holds the page that we need to animate to, and the icon views that we need to animate up
     // when we scroll to that page on resume.
     private int mNewShortcutAnimatePage = -1;
@@ -3535,10 +3537,10 @@
      *
      * Implementation of the method from LauncherModel.Callbacks.
      */
-    public void finishBindingItems() {
+    public void finishBindingItems(final boolean upgradePath) {
         if (waitUntilResume(new Runnable() {
                 public void run() {
-                    finishBindingItems();
+                    finishBindingItems(upgradePath);
                 }
             })) {
             return;
@@ -3590,6 +3592,13 @@
         }
 
         mWorkspaceLoading = false;
+        if (upgradePath) {
+            mWorkspace.saveWorkspaceToDb();
+
+            // Run through this twice... a little hackleberry, but the right solution is complex.
+            mWorkspace.stripDuplicateApps();
+            mIntentsOnWorkspaceFromUpgradePath = mWorkspace.stripDuplicateApps();
+        }
     }
 
     private boolean canRunNewAppsAnimation() {
@@ -3681,6 +3690,12 @@
             public void run() {
                 if (mAppsCustomizeContent != null) {
                     mAppsCustomizeContent.setApps(apps);
+
+                    if (mIntentsOnWorkspaceFromUpgradePath != null) {
+                        getHotseat().addAllAppsFolder(mIconCache, apps,
+                                mIntentsOnWorkspaceFromUpgradePath, Launcher.this);
+                        mIntentsOnWorkspaceFromUpgradePath = null;
+                    }
                 }
             }
         };
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index bbdff9e..bde4f7c 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -154,7 +154,7 @@
         public void startBinding();
         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end);
         public void bindFolders(HashMap<Long,FolderInfo> folders);
-        public void finishBindingItems();
+        public void finishBindingItems(boolean upgradePath);
         public void bindAppWidget(LauncherAppWidgetInfo info);
         public void bindAllApplications(ArrayList<ApplicationInfo> apps);
         public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
@@ -306,7 +306,8 @@
             if (stackTrace != null) {
                 e.setStackTrace(stackTrace);
             }
-            throw e;
+            // TODO: something breaks this in the upgrade path
+            //throw e;
         }
     }
 
@@ -1050,6 +1051,7 @@
         private boolean mIsLoadingAndBindingWorkspace;
         private boolean mStopped;
         private boolean mLoadAndBindStepFinished;
+        private boolean mIsUpgradePath;
 
         private HashMap<Object, CharSequence> mLabelCache;
 
@@ -1334,7 +1336,11 @@
             final boolean isSafeMode = manager.isSafeMode();
 
             // Make sure the default workspace is loaded, if needed
-            mApp.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);
+            boolean loadOldDb = mApp.getLauncherProvider().shouldLoadOldDb();
+            Uri contentUri = loadOldDb ? LauncherSettings.Favorites.OLD_CONTENT_URI :
+                    LauncherSettings.Favorites.CONTENT_URI;
+
+            mIsUpgradePath = loadOldDb;
 
             synchronized (sBgLock) {
                 sBgWorkspaceItems.clear();
@@ -1345,8 +1351,7 @@
 
                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();
 
-                final Cursor c = contentResolver.query(
-                        LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
+                final Cursor c = contentResolver.query(contentUri, null, null, null, null);
 
                 // +1 for the hotseat (it can be larger than the workspace)
                 // Load workspace in reverse order to ensure that latest items are loaded first (and
@@ -1437,7 +1442,6 @@
                                     info.screen = c.getInt(screenIndex);
                                     info.cellX = c.getInt(cellXIndex);
                                     info.cellY = c.getInt(cellYIndex);
-
                                     // check & update map of what's occupied
                                     if (!checkItemPlacement(occupied, info)) {
                                         break;
@@ -1455,6 +1459,10 @@
                                         folderInfo.add(info);
                                         break;
                                     }
+                                    if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
+                                            loadOldDb) {
+                                        info.screen = permuteScreens(info.screen);
+                                    }
                                     sBgItemsIdMap.put(info.id, info);
 
                                     // now that we've loaded everthing re-save it with the
@@ -1494,6 +1502,10 @@
                                         sBgWorkspaceItems.add(folderInfo);
                                         break;
                                 }
+                                if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
+                                        loadOldDb) {
+                                    folderInfo.screen = permuteScreens(folderInfo.screen);
+                                }
 
                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);
                                 sBgFolders.put(folderInfo.id, folderInfo);
@@ -1534,8 +1546,12 @@
                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
                                         continue;
                                     }
-                                    appWidgetInfo.container = c.getInt(containerIndex);
+                                    if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
+                                            loadOldDb) {
+                                        appWidgetInfo.screen = permuteScreens(appWidgetInfo.screen);
+                                    }
 
+                                    appWidgetInfo.container = c.getInt(containerIndex);
                                     // check & update map of what's occupied
                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {
                                         break;
@@ -1590,6 +1606,16 @@
             }
         }
 
+        // We rearrange the screens from the old launcher
+        // 12345 -> 34512
+        private int permuteScreens(int screen) {
+            if (screen >= 2) {
+                return screen - 2;
+            } else {
+                return screen + 3;
+            }
+        }
+
         /** Filters the set of items who are directly or indirectly (via another container) on the
          * specified screen. */
         private void filterCurrentWorkspaceItems(int currentScreen,
@@ -1867,7 +1893,7 @@
                 public void run() {
                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);
                     if (callbacks != null) {
-                        callbacks.finishBindingItems();
+                        callbacks.finishBindingItems(mIsUpgradePath);
                     }
 
                     // If we're profiling, ensure this is the last thing in the queue.
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index fb12f71..4c80b6b 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -68,6 +68,7 @@
 
     private static final int DATABASE_VERSION = 12;
 
+    static final String OLD_AUTHORITY = "com.android.launcher2.settings";
     static final String AUTHORITY = "com.android.launcher3.settings";
 
     static final String TABLE_FAVORITES = "favorites";
@@ -78,7 +79,7 @@
             "DEFAULT_WORKSPACE_RESOURCE_ID";
 
     private static final String ACTION_APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE =
-            "com.android.launcher3.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
+            "com.android.launcher.action.APPWIDGET_DEFAULT_WORKSPACE_CONFIGURE";
 
     /**
      * {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
@@ -206,11 +207,30 @@
     }
 
     /**
+     * @param Should we load the old db for upgrade? first run only.
+     */
+    synchronized public boolean shouldLoadOldDb() {
+        String spKey = LauncherApplication.getSharedPreferencesKey();
+        SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
+
+        boolean loadOldDb = false;
+        if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) {
+
+            SharedPreferences.Editor editor = sp.edit();
+            editor.remove(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED);
+            editor.commit();
+            loadOldDb = true;
+        }
+        return loadOldDb;
+    }
+
+    /**
      * @param workspaceResId that can be 0 to use default or non-zero for specific resource
      */
     synchronized public void loadDefaultFavoritesIfNecessary(int origWorkspaceResId) {
         String spKey = LauncherApplication.getSharedPreferencesKey();
         SharedPreferences sp = getContext().getSharedPreferences(spKey, Context.MODE_PRIVATE);
+
         if (sp.getBoolean(DB_CREATED_BUT_DEFAULT_WORKSPACE_NOT_LOADED, false)) {
             int workspaceResId = origWorkspaceResId;
 
@@ -225,6 +245,7 @@
             if (origWorkspaceResId != 0) {
                 editor.putInt(DEFAULT_WORKSPACE_RESOURCE_ID, origWorkspaceResId);
             }
+
             mOpenHelper.loadFavorites(mOpenHelper.getWritableDatabase(), workspaceResId);
             editor.commit();
         }
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 7d2b843..eb395c8 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -102,6 +102,13 @@
                 "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
 
         /**
+         * The content:// style URL for this table
+         */
+        static final Uri OLD_CONTENT_URI = Uri.parse("content://" +
+                LauncherProvider.OLD_AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES +
+                "?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
+
+        /**
          * The content:// style URL for this table. When this Uri is used, no notification is
          * sent if the content changes.
          */
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 4f1fb08..b4dc7d3 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3416,6 +3416,96 @@
         }
     }
 
+    ArrayList<ComponentName> stripDuplicateApps() {
+        ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();
+        stripDuplicateApps((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents);
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            CellLayout cl = (CellLayout) getChildAt(i);
+            stripDuplicateApps(cl, uniqueIntents);
+        }
+        return uniqueIntents;
+    }
+
+    void stripDuplicateApps(CellLayout cl,  ArrayList<ComponentName> uniqueIntents) {
+        int count = cl.getShortcutsAndWidgets().getChildCount();
+
+        ArrayList<View> children = new ArrayList<View>();
+        for (int i = 0; i < count; i++) {
+            View v = cl.getShortcutsAndWidgets().getChildAt(i);
+            children.add(v);
+        }
+
+        for (int i = 0; i < count; i++) {
+            View v = children.get(i);
+            ItemInfo info = (ItemInfo) v.getTag();
+            // Null check required as the AllApps button doesn't have an item info
+            if (info instanceof ShortcutInfo) {
+                ShortcutInfo si = (ShortcutInfo) info;
+                ComponentName cn = si.intent.getComponent();
+
+                if (!uniqueIntents.contains(cn)) {
+                    uniqueIntents.add(cn);
+                } else {
+                    cl.removeViewInLayout(v);
+                    LauncherModel.deleteItemFromDatabase(mLauncher, si);
+                }
+            }
+            if (v instanceof FolderIcon) {
+                FolderIcon fi = (FolderIcon) v;
+                ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();
+                for (int j = 0; j < items.size(); j++) {
+                    if (items.get(j).getTag() instanceof ShortcutInfo) {
+                        ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();
+                        ComponentName cn = si.intent.getComponent();
+
+                        if (!uniqueIntents.contains(cn)) {
+                            uniqueIntents.add(cn);
+                        } else {
+                            fi.getFolderInfo().remove(si);
+                            LauncherModel.deleteItemFromDatabase(mLauncher, si);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void saveWorkspaceToDb() {
+        saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            CellLayout cl = (CellLayout) getChildAt(i);
+            saveWorkspaceScreenToDb(cl);
+        }
+    }
+
+    void saveWorkspaceScreenToDb(CellLayout cl) {
+        int count = cl.getShortcutsAndWidgets().getChildCount();
+
+        int screen = indexOfChild(cl);
+        int container = Favorites.CONTAINER_DESKTOP;
+
+        if (mLauncher.isHotseatLayout(cl)) {
+            screen = -1;
+            container = Favorites.CONTAINER_HOTSEAT;
+        }
+
+        for (int i = 0; i < count; i++) {
+            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) {
+                LauncherModel.addItemToDatabase(mLauncher, info, container, screen, info.cellX,
+                        info.cellY, false);
+            }
+            if (v instanceof FolderIcon) {
+                FolderIcon fi = (FolderIcon) v;
+                fi.getFolder().addItemLocationsInDatabase();
+            }
+        }
+    }
+
     @Override
     public boolean supportsFlingToDelete() {
         return true;