Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b5b05b7 authored by Adam Cohen's avatar Adam Cohen Committed by Android (Google) Code Review
Browse files

Merge "New launcher2 icon migration algorithm." into jb-ub-now-kermit

parents 24fa33f8 d502404a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.launcher3">
    <uses-sdk android:targetSdkVersion="19" android:minSdkVersion="16"/>

    <permission
        android:name="com.android.launcher3.permission.PRELOAD_WORKSPACE"
+20 −0
Original line number Diff line number Diff line
@@ -130,6 +130,8 @@ public class Launcher extends Activity
    static final boolean DEBUG_RESUME_TIME = false;
    static final boolean DEBUG_DUMP_LOG = false;

    static final boolean ENABLE_DEBUG_INTENTS = false; // allow DebugIntents to run

    private static final int REQUEST_CREATE_SHORTCUT = 1;
    private static final int REQUEST_CREATE_APPWIDGET = 5;
    private static final int REQUEST_PICK_APPLICATION = 6;
@@ -1571,6 +1573,15 @@ public class Launcher extends Activity
            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                mUserPresent = true;
                updateRunning();
            } else if (ENABLE_DEBUG_INTENTS && DebugIntents.DELETE_DATABASE.equals(action)) {
                mModel.resetLoadedState(false, true);
                mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
                        LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE);
            } else if (ENABLE_DEBUG_INTENTS && DebugIntents.MIGRATE_DATABASE.equals(action)) {
                mModel.resetLoadedState(false, true);
                mModel.startLoader(false, PagedView.INVALID_RESTORE_PAGE,
                        LauncherModel.LOADER_FLAG_CLEAR_WORKSPACE
                                | LauncherModel.LOADER_FLAG_MIGRATE_SHORTCUTS);
            }
        }
    };
@@ -1583,6 +1594,10 @@ public class Launcher extends Activity
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        filter.addAction(Intent.ACTION_USER_PRESENT);
        if (ENABLE_DEBUG_INTENTS) {
            filter.addAction(DebugIntents.DELETE_DATABASE);
            filter.addAction(DebugIntents.MIGRATE_DATABASE);
        }
        registerReceiver(mReceiver, filter);
        FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
        mAttached = true;
@@ -4704,3 +4719,8 @@ interface LauncherTransitionable {
    void onLauncherTransitionStep(Launcher l, float t);
    void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace);
}

interface DebugIntents {
    static final String DELETE_DATABASE = "com.android.launcher3.action.DELETE_DATABASE";
    static final String MIGRATE_DATABASE = "com.android.launcher3.action.MIGRATE_DATABASE";
}
+27 −5
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@ public class LauncherModel extends BroadcastReceiver {
    // false = strew non-workspace apps across the workspace on upgrade
    public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;

    public static final int LOADER_FLAG_NONE = 0;
    public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;
    public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;

    private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
    private static final long INVALID_SCREEN_ID = -1L;
    private final boolean mAppsCanBeOnRemoveableStorage;
@@ -1193,6 +1197,10 @@ public class LauncherModel extends BroadcastReceiver {
    }

    public void startLoader(boolean isLaunching, int synchronousBindPage) {
        startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);
    }

    public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {
        synchronized (mLock) {
            if (DEBUG_LOADERS) {
                Log.d(TAG, "startLoader isLaunching=" + isLaunching);
@@ -1207,7 +1215,7 @@ public class LauncherModel extends BroadcastReceiver {
                // If there is already one running, tell it to stop.
                // also, don't downgrade isLaunching if we're already running
                isLaunching = isLaunching || stopLoaderLocked();
                mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching);
                mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);
                if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE
                        && mAllAppsLoaded && mWorkspaceLoaded) {
                    mLoaderTask.runBindSynchronousPage(synchronousBindPage);
@@ -1298,13 +1306,15 @@ public class LauncherModel extends BroadcastReceiver {
        private boolean mIsLoadingAndBindingWorkspace;
        private boolean mStopped;
        private boolean mLoadAndBindStepFinished;
        private int mFlags;

        private HashMap<Object, CharSequence> mLabelCache;

        LoaderTask(Context context, boolean isLaunching) {
        LoaderTask(Context context, boolean isLaunching, int flags) {
            mContext = context;
            mIsLaunching = isLaunching;
            mLabelCache = new HashMap<Object, CharSequence>();
            mFlags = flags;
        }

        boolean isLaunching() {
@@ -1651,7 +1661,7 @@ public class LauncherModel extends BroadcastReceiver {
            }
        }

        /** Returns whether this is an upgradge path */
        /** Returns whether this is an upgrade path */
        private boolean loadWorkspace() {
            // Log to disk
            Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);
@@ -1669,8 +1679,20 @@ public class LauncherModel extends BroadcastReceiver {
            int countX = (int) grid.numColumns;
            int countY = (int) grid.numRows;

            // Make sure the default workspace is loaded, if needed
            if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {
                Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);
                LauncherAppState.getLauncherProvider().deleteDatabase();
            }

            if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {
                // append the user's Launcher2 shortcuts
                Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);
                LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();
            } else {
                // Make sure the default workspace is loaded
                Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);
                LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);
            }

            // Check if we need to do any upgrade-path logic
            // (Includes having just imported default favorites)
+223 −1
Original line number Diff line number Diff line
@@ -55,9 +55,11 @@ import com.android.launcher3.config.ProviderConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class LauncherProvider extends ContentProvider {
@@ -72,7 +74,7 @@ public class LauncherProvider extends ContentProvider {
    static final String AUTHORITY = ProviderConfig.AUTHORITY;

    // Should we attempt to load anything from the com.android.launcher2 provider?
    static final boolean IMPORT_LAUNCHER2_DATABASE = true;
    static final boolean IMPORT_LAUNCHER2_DATABASE = false;

    static final String TABLE_FAVORITES = "favorites";
    static final String TABLE_WORKSPACE_SCREENS = "workspaceScreens";
@@ -133,6 +135,9 @@ public class LauncherProvider extends ContentProvider {

    private static long dbInsertAndCheck(DatabaseHelper helper,
            SQLiteDatabase db, String table, String nullColumnHack, ContentValues values) {
        if (values == null) {
            throw new RuntimeException("Error: attempting to insert null values");
        }
        if (!values.containsKey(LauncherSettings.Favorites._ID)) {
            throw new RuntimeException("Error: attempting to add item without specifying an id");
        }
@@ -287,6 +292,11 @@ public class LauncherProvider extends ContentProvider {
        }
    }

    public void migrateLauncher2Shortcuts() {
        mOpenHelper.migrateLauncher2Shortcuts(mOpenHelper.getWritableDatabase(),
                LauncherSettings.Favorites.OLD_CONTENT_URI);
    }

    private static int getDefaultWorkspaceResourceId() {
        if (LauncherAppState.isDisableAllApps()) {
            return R.xml.default_workspace_no_all_apps;
@@ -306,6 +316,15 @@ public class LauncherProvider extends ContentProvider {
        return !isTablet && IMPORT_LAUNCHER2_DATABASE;
    }

    public void deleteDatabase() {
        // Are you sure? (y/n)
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final String dbFile = db.getPath();
        mOpenHelper.close();
        SQLiteDatabase.deleteDatabase(new File(dbFile));
        mOpenHelper = new DatabaseHelper(getContext());
    }

    private static class DatabaseHelper extends SQLiteOpenHelper {
        private static final String TAG_FAVORITES = "favorites";
        private static final String TAG_FAVORITE = "favorite";
@@ -1431,6 +1450,209 @@ public class LauncherProvider extends ContentProvider {
            }
            return id;
        }

        public void migrateLauncher2Shortcuts(SQLiteDatabase db, Uri uri) {
            final ContentResolver resolver = mContext.getContentResolver();
            Cursor c = null;
            int count = 0;
            int curScreen = 0;

            try {
                c = resolver.query(uri, null, null, null, "title ASC");
            } catch (Exception e) {
                // Ignore
            }


            // We already have a favorites database in the old provider
            if (c != null) {
                try {
                    if (c.getCount() > 0) {
                        final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
                        final int intentIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
                        final int titleIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
                        final int iconTypeIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
                        final int iconIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
                        final int iconPackageIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
                        final int iconResourceIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
                        final int containerIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
                        final int itemTypeIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
                        final int screenIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
                        final int cellXIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
                        final int cellYIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
                        final int uriIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
                        final int displayModeIndex
                                = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);

                        int i = 0;
                        int curX = 0;
                        int curY = 0;

                        final LauncherAppState app = LauncherAppState.getInstance();
                        final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
                        final int width = (int) grid.numColumns;
                        final int height = (int) grid.numRows;
                        final int hotseatWidth = (int) grid.numHotseatIcons;

                        final HashSet<String> seenIntents = new HashSet<String>(c.getCount());

                        final ContentValues[] rows = new ContentValues[c.getCount()];

                        while (c.moveToNext()) {
                            final int itemType = c.getInt(itemTypeIndex);
                            if (itemType != Favorites.ITEM_TYPE_APPLICATION
                                    && itemType != Favorites.ITEM_TYPE_SHORTCUT
                                    && itemType != Favorites.ITEM_TYPE_FOLDER) {
                                continue;
                            }

                            final int cellX = c.getInt(cellXIndex);
                            final int cellY = c.getInt(cellYIndex);
                            final int screen = c.getInt(screenIndex);
                            int container = c.getInt(containerIndex);
                            final String intentStr = c.getString(intentIndex);
                            Launcher.addDumpLog(TAG, "migrating \""
                                + c.getString(titleIndex) + "\": " + intentStr, true);

                            if (itemType != Favorites.ITEM_TYPE_FOLDER) {
                                if (TextUtils.isEmpty(intentStr)) {
                                    // no intent? no icon
                                    Launcher.addDumpLog(TAG, "skipping empty intent", true);
                                    continue;
                                } else {
                                    try {
                                        // Canonicalize
                                        final Intent intent = Intent.parseUri(intentStr, 0);
                                        // the Play Store sets the package parameter, but Launcher
                                        // does not, so we clear that out to keep them the same
                                        intent.setPackage(null);
                                        final String key = intent.toUri(0);
                                        if (seenIntents.contains(key)) {
                                            Launcher.addDumpLog(TAG, "skipping duplicate", true);
                                            continue;
                                        } else {
                                            seenIntents.add(key);
                                        }
                                    } catch (URISyntaxException e) {
                                        // bogus intent?
                                        Launcher.addDumpLog(TAG,
                                                "skipping invalid intent uri", true);
                                        continue;
                                    }
                                }
                            }

                            ContentValues values = new ContentValues(c.getColumnCount());
                            values.put(LauncherSettings.Favorites._ID, c.getInt(idIndex));
                            values.put(LauncherSettings.Favorites.INTENT, intentStr);
                            values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
                            values.put(LauncherSettings.Favorites.ICON_TYPE,
                                    c.getInt(iconTypeIndex));
                            values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex));
                            values.put(LauncherSettings.Favorites.ICON_PACKAGE,
                                    c.getString(iconPackageIndex));
                            values.put(LauncherSettings.Favorites.ICON_RESOURCE,
                                    c.getString(iconResourceIndex));
                            values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType);
                            values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
                            values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex));
                            values.put(LauncherSettings.Favorites.DISPLAY_MODE,
                                    c.getInt(displayModeIndex));

                            if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
                                    && screen >= hotseatWidth) {
                                // no room for you in the hotseat? it's off to the desktop with you
                                container = Favorites.CONTAINER_DESKTOP;
                            }

                            if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
                                // In a folder or in the hotseat, preserve position
                                values.put(LauncherSettings.Favorites.SCREEN, screen);
                                values.put(LauncherSettings.Favorites.CELLX, cellX);
                                values.put(LauncherSettings.Favorites.CELLY, cellY);
                            } else {
                                values.put(LauncherSettings.Favorites.SCREEN, curScreen);
                                values.put(LauncherSettings.Favorites.CELLX, curX);
                                values.put(LauncherSettings.Favorites.CELLY, curY);
                                curX = (curX + 1) % width;
                                if (curX == 0) {
                                    curY = (curY + 1);
                                }
                                // Leave the last row of icons blank on screen 0
                                if (curScreen == 0 && curY == height - 1 || curY == height) {
                                    curScreen = (int) generateNewScreenId();
                                    curY = 0;
                                }
                            }

                            values.put(LauncherSettings.Favorites.CONTAINER, container);

                            rows[i++] = values;
                        }

                        if (i > 0) {
                            db.beginTransaction();
                            try {
                                final int N = rows.length;
                                for (i = 0; i < N; i++) {
                                    if (rows[i] == null) continue;
                                    if (dbInsertAndCheck(this, db, TABLE_FAVORITES, null, rows[i])
                                            < 0) {
                                        return;
                                    } else {
                                        count++;
                                    }
                                }
                                db.setTransactionSuccessful();
                            } finally {
                                db.endTransaction();
                            }
                        }

                        db.beginTransaction();
                        try {
                            for (i=0; i<=curScreen; i++) {
                                final ContentValues values = new ContentValues();
                                values.put(LauncherSettings.WorkspaceScreens._ID, i);
                                values.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
                                if (dbInsertAndCheck(this, db, TABLE_WORKSPACE_SCREENS, null, values)
                                        < 0) {
                                    return;
                                }
                            }
                            db.setTransactionSuccessful();
                        } finally {
                            db.endTransaction();
                        }
                    }
                } finally {
                    c.close();
                }
            }

            Launcher.addDumpLog(TAG, "migrated " + count + " icons from Launcher2 into "
                    + (curScreen+1) + " screens", true);

            // ensure that new screens are created to hold these icons
            setFlagJustLoadedOldDb();

            // Update max IDs; very important since we just grabbed IDs from another database
            mMaxItemId = initializeMaxItemId(db);
            mMaxScreenId = initializeMaxScreenId(db);
            if (LOGD) Log.d(TAG, "mMaxItemId: " + mMaxItemId + " mMaxScreenId: " + mMaxScreenId);
        }
    }

    /**