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

Commit c0000450 authored by Tracy Zhou's avatar Tracy Zhou
Browse files

Support grid preview with v2 migration algorithm

The focus of ag/10346770 is around the actual algorithm, while in the meantime our preview logic has changed during the code review of ag/10100264.

GridSizeMigrationTaskV2 addresses both cases, the difference being preview passes in constructed IDP while actual migration uses IDP from the current Context.

When doing actual migration, we call METHOD_UPDATE_CURRENT_OPEN_HELPER to update the current db helper and copy the favorites table from the previous db into the current db in favorites_tmp table. Then we do migration from there.

When calculating preview, I added METHOD_PREP_FOR_PREVIEW in this change to copy the favorites table from the intended grid setting to the current grid setting in favorites_preview table. Then we calculate migration from the current favorites table to favorites_preview table and save into favorites_preview table.

Bug: 144052802
Fixes: 144052839

Test: Manual

Change-Id: I64a8b61a4e0bf8399c0ae1af4ef9d2bde0f1ee2f
parent ae581cdf
Loading
Loading
Loading
Loading
+43 −18
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.function.Supplier;

public class LauncherProvider extends ContentProvider {
    private static final String TAG = "LauncherProvider";
@@ -145,7 +146,7 @@ public class LauncherProvider extends ContentProvider {
     */
    protected synchronized void createDbIfNotExists() {
        if (mOpenHelper == null) {
            mOpenHelper = new DatabaseHelper(getContext());
            mOpenHelper = DatabaseHelper.createDatabaseHelper(getContext());

            if (RestoreDbTask.isPending(getContext())) {
                if (!RestoreDbTask.performRestore(getContext(), mOpenHelper,
@@ -159,17 +160,17 @@ public class LauncherProvider extends ContentProvider {
        }
    }

    private synchronized boolean updateCurrentOpenHelper() {
        final InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
        if (TextUtils.equals(idp.dbFile, mOpenHelper.getDatabaseName())) {
    private synchronized boolean prepForMigration(String dbFile, String targetTableName,
            Supplier<DatabaseHelper> src, Supplier<DatabaseHelper> dst) {
        if (TextUtils.equals(dbFile, mOpenHelper.getDatabaseName())) {
            return false;
        }

        DatabaseHelper oldHelper = mOpenHelper;
        mOpenHelper = new DatabaseHelper(getContext());
        copyTable(oldHelper.getReadableDatabase(), Favorites.TABLE_NAME,
                mOpenHelper.getWritableDatabase(), Favorites.TMP_TABLE, getContext());
        oldHelper.close();
        final DatabaseHelper helper = src.get();
        mOpenHelper = dst.get();
        copyTable(helper.getReadableDatabase(), Favorites.TABLE_NAME,
                mOpenHelper.getWritableDatabase(), targetTableName, getContext());
        helper.close();
        return true;
    }

@@ -425,7 +426,23 @@ public class LauncherProvider extends ContentProvider {
                if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
                    Bundle result = new Bundle();
                    result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
                            updateCurrentOpenHelper());
                            prepForMigration(
                                    InvariantDeviceProfile.INSTANCE.get(getContext()).dbFile,
                                    Favorites.TMP_TABLE,
                                    () -> mOpenHelper,
                                    () -> DatabaseHelper.createDatabaseHelper(getContext())));
                    return result;
                }
            }
            case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: {
                if (MULTI_DB_GRID_MIRATION_ALGO.get()) {
                    Bundle result = new Bundle();
                    result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE,
                            prepForMigration(
                                    arg /* dbFile */,
                                    Favorites.PREVIEW_TABLE_NAME,
                                    () -> DatabaseHelper.createDatabaseHelper(getContext(), arg),
                                    () -> mOpenHelper));
                    return result;
                }
            }
@@ -596,23 +613,31 @@ public class LauncherProvider extends ContentProvider {
        private int mMaxScreenId = -1;
        private boolean mBackupTableExists;

        DatabaseHelper(Context context) {
            this(context, MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
                    context).dbFile : LauncherFiles.LAUNCHER_DB);
        static DatabaseHelper createDatabaseHelper(Context context) {
            return createDatabaseHelper(context, null);
        }

        static DatabaseHelper createDatabaseHelper(Context context, String dbName) {
            if (dbName == null) {
                dbName = MULTI_DB_GRID_MIRATION_ALGO.get() ? InvariantDeviceProfile.INSTANCE.get(
                        context).dbFile : LauncherFiles.LAUNCHER_DB;
            }
            DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName);
            // Table creation sometimes fails silently, which leads to a crash loop.
            // This way, we will try to create a table every time after crash, so the device
            // would eventually be able to recover.
            if (!tableExists(getReadableDatabase(), Favorites.TABLE_NAME)) {
            if (!tableExists(databaseHelper.getReadableDatabase(), Favorites.TABLE_NAME)) {
                Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate");
                // This operation is a no-op if the table already exists.
                addFavoritesTable(getWritableDatabase(), true);
                databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true);
            }
            if (!MULTI_DB_GRID_MIRATION_ALGO.get()) {
                mBackupTableExists = tableExists(getReadableDatabase(),
                        Favorites.BACKUP_TABLE_NAME);
                databaseHelper.mBackupTableExists = tableExists(
                        databaseHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME);
            }

            initIds();
            databaseHelper.initIds();
            return databaseHelper;
        }

        /**
+7 −1
Original line number Diff line number Diff line
@@ -326,10 +326,16 @@ public class LauncherSettings {

        public static final String METHOD_UPDATE_CURRENT_OPEN_HELPER = "update_current_open_helper";

        public static final String METHOD_PREP_FOR_PREVIEW = "prep_for_preview";

        public static final String EXTRA_VALUE = "value";

        public static Bundle call(ContentResolver cr, String method) {
            return cr.call(CONTENT_URI, method, null, null);
            return call(cr, method, null);
        }

        public static Bundle call(ContentResolver cr, String method, String arg) {
            return cr.call(CONTENT_URI, method, arg, null);
        }
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.view.View.VISIBLE;

import static com.android.launcher3.config.FeatureFlags.ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER;
import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_ALGO;
import static com.android.launcher3.model.GridSizeMigrationTask.needsToMigrate;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.sortWorkspaceItemsSpatially;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -397,7 +396,10 @@ public class LauncherPreviewRenderer implements Callable<Bitmap> {

        private void populate() {
            if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
                boolean needsToMigrate = needsToMigrate(mContext, mIdp);
                boolean needsToMigrate =
                        MULTI_DB_GRID_MIRATION_ALGO.get()
                                ? GridSizeMigrationTaskV2.needsToMigrate(mContext, mIdp)
                                : GridSizeMigrationTask.needsToMigrate(mContext, mIdp);
                boolean success = false;
                if (needsToMigrate) {
                    success = MULTI_DB_GRID_MIRATION_ALGO.get()
+62 −30
Original line number Diff line number Diff line
@@ -123,8 +123,16 @@ public class GridSizeMigrationTaskV2 {
    }

    /**
     * Run the migration algorithm if needed. For preview, we provide the intended idp because it
     * has not been changed. If idp is null, we read it from the context, for actual grid migration.
     * When migrating the grid for preview, we copy the table
     * {@link LauncherSettings.Favorites.TABLE_NAME} into
     * {@link LauncherSettings.Favorites.PREVIEW_TABLE_NAME}, run grid size migration from the
     * former to the later, then use the later table for preview.
     *
     * Similarly when doing the actual grid migration, the former grid option's table
     * {@link LauncherSettings.Favorites.TABLE_NAME} is copied into the new grid option's
     * {@link LauncherSettings.Favorites.TMP_TABLE}, we then run the grid size migration algorithm
     * to migrate the later to the former, and load the workspace from the default
     * {@link LauncherSettings.Favorites.TABLE_NAME}.
     *
     * @return false if the migration failed.
     */
@@ -151,7 +159,14 @@ public class GridSizeMigrationTaskV2 {
        HashSet<String> validPackages = getValidPackages(context);
        int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);

        if (migrateForPreview) {
            if (!LauncherSettings.Settings.call(
                    context.getContentResolver(),
                    LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW, idp.dbFile).getBoolean(
                    LauncherSettings.Settings.EXTRA_VALUE)) {
                return false;
            }
        } else if (!LauncherSettings.Settings.call(
                context.getContentResolver(),
                LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER).getBoolean(
                LauncherSettings.Settings.EXTRA_VALUE)) {
@@ -164,9 +179,13 @@ public class GridSizeMigrationTaskV2 {
                LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder(
                LauncherSettings.Settings.EXTRA_VALUE)) {

            DbReader srcReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TMP_TABLE,
            DbReader srcReader = new DbReader(t.getDb(),
                    migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME
                            : LauncherSettings.Favorites.TMP_TABLE,
                    context, validPackages, srcHotseatCount);
            DbReader destReader = new DbReader(t.getDb(), LauncherSettings.Favorites.TABLE_NAME,
            DbReader destReader = new DbReader(t.getDb(),
                    migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME
                            : LauncherSettings.Favorites.TABLE_NAME,
                    context, validPackages, idp.numHotseatIcons);

            Point targetSize = new Point(idp.numColumns, idp.numRows);
@@ -174,7 +193,9 @@ public class GridSizeMigrationTaskV2 {
                    srcReader, destReader, idp.numHotseatIcons, targetSize);
            task.migrate();

            if (!migrateForPreview) {
                dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
            }

            t.commit();
            return true;
@@ -186,6 +207,7 @@ public class GridSizeMigrationTaskV2 {
            Log.v(TAG, "Workspace migration completed in "
                    + (System.currentTimeMillis() - migrationStartTime));

            if (!migrateForPreview) {
                // Save current configuration, so that the migration does not run again.
                prefs.edit()
                        .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
@@ -193,6 +215,7 @@ public class GridSizeMigrationTaskV2 {
                        .apply();
            }
        }
    }

    @VisibleForTesting
    protected boolean migrate() {
@@ -202,7 +225,7 @@ public class GridSizeMigrationTaskV2 {

        // Migrate hotseat
        HotseatPlacementSolution hotseatSolution = new HotseatPlacementSolution(mDb, mSrcReader,
                mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
                mDestReader, mContext, mDestHotseatSize, mHotseatItems, mHotseatDiff);
        hotseatSolution.find();

        // Sort the items by the reading order.
@@ -215,7 +238,7 @@ public class GridSizeMigrationTaskV2 {
            }
            List<DbEntry> entries = mDestReader.loadWorkspaceEntries(screenId);
            GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
                    mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
                    mDestReader, mContext, entries, screenId, mTrgX, mTrgY, mWorkspaceDiff);
            workspaceSolution.find();
            if (mWorkspaceDiff.isEmpty()) {
                break;
@@ -225,7 +248,8 @@ public class GridSizeMigrationTaskV2 {
        int screenId = mDestReader.mLastScreenId + 1;
        while (!mWorkspaceDiff.isEmpty()) {
            GridPlacementSolution workspaceSolution = new GridPlacementSolution(mDb, mSrcReader,
                    mContext, new ArrayList<>(), screenId, mTrgX, mTrgY, mWorkspaceDiff);
                    mDestReader, mContext, new ArrayList<>(), screenId, mTrgX, mTrgY,
                    mWorkspaceDiff);
            workspaceSolution.find();
            screenId++;
        }
@@ -246,7 +270,8 @@ public class GridSizeMigrationTaskV2 {
    }

    private static void insertEntryInDb(SQLiteDatabase db, Context context,
            ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry) {
            ArrayList<DbEntry> entriesFromSrcDb, DbEntry entry, String srcTableName,
            String destTableName) {
        int id = -1;
        switch (entry.itemType) {
            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
@@ -283,8 +308,8 @@ public class GridSizeMigrationTaskV2 {
                return;
        }

        Cursor c = db.query(LauncherSettings.Favorites.TMP_TABLE, null,
                LauncherSettings.Favorites._ID + " = '" + id + "'", null, null, null, null);
        Cursor c = db.query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + id + "'",
                null, null, null, null);

        while (c.moveToNext()) {
            ContentValues values = new ContentValues();
@@ -294,14 +319,14 @@ public class GridSizeMigrationTaskV2 {
                    LauncherSettings.Settings.call(context.getContentResolver(),
                            LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt(
                            LauncherSettings.Settings.EXTRA_VALUE));
            db.insert(LauncherSettings.Favorites.TABLE_NAME, null, values);
            db.insert(destTableName, null, values);
        }
        c.close();
    }

    private static void removeEntryFromDb(SQLiteDatabase db, IntArray entryId) {
        db.delete(LauncherSettings.Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
                LauncherSettings.Favorites._ID, entryId), null);
    private static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryId) {
        db.delete(tableName,
                Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryId), null);
    }

    private static HashSet<String> getValidPackages(Context context) {
@@ -325,6 +350,7 @@ public class GridSizeMigrationTaskV2 {

        private final SQLiteDatabase mDb;
        private final DbReader mSrcReader;
        private final DbReader mDestReader;
        private final Context mContext;
        private final GridOccupancy mOccupied;
        private final int mScreenId;
@@ -335,11 +361,12 @@ public class GridSizeMigrationTaskV2 {
        private int mNextStartX;
        private int mNextStartY;

        GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
                List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
        GridPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
                Context context, List<DbEntry> placedWorkspaceItems, int screenId, int trgX,
                int trgY, List<DbEntry> itemsToPlace) {
            mDb = db;
            mSrcReader = srcReader;
            mDestReader = destReader;
            mContext = context;
            mOccupied = new GridOccupancy(trgX, trgY);
            mScreenId = screenId;
@@ -362,7 +389,8 @@ public class GridSizeMigrationTaskV2 {
                    continue;
                }
                if (findPlacement(entry)) {
                    insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry);
                    insertEntryInDb(mDb, mContext, mSrcReader.mWorkspaceEntries, entry,
                            mSrcReader.mTableName, mDestReader.mTableName);
                    iterator.remove();
                }
            }
@@ -397,14 +425,17 @@ public class GridSizeMigrationTaskV2 {

        private final SQLiteDatabase mDb;
        private final DbReader mSrcReader;
        private final DbReader mDestReader;
        private final Context mContext;
        private final HotseatOccupancy mOccupied;
        private final List<DbEntry> mItemsToPlace;

        HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, Context context,
                int hotseatSize, List<DbEntry> placedHotseatItems, List<DbEntry> itemsToPlace) {
        HotseatPlacementSolution(SQLiteDatabase db, DbReader srcReader, DbReader destReader,
                Context context, int hotseatSize, List<DbEntry> placedHotseatItems,
                List<DbEntry> itemsToPlace) {
            mDb = db;
            mSrcReader = srcReader;
            mDestReader = destReader;
            mContext = context;
            mOccupied = new HotseatOccupancy(hotseatSize);
            for (DbEntry entry : placedHotseatItems) {
@@ -422,7 +453,8 @@ public class GridSizeMigrationTaskV2 {
                    // to something other than -1.
                    entry.cellX = i;
                    entry.cellY = 0;
                    insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry);
                    insertEntryInDb(mDb, mContext, mSrcReader.mHotseatEntries, entry,
                            mSrcReader.mTableName, mDestReader.mTableName);
                    mOccupied.markCells(entry, true);
                }
            }
@@ -519,7 +551,7 @@ public class GridSizeMigrationTaskV2 {
                }
                mHotseatEntries.add(entry);
            }
            removeEntryFromDb(mDb, entriesToRemove);
            removeEntryFromDb(mDb, mTableName, entriesToRemove);
            c.close();
            return mHotseatEntries;
        }
@@ -639,7 +671,7 @@ public class GridSizeMigrationTaskV2 {
                }
                mWorkspaceEntries.add(entry);
            }
            removeEntryFromDb(mDb, entriesToRemove);
            removeEntryFromDb(mDb, mTableName, entriesToRemove);
            c.close();
            return mWorkspaceEntries;
        }
@@ -657,7 +689,7 @@ public class GridSizeMigrationTaskV2 {
                    total++;
                    entry.mFolderItems.add(intent);
                } catch (Exception e) {
                    removeEntryFromDb(mDb, IntArray.wrap(c.getInt(0)));
                    removeEntryFromDb(mDb, mTableName, IntArray.wrap(c.getInt(0)));
                }
            }
            c.close();
+1 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ public class LauncherDbUtils {
            toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db");
            toDb.execSQL(
                    "INSERT INTO " + toTable + " SELECT * FROM from_db." + fromTable);
            toDb.execSQL("DETACH DATABASE 'from_db'");
        } else {
            toDb.execSQL("INSERT INTO " + toTable + " SELECT * FROM " + fromTable);
        }