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
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index a699c32..8d20bd6 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -85,6 +85,7 @@
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 @@
*/
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 @@
}
}
- 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 @@
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 @@
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;
}
/**
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index f516446..5262b18 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -326,10 +326,16 @@
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);
}
}
}
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 5bc6610..7d4eb0e 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -21,7 +21,6 @@
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 @@
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()
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
index 0bdccfa..79ae4c5 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTaskV2.java
@@ -123,8 +123,16 @@
}
/**
- * 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 @@
HashSet<String> validPackages = getValidPackages(context);
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
- if (!LauncherSettings.Settings.call(
+ 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 @@
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 @@
srcReader, destReader, idp.numHotseatIcons, targetSize);
task.migrate();
- dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
+ if (!migrateForPreview) {
+ dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE);
+ }
t.commit();
return true;
@@ -186,11 +207,13 @@
Log.v(TAG, "Workspace migration completed in "
+ (System.currentTimeMillis() - migrationStartTime));
- // Save current configuration, so that the migration does not run again.
- prefs.edit()
- .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
- .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
- .apply();
+ if (!migrateForPreview) {
+ // Save current configuration, so that the migration does not run again.
+ prefs.edit()
+ .putString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)
+ .putInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)
+ .apply();
+ }
}
}
@@ -202,7 +225,7 @@
// 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 @@
}
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
}
mHotseatEntries.add(entry);
}
- removeEntryFromDb(mDb, entriesToRemove);
+ removeEntryFromDb(mDb, mTableName, entriesToRemove);
c.close();
return mHotseatEntries;
}
@@ -639,7 +671,7 @@
}
mWorkspaceEntries.add(entry);
}
- removeEntryFromDb(mDb, entriesToRemove);
+ removeEntryFromDb(mDb, mTableName, entriesToRemove);
c.close();
return mWorkspaceEntries;
}
@@ -657,7 +689,7 @@
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();
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index dacea84..7e05a5a 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -129,6 +129,7 @@
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);
}