From 3772b246c2971d93f1b64755dd9249efe4828af1 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Sat, 6 May 2023 18:18:07 +0000 Subject: [PATCH] Revert "Revert "Revert "Changing GridMigrationTask to use ModelDbController directly""" This reverts commit 8d9e468dbb30a3a036b314dc599164d540f9c442. Reason for revert: b/281179368 Change-Id: Ibfc5329f72cdbcb37d01a8bf3dac2ba0724b9faf --- .../launcher3/AppWidgetsRestoredReceiver.java | 8 +- .../android/launcher3/LauncherProvider.java | 12 + .../android/launcher3/LauncherSettings.java | 26 +- .../graphics/PreviewSurfaceRenderer.java | 34 +-- .../launcher3/model/DatabaseHelper.java | 82 +++++- .../model/GridSizeMigrationUtil.java | 131 ++++++--- .../android/launcher3/model/LoaderCursor.java | 22 +- .../android/launcher3/model/LoaderTask.java | 100 ++++--- .../launcher3/model/ModelDbController.java | 139 ++++----- .../launcher3/provider/LauncherDbUtils.java | 2 +- .../launcher3/provider/RestoreDbTask.java | 34 +-- .../android/launcher3/util/ContentWriter.java | 10 +- .../model/DbDowngradeHelperTest.java | 5 +- .../model/GridSizeMigrationUtilTest.kt | 275 +++++++----------- .../launcher3/model/LoaderCursorTest.java | 3 +- .../provider/LauncherDbUtilsTest.java | 6 +- .../launcher3/provider/RestoreDbTaskTest.java | 56 ++-- .../launcher3/util/LauncherModelHelper.java | 8 +- 18 files changed, 505 insertions(+), 448 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index 5fbd48cdaf..f041ffbe6c 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -16,8 +16,8 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.LoaderTask; -import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.pm.UserCache; @@ -52,7 +52,7 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { * Updates the app widgets whose id has changed during the restore process. */ @WorkerThread - public static void restoreAppWidgetIds(Context context, ModelDbController controller, + public static void restoreAppWidgetIds(Context context, DatabaseHelper helper, int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) { if (WidgetsModel.GO_DISABLE_WIDGETS) { Log.e(TAG, "Skipping widget ID remap as widgets not supported"); @@ -92,12 +92,12 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?"; final String[] args = new String[] { oldWidgetId, Long.toString(mainProfileId) }; int result = new ContentWriter(context, - new ContentWriter.CommitParams(controller, where, args)) + new ContentWriter.CommitParams(helper, where, args)) .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]) .put(LauncherSettings.Favorites.RESTORED, state) .commit(); if (result == 0) { - Cursor cursor = controller.getDb().query( + Cursor cursor = helper.getWritableDatabase().query( Favorites.TABLE_NAME, new String[] {Favorites.APPWIDGET_ID}, "appWidgetId=?", new String[] { oldWidgetId }, null, null, null); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 9abec505c7..0df4bd409e 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -263,6 +263,18 @@ public class LauncherProvider extends ContentProvider { getModelDbController().refreshHotseatRestoreTable(); return null; } + case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: { + Bundle result = new Bundle(); + result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, + getModelDbController().updateCurrentOpenHelper(arg /* dbFile */)); + return result; + } + case LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW: { + Bundle result = new Bundle(); + result.putBoolean(LauncherSettings.Settings.EXTRA_VALUE, + getModelDbController().prepareForPreview(arg /* dbFile */)); + return result; + } } return null; } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 7fda326ec2..b65e96ba52 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -147,6 +147,11 @@ public class LauncherSettings { */ public static final String HYBRID_HOTSEAT_BACKUP_TABLE = "hotseat_restore_backup"; + /** + * Temporary table used specifically for grid migrations during wallpaper preview + */ + public static final String PREVIEW_TABLE_NAME = "favorites_preview"; + /** * Temporary table used specifically for multi-db grid migrations */ @@ -158,6 +163,18 @@ public class LauncherSettings { public static final Uri CONTENT_URI = Uri.parse("content://" + LauncherProvider.AUTHORITY + "/" + TABLE_NAME); + /** + * The content:// style URL for "favorites_preview" table + */ + public static final Uri PREVIEW_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + PREVIEW_TABLE_NAME); + + /** + * The content:// style URL for "favorites_tmp" table + */ + public static final Uri TMP_CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + TMP_TABLE); + /** * The content:// style URL for a given row, identified by its id. * @@ -359,6 +376,10 @@ public class LauncherSettings { public static final String METHOD_REFRESH_HOTSEAT_RESTORE_TABLE = "restore_hotseat_table"; + 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 final String EXTRA_DB_NAME = "db_name"; @@ -372,8 +393,11 @@ public class LauncherSettings { } public static Bundle call(ContentResolver cr, String method, String arg) { - return cr.call(CONTENT_URI, method, arg, null); + return call(cr, method, arg, null /* extras */); } + public static Bundle call(ContentResolver cr, String method, String arg, Bundle extras) { + return cr.call(CONTENT_URI, method, arg, extras); + } } } diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 8f0b8ec531..372e9bf2e9 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -16,7 +16,6 @@ package com.android.launcher3.graphics; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -53,8 +52,6 @@ import com.android.launcher3.graphics.LauncherPreviewRenderer.PreviewContext; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.GridSizeMigrationUtil; import com.android.launcher3.model.LoaderTask; -import com.android.launcher3.model.ModelDbController; -import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; @@ -148,9 +145,7 @@ public class PreviewSurfaceRenderer { final String query = LauncherSettings.Favorites.ITEM_TYPE + " = " + LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET; - ModelDbController mainController = - LauncherAppState.getInstance(mContext).getModel().getModelDbController(); - try (Cursor c = mainController.query(TABLE_NAME, + try (Cursor c = context.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, new String[] { LauncherSettings.Favorites.APPWIDGET_ID, LauncherSettings.Favorites.SPANX, @@ -195,6 +190,8 @@ public class PreviewSurfaceRenderer { @WorkerThread private void loadModelData() { + final boolean migrated = doGridMigrationIfNecessary(); + final Context inflationContext; if (mWallpaperColors != null) { // Create a themed context, without affecting the main application context @@ -212,20 +209,8 @@ public class PreviewSurfaceRenderer { Themes.getActivityThemeRes(mContext)); } - if (GridSizeMigrationUtil.needsToMigrate(inflationContext, mIdp)) { - // Start the migration + if (migrated) { PreviewContext previewContext = new PreviewContext(inflationContext, mIdp); - // Copy existing data to preview DB - LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext) - .getModel().getModelDbController().getDb(), - TABLE_NAME, - LauncherAppState.getInstance(previewContext) - .getModel().getModelDbController().getDb(), - TABLE_NAME, - mContext); - LauncherAppState.getInstance(previewContext) - .getModel().getModelDbController().clearEmptyDbFlag(); - new LoaderTask( LauncherAppState.getInstance(previewContext), /* bgAllAppsList= */ null, @@ -244,7 +229,8 @@ public class PreviewSurfaceRenderer { query += " or " + LauncherSettings.Favorites.SCREEN + " = " + Workspace.SECOND_SCREEN_ID; } - loadWorkspace(new ArrayList<>(), query, null); + loadWorkspaceForPreviewSurfaceRenderer(new ArrayList<>(), + LauncherSettings.Favorites.PREVIEW_CONTENT_URI, query); final SparseArray spanInfo = getLoadedLauncherWidgetInfo(previewContext.getBaseContext()); @@ -267,6 +253,14 @@ public class PreviewSurfaceRenderer { } } + @WorkerThread + private boolean doGridMigrationIfNecessary() { + if (!GridSizeMigrationUtil.needsToMigrate(mContext, mIdp)) { + return false; + } + return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, mIdp); + } + @UiThread private void renderView(Context inflationContext, BgDataModel dataModel, Map widgetProviderInfoMap, diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java index ecf5f67a97..dc5fcf7d4b 100644 --- a/src/com/android/launcher3/model/DatabaseHelper.java +++ b/src/com/android/launcher3/model/DatabaseHelper.java @@ -15,8 +15,8 @@ */ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; +import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.content.ContentValues; import android.content.Context; @@ -36,6 +36,9 @@ import androidx.annotation.NonNull; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherFiles; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; @@ -55,7 +58,6 @@ import java.io.File; import java.net.URISyntaxException; import java.util.Arrays; import java.util.Locale; -import java.util.function.ToLongFunction; import java.util.stream.Collectors; /** @@ -74,23 +76,45 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements private static final boolean LOGD = false; private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json"; + public static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; private final Context mContext; - private final ToLongFunction mUserSerialProvider; - private final Runnable mOnEmptyDbCreateCallback; - + private final boolean mForMigration; private int mMaxItemId = -1; public boolean mHotseatRestoreTableExists; + public static DatabaseHelper createDatabaseHelper(Context context, boolean forMigration) { + return createDatabaseHelper(context, null, forMigration); + } + + public static DatabaseHelper createDatabaseHelper(Context context, String dbName, + boolean forMigration) { + if (dbName == null) { + dbName = InvariantDeviceProfile.INSTANCE.get(context).dbFile; + } + DatabaseHelper databaseHelper = new DatabaseHelper(context, dbName, forMigration); + // 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(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. + databaseHelper.addFavoritesTable(databaseHelper.getWritableDatabase(), true); + } + databaseHelper.mHotseatRestoreTableExists = tableExists( + databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); + + databaseHelper.initIds(); + return databaseHelper; + } + /** * Constructor used in tests and for restore. */ - public DatabaseHelper(Context context, String dbName, - ToLongFunction userSerialProvider, Runnable onEmptyDbCreateCallback) { + public DatabaseHelper(Context context, String dbName, boolean forMigration) { super(context, dbName, SCHEMA_VERSION); mContext = context; - mUserSerialProvider = userSerialProvider; - mOnEmptyDbCreateCallback = onEmptyDbCreateCallback; + mForMigration = forMigration; } protected void initIds() { @@ -107,11 +131,13 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements mMaxItemId = 1; - addTableToDb(db, getDefaultUserSerial(), false /* optional */); + addFavoritesTable(db, false); // Fresh and clean launcher DB. mMaxItemId = initializeMaxItemId(db); - mOnEmptyDbCreateCallback.run(); + if (!mForMigration) { + onEmptyDbCreated(); + } } public void onAddOrDeleteOp(SQLiteDatabase db) { @@ -121,8 +147,38 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements } } - private long getDefaultUserSerial() { - return mUserSerialProvider.applyAsLong(Process.myUserHandle()); + /** + * Re-composite given key in respect to database. If the current db is + * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to + * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning + * string will be "EMPTY_DATABASE_CREATED@minimal.db". + */ + public String getKey(final String key) { + if (TextUtils.equals(getDatabaseName(), LauncherFiles.LAUNCHER_DB)) { + return key; + } + return key + "@" + getDatabaseName(); + } + + /** + * Overridden in tests. + */ + protected void onEmptyDbCreated() { + // Set the flag for empty DB + LauncherPrefs.getPrefs(mContext).edit().putBoolean(getKey(EMPTY_DATABASE_CREATED), true) + .commit(); + } + + public long getSerialNumberForUser(UserHandle user) { + return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); + } + + public long getDefaultUserSerial() { + return getSerialNumberForUser(Process.myUserHandle()); + } + + private void addFavoritesTable(SQLiteDatabase db, boolean optional) { + Favorites.addTableToDb(db, getDefaultUserSerial(), optional); } @Override diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index 9a6cde63cd..eded5ea6a9 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -16,9 +16,6 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; -import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE; -import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import android.content.ComponentName; @@ -37,15 +34,16 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.graphics.LauncherPreviewRenderer; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.WidgetManagerHelper; @@ -91,38 +89,81 @@ public class GridSizeMigrationUtil { return needsToMigrate; } + /** See {@link #migrateGridIfNeeded(Context, InvariantDeviceProfile)} */ + public static boolean migrateGridIfNeeded(Context context) { + if (context instanceof LauncherPreviewRenderer.PreviewContext) { + return true; + } + return migrateGridIfNeeded(context, null); + } + /** - * When migrating the grid, we copy the table - * {@link LauncherSettings.Favorites#TABLE_NAME} from {@code source} into - * {@link LauncherSettings.Favorites#TMP_TABLE}, run the grid size migration algorithm + * 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. */ - public static boolean migrateGridIfNeeded( - @NonNull Context context, - @NonNull InvariantDeviceProfile idp, - @NonNull DatabaseHelper target, - @NonNull SQLiteDatabase source) { + public static boolean migrateGridIfNeeded(Context context, InvariantDeviceProfile idp) { + boolean migrateForPreview = idp != null; + if (!migrateForPreview) { + idp = LauncherAppState.getIDP(context); + } DeviceGridState srcDeviceState = new DeviceGridState(context); DeviceGridState destDeviceState = new DeviceGridState(idp); if (!needsToMigrate(srcDeviceState, destDeviceState)) { return true; } - copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context); HashSet validPackages = getValidPackages(context); + + if (migrateForPreview) { + if (!LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_PREP_FOR_PREVIEW, + destDeviceState.getDbFile()).getBoolean( + LauncherSettings.Settings.EXTRA_VALUE)) { + return false; + } + } else if (!LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER, + destDeviceState.getDbFile()).getBoolean( + LauncherSettings.Settings.EXTRA_VALUE)) { + return false; + } + long migrationStartTime = System.currentTimeMillis(); - try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) { - DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context, validPackages); - DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context, validPackages); + try (SQLiteTransaction t = (SQLiteTransaction) LauncherSettings.Settings.call( + context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_TRANSACTION).getBinder( + LauncherSettings.Settings.EXTRA_VALUE)) { + + DbReader srcReader = new DbReader(t.getDb(), + migrateForPreview ? LauncherSettings.Favorites.TABLE_NAME + : LauncherSettings.Favorites.TMP_TABLE, + context, validPackages); + DbReader destReader = new DbReader(t.getDb(), + migrateForPreview ? LauncherSettings.Favorites.PREVIEW_TABLE_NAME + : LauncherSettings.Favorites.TABLE_NAME, + context, validPackages); Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows()); - migrate(target, srcReader, destReader, destDeviceState.getNumHotseat(), + migrate(context, t.getDb(), srcReader, destReader, destDeviceState.getNumHotseat(), targetSize, srcDeviceState, destDeviceState); - dropTable(t.getDb(), TMP_TABLE); + + if (!migrateForPreview) { + dropTable(t.getDb(), LauncherSettings.Favorites.TMP_TABLE); + } + t.commit(); return true; } catch (Exception e) { @@ -133,7 +174,7 @@ public class GridSizeMigrationUtil { Log.v(TAG, "Workspace migration completed in " + (System.currentTimeMillis() - migrationStartTime)); - if (!(context instanceof SandboxContext)) { + if (!migrateForPreview) { // Save current configuration, so that the migration does not run again. destDeviceState.writeToPrefs(context); } @@ -141,7 +182,7 @@ public class GridSizeMigrationUtil { } public static boolean migrate( - @NonNull DatabaseHelper helper, + @NonNull final Context context, @NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, final int destHotseatSize, @NonNull final Point targetSize, @NonNull final DeviceGridState srcDeviceState, @@ -193,8 +234,8 @@ public class GridSizeMigrationUtil { Collections.sort(workspaceToBeAdded); // Migrate hotseat - solveHotseatPlacement(helper, destHotseatSize, - srcReader, destReader, dstHotseatItems, hotseatToBeAdded); + solveHotseatPlacement(db, srcReader, + destReader, context, destHotseatSize, dstHotseatItems, hotseatToBeAdded); // Migrate workspace. // First we create a collection of the screens @@ -214,8 +255,8 @@ public class GridSizeMigrationUtil { if (DEBUG) { Log.d(TAG, "Migrating " + screenId); } - solveGridPlacement(helper, srcReader, - destReader, screenId, trgX, trgY, workspaceToBeAdded, false); + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, false); if (workspaceToBeAdded.isEmpty()) { break; } @@ -225,8 +266,8 @@ public class GridSizeMigrationUtil { // any of the screens, in this case we add them to new screens until all of them are placed. int screenId = destReader.mLastScreenId + 1; while (!workspaceToBeAdded.isEmpty()) { - solveGridPlacement(helper, srcReader, - destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages); + solveGridPlacement(db, srcReader, + destReader, context, screenId, trgX, trgY, workspaceToBeAdded, preservePages); screenId++; } @@ -257,33 +298,33 @@ public class GridSizeMigrationUtil { }); } - private static void insertEntryInDb(DatabaseHelper helper, DbEntry entry, + private static void insertEntryInDb(SQLiteDatabase db, Context context, DbEntry entry, String srcTableName, String destTableName) { - int id = copyEntryAndUpdate(helper, entry, srcTableName, destTableName); + int id = copyEntryAndUpdate(db, context, entry, srcTableName, destTableName); if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) { for (Set itemIds : entry.mFolderItems.values()) { for (int itemId : itemIds) { - copyEntryAndUpdate(helper, itemId, id, srcTableName, destTableName); + copyEntryAndUpdate(db, context, itemId, id, srcTableName, destTableName); } } } } - private static int copyEntryAndUpdate(DatabaseHelper helper, + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, DbEntry entry, String srcTableName, String destTableName) { - return copyEntryAndUpdate(helper, entry, -1, -1, srcTableName, destTableName); + return copyEntryAndUpdate(db, context, entry, -1, -1, srcTableName, destTableName); } - private static int copyEntryAndUpdate(DatabaseHelper helper, + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, int id, int folderId, String srcTableName, String destTableName) { - return copyEntryAndUpdate(helper, null, id, folderId, srcTableName, destTableName); + return copyEntryAndUpdate(db, context, null, id, folderId, srcTableName, destTableName); } - private static int copyEntryAndUpdate(DatabaseHelper helper, DbEntry entry, - int id, int folderId, String srcTableName, String destTableName) { + private static int copyEntryAndUpdate(SQLiteDatabase db, Context context, + DbEntry entry, int id, int folderId, String srcTableName, String destTableName) { int newId = -1; - Cursor c = helper.getWritableDatabase().query(srcTableName, null, + Cursor c = db.query(srcTableName, null, LauncherSettings.Favorites._ID + " = '" + (entry != null ? entry.id : id) + "'", null, null, null, null); while (c.moveToNext()) { @@ -294,9 +335,11 @@ public class GridSizeMigrationUtil { } else { values.put(LauncherSettings.Favorites.CONTAINER, folderId); } - newId = helper.generateNewItemId(); + newId = LauncherSettings.Settings.call(context.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_ITEM_ID).getInt( + LauncherSettings.Settings.EXTRA_VALUE); values.put(LauncherSettings.Favorites._ID, newId); - helper.getWritableDatabase().insert(destTableName, null, values); + db.insert(destTableName, null, values); } c.close(); return newId; @@ -324,9 +367,9 @@ public class GridSizeMigrationUtil { return validPackages; } - private static void solveGridPlacement(@NonNull final DatabaseHelper helper, + private static void solveGridPlacement(@NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, - final int screenId, final int trgX, final int trgY, + @NonNull final Context context, final int screenId, final int trgX, final int trgY, @NonNull final List sortedItemsToPlace, final boolean matchingScreenIdOnly) { final GridOccupancy occupied = new GridOccupancy(trgX, trgY); final Point trg = new Point(trgX, trgY); @@ -348,7 +391,7 @@ public class GridSizeMigrationUtil { continue; } if (findPlacementForEntry(entry, next, trg, occupied, screenId)) { - insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); iterator.remove(); } } @@ -385,9 +428,9 @@ public class GridSizeMigrationUtil { return false; } - private static void solveHotseatPlacement( - @NonNull final DatabaseHelper helper, final int hotseatSize, + private static void solveHotseatPlacement(@NonNull final SQLiteDatabase db, @NonNull final DbReader srcReader, @NonNull final DbReader destReader, + @NonNull final Context context, final int hotseatSize, @NonNull final List placedHotseatItems, @NonNull final List itemsToPlace) { @@ -404,7 +447,7 @@ public class GridSizeMigrationUtil { // to something other than -1. entry.cellX = i; entry.cellY = 0; - insertEntryInDb(helper, entry, srcReader.mTableName, destReader.mTableName); + insertEntryInDb(db, context, entry, srcReader.mTableName, destReader.mTableName); occupied[entry.screenId] = true; } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 2054d930e6..a5dccc1fab 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -16,16 +16,16 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; - import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; +import android.net.Uri; import android.os.UserHandle; import android.provider.BaseColumns; import android.text.TextUtils; @@ -66,7 +66,9 @@ public class LoaderCursor extends CursorWrapper { private final LongSparseArray allUsers; private final LauncherAppState mApp; + private final Uri mContentUri; private final Context mContext; + private final PackageManager mPM; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; @@ -106,14 +108,17 @@ public class LoaderCursor extends CursorWrapper { public int itemType; public int restoreFlag; - public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState) { + public LoaderCursor(Cursor cursor, Uri contentUri, LauncherAppState app, + UserManagerState userManagerState) { super(cursor); mApp = app; allUsers = userManagerState.allUsers; + mContentUri = contentUri; mContext = app.getContext(); mIconCache = app.getIconCache(); mIDP = app.getInvariantDeviceProfile(); + mPM = mContext.getPackageManager(); // Init column indices mIconIndex = getColumnIndexOrThrow(Favorites.ICON); @@ -385,7 +390,7 @@ public class LoaderCursor extends CursorWrapper { */ public ContentWriter updater() { return new ContentWriter(mContext, new ContentWriter.CommitParams( - mApp.getModel().getModelDbController(), + mApp.getModel().getModelDbController().getDatabaseHelper(), BaseColumns._ID + "= ?", new String[]{Integer.toString(id)})); } @@ -404,8 +409,8 @@ public class LoaderCursor extends CursorWrapper { public boolean commitDeleted() { if (mItemsToRemove.size() > 0) { // Remove dead items - mApp.getModel().getModelDbController().delete(TABLE_NAME, - Utilities.createDbSelectionQuery(Favorites._ID, mItemsToRemove), null); + mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery( + Favorites._ID, mItemsToRemove), null); return true; } return false; @@ -430,8 +435,9 @@ public class LoaderCursor extends CursorWrapper { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); values.put(Favorites.RESTORED, 0); - mApp.getModel().getModelDbController().update(TABLE_NAME, values, - Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null); + mContext.getContentResolver().update(mContentUri, values, + Utilities.createDbSelectionQuery( + Favorites._ID, mRestoredRows), null); } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index d4eded5968..9053d19f84 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -16,7 +16,6 @@ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED; @@ -42,6 +41,7 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Point; +import android.net.Uri; import android.os.Bundle; import android.os.Trace; import android.os.UserHandle; @@ -50,6 +50,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.LongSparseArray; +import android.util.TimingLogger; import androidx.annotation.Nullable; @@ -199,10 +200,25 @@ public class LoaderTask implements Runnable { } Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); + TimingLogger timingLogger = new TimingLogger(TAG, "run"); LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger(); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { List allShortcuts = new ArrayList<>(); - loadWorkspace(allShortcuts, "", memoryLogger); + Trace.beginSection("LoadWorkspace"); + try { + loadWorkspace(allShortcuts, memoryLogger); + } finally { + Trace.endSection(); + } + logASplit(timingLogger, "loadWorkspace"); + + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + verifyNotStopped(); + mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.markActive(); + logASplit(timingLogger, "workspaceDelegateItems"); + } // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different @@ -212,21 +228,21 @@ public class LoaderTask implements Runnable { verifyNotStopped(); sanitizeFolders(mItemsDeleted); sanitizeWidgetsShortcutsAndPackages(); - logASplit("sanitizeData"); + logASplit(timingLogger, "sanitizeData"); } verifyNotStopped(); mLauncherBinder.bindWorkspace(true /* incrementBindId */, /* isBindSync= */ false); - logASplit("bindWorkspace"); + logASplit(timingLogger, "bindWorkspace"); mModelDelegate.workspaceLoadComplete(); // Notify the installer packages of packages with active installs on the first screen. sendFirstScreenActiveInstallsBroadcast(); - logASplit("sendFirstScreenActiveInstallsBroadcast"); + logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast"); // Take a break waitForIdle(); - logASplit("step 1 complete"); + logASplit(timingLogger, "step 1 complete"); verifyNotStopped(); // second step @@ -237,16 +253,16 @@ public class LoaderTask implements Runnable { } finally { Trace.endSection(); } - logASplit("loadAllApps"); + logASplit(timingLogger, "loadAllApps"); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindAllAppsItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); - logASplit("allAppsDelegateItems"); + logASplit(timingLogger, "allAppsDelegateItems"); } verifyNotStopped(); mLauncherBinder.bindAllApps(); - logASplit("bindAllApps"); + logASplit(timingLogger, "bindAllApps"); verifyNotStopped(); IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); @@ -254,73 +270,75 @@ public class LoaderTask implements Runnable { updateHandler.updateIcons(allActivityList, LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); - logASplit("update icon cache"); + logASplit(timingLogger, "update icon cache"); verifyNotStopped(); - logASplit("save shortcuts in icon cache"); + logASplit(timingLogger, "save shortcuts in icon cache"); updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), mApp.getModel()::onPackageIconsUpdated); // Take a break waitForIdle(); - logASplit("step 2 complete"); + logASplit(timingLogger, "step 2 complete"); verifyNotStopped(); // third step List allDeepShortcuts = loadDeepShortcuts(); - logASplit("loadDeepShortcuts"); + logASplit(timingLogger, "loadDeepShortcuts"); verifyNotStopped(); mLauncherBinder.bindDeepShortcuts(); - logASplit("bindDeepShortcuts"); + logASplit(timingLogger, "bindDeepShortcuts"); verifyNotStopped(); - logASplit("save deep shortcuts in icon cache"); + logASplit(timingLogger, "save deep shortcuts in icon cache"); updateHandler.updateIcons(allDeepShortcuts, new ShortcutCachingLogic(), (pkgs, user) -> { }); // Take a break waitForIdle(); - logASplit("step 3 complete"); + logASplit(timingLogger, "step 3 complete"); verifyNotStopped(); // fourth step List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); - logASplit("load widgets"); + logASplit(timingLogger, "load widgets"); verifyNotStopped(); mLauncherBinder.bindWidgets(); - logASplit("bindWidgets"); + logASplit(timingLogger, "bindWidgets"); verifyNotStopped(); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList); - logASplit("otherDelegateItems"); + logASplit(timingLogger, "otherDelegateItems"); verifyNotStopped(); } updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); - logASplit("save widgets in icon cache"); + logASplit(timingLogger, "save widgets in icon cache"); // fifth step loadFolderNames(); verifyNotStopped(); updateHandler.finish(); - logASplit("finish icon update"); + logASplit(timingLogger, "finish icon update"); mModelDelegate.modelLoadComplete(); transaction.commit(); memoryLogger.clearLogs(); } catch (CancellationException e) { // Loader stopped, ignore - logASplit("Cancelled"); + logASplit(timingLogger, "Cancelled"); } catch (Exception e) { memoryLogger.printLogs(); throw e; + } finally { + timingLogger.dumpToLog(); } TraceHelper.INSTANCE.endSection(traceToken); } @@ -330,29 +348,25 @@ public class LoaderTask implements Runnable { this.notify(); } - protected void loadWorkspace( - List allDeepShortcuts, - String selection, - LoaderMemoryLogger memoryLogger) { - Trace.beginSection("LoadWorkspace"); - try { - loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger); - } finally { - Trace.endSection(); - } - logASplit("loadWorkspace"); + private void loadWorkspace( + List allDeepShortcuts, LoaderMemoryLogger memoryLogger) { + loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI, + null /* selection */, memoryLogger); + } + protected void loadWorkspaceForPreviewSurfaceRenderer( + List allDeepShortcuts, Uri contentUri, String selection) { + loadWorkspace(allDeepShortcuts, contentUri, selection, null); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { - verifyNotStopped(); mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); mModelDelegate.markActive(); - logASplit("workspaceDelegateItems"); } } - private void loadWorkspaceImpl( + protected void loadWorkspace( List allDeepShortcuts, + Uri contentUri, String selection, @Nullable LoaderMemoryLogger memoryLogger) { final Context context = mApp.getContext(); @@ -363,7 +377,7 @@ public class LoaderTask implements Runnable { final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context); boolean clearDb = false; - if (!mApp.getModel().getModelDbController().migrateGridIfNeeded()) { + if (!GridSizeMigrationUtil.migrateGridIfNeeded(context)) { // Migration failed. Clear workspace. clearDb = true; } @@ -388,9 +402,8 @@ public class LoaderTask implements Runnable { mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); mShortcutKeyToPinnedShortcuts = new HashMap<>(); - ModelDbController dbController = mApp.getModel().getModelDbController(); final LoaderCursor c = new LoaderCursor( - dbController.query(TABLE_NAME, null, selection, null, null), + contentResolver.query(contentUri, null, selection, null, null), contentUri, mApp, mUserManagerState); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME); @@ -1099,9 +1112,12 @@ public class LoaderTask implements Runnable { FileLog.d(TAG, widgetDimension.toString()); } - private static void logASplit(String label) { - if (DEBUG) { - Log.d(TAG, label); + private static void logASplit(@Nullable TimingLogger timingLogger, String label) { + if (timingLogger != null) { + timingLogger.addSplit(label); + if (DEBUG) { + Log.d(TAG, label); + } } } } diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java index 43d8958622..97bce8c25a 100644 --- a/src/com/android/launcher3/model/ModelDbController.java +++ b/src/com/android/launcher3/model/ModelDbController.java @@ -19,10 +19,11 @@ import static android.util.Base64.NO_PADDING; import static android.util.Base64.NO_WRAP; import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT; -import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL; import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG; +import static com.android.launcher3.model.DatabaseHelper.EMPTY_DATABASE_CREATED; +import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; import android.app.blob.BlobHandle; @@ -30,6 +31,7 @@ import android.app.blob.BlobStoreManager; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.res.Resources; @@ -41,7 +43,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.Process; -import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; @@ -53,22 +54,18 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.AutoInstallsLayout; import com.android.launcher3.AutoInstallsLayout.SourceResources; -import com.android.launcher3.ConstantItem; import com.android.launcher3.DefaultLayoutParser; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.LauncherFiles; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.util.Partner; import com.android.launcher3.widget.LauncherWidgetHolder; @@ -76,6 +73,7 @@ import org.xmlpull.v1.XmlPullParser; import java.io.InputStream; import java.io.StringReader; +import java.util.function.Supplier; /** * Utility class which maintains an instance of Launcher database and provides utility methods @@ -84,8 +82,6 @@ import java.io.StringReader; public class ModelDbController { private static final String TAG = "LauncherProvider"; - private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; - protected DatabaseHelper mOpenHelper; private final Context mContext; @@ -96,36 +92,26 @@ public class ModelDbController { private synchronized void createDbIfNotExists() { if (mOpenHelper == null) { - mOpenHelper = createDatabaseHelper(false /* forMigration */); - RestoreDbTask.restoreIfNeeded(mContext, this); + mOpenHelper = DatabaseHelper.createDatabaseHelper( + mContext, false /* forMigration */); + + RestoreDbTask.restoreIfNeeded(mContext, mOpenHelper); } } - protected DatabaseHelper createDatabaseHelper(boolean forMigration) { - boolean isSandbox = mContext instanceof SandboxContext; - String dbName = isSandbox ? null : InvariantDeviceProfile.INSTANCE.get(mContext).dbFile; - - // Set the flag for empty DB - Runnable onEmptyDbCreateCallback = forMigration ? () -> { } - : () -> LauncherPrefs.get(mContext).putSync(getEmptyDbCreatedKey(dbName).to(true)); - - DatabaseHelper databaseHelper = new DatabaseHelper(mContext, dbName, - this::getSerialNumberForUser, onEmptyDbCreateCallback); - // 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(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. - addTableToDb(databaseHelper.getWritableDatabase(), - getSerialNumberForUser(Process.myUserHandle()), - true /* optional */); + private synchronized boolean prepForMigration(String dbFile, String targetTableName, + Supplier src, Supplier dst) { + if (TextUtils.equals(dbFile, mOpenHelper.getDatabaseName())) { + Log.e(TAG, "prepForMigration - target db is same as current: " + dbFile); + return false; } - databaseHelper.mHotseatRestoreTableExists = tableExists( - databaseHelper.getReadableDatabase(), Favorites.HYBRID_HOTSEAT_BACKUP_TABLE); - databaseHelper.initIds(); - return databaseHelper; + final DatabaseHelper helper = src.get(); + mOpenHelper = dst.get(); + copyTable(helper.getReadableDatabase(), Favorites.TABLE_NAME, + mOpenHelper.getWritableDatabase(), targetTableName, mContext); + helper.close(); + return true; } /** @@ -281,40 +267,42 @@ public class ModelDbController { } /** - * Migrates the DB if needed, and returns false if the migration failed - * and DB needs to be cleared. - * @return true if migration was success or ignored, false if migration failed - * and the DB should be reset. + * Updates the current DB and copies all the existing data to the temp table + * @param dbFile name of the target db file name */ - public boolean migrateGridIfNeeded() { - InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext); - if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) { - return true; - } - String targetDbName = new DeviceGridState(idp).getDbFile(); - if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) { - Log.e(TAG, "migrateGridIfNeeded - target db is same as current: " + targetDbName); - return false; - } - DatabaseHelper oldHelper = mOpenHelper; - mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper - : createDatabaseHelper(true /* forMigration */); - try { - return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper, - oldHelper.getWritableDatabase()); - } finally { - if (mOpenHelper != oldHelper) { - oldHelper.close(); - } - } + @WorkerThread + public boolean updateCurrentOpenHelper(String dbFile) { + createDbIfNotExists(); + return prepForMigration( + dbFile, + Favorites.TMP_TABLE, + () -> mOpenHelper, + () -> DatabaseHelper.createDatabaseHelper( + mContext, true /* forMigration */)); } /** - * Returns the underlying model database + * Returns the current DatabaseHelper. + * Only for tests */ - public SQLiteDatabase getDb() { + @WorkerThread + public DatabaseHelper getDatabaseHelper() { createDbIfNotExists(); - return mOpenHelper.getWritableDatabase(); + return mOpenHelper; + } + + /** + * Prepares the DB for preview by copying all existing data to preview table + */ + @WorkerThread + public boolean prepareForPreview(String dbFile) { + createDbIfNotExists(); + return prepForMigration( + dbFile, + Favorites.PREVIEW_TABLE_NAME, + () -> DatabaseHelper.createDatabaseHelper( + mContext, dbFile, true /* forMigration */), + () -> mOpenHelper); } private void onAddOrDeleteOp(SQLiteDatabase db) { @@ -357,7 +345,8 @@ public class ModelDbController { } private void clearFlagEmptyDbCreated() { - LauncherPrefs.get(mContext).removeSync(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName())); + LauncherPrefs.getPrefs(mContext).edit() + .remove(mOpenHelper.getKey(EMPTY_DATABASE_CREATED)).commit(); } /** @@ -370,8 +359,9 @@ public class ModelDbController { @WorkerThread public synchronized void loadDefaultFavoritesIfNecessary() { createDbIfNotExists(); + SharedPreferences sp = LauncherPrefs.getPrefs(mContext); - if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()))) { + if (sp.getBoolean(mOpenHelper.getKey(EMPTY_DATABASE_CREATED), false)) { Log.d(TAG, "loading default workspace"); LauncherWidgetHolder widgetHolder = mOpenHelper.newLauncherWidgetHolder(); @@ -489,27 +479,4 @@ public class ModelDbController { return new DefaultLayoutParser(mContext, widgetHolder, mOpenHelper, mContext.getResources(), defaultLayout); } - - /** - * Re-composite given key in respect to database. If the current db is - * {@link LauncherFiles#LAUNCHER_DB}, return the key as-is. Otherwise append the db name to - * given key. e.g. consider key="EMPTY_DATABASE_CREATED", dbName="minimal.db", the returning - * string will be "EMPTY_DATABASE_CREATED@minimal.db". - */ - private ConstantItem getEmptyDbCreatedKey(String dbName) { - if (mContext instanceof SandboxContext) { - return LauncherPrefs.nonRestorableItem(EMPTY_DATABASE_CREATED, - false /* default value */, false /* boot aware */); - } - String key = TextUtils.equals(dbName, LauncherFiles.LAUNCHER_DB) - ? EMPTY_DATABASE_CREATED : EMPTY_DATABASE_CREATED + "@" + dbName; - return LauncherPrefs.backedUpItem(key, false /* default value */, false /* boot aware */); - } - - /** - * Returns the serial number for the provided user - */ - public long getSerialNumberForUser(UserHandle user) { - return UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user); - } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index c718dcc877..48969fc44e 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -101,7 +101,7 @@ public class LauncherDbUtils { UserManagerState ums = new UserManagerState(); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums); + LoaderCursor lc = new LoaderCursor(c, null, LauncherAppState.getInstance(context), ums); IntSet deletedShortcuts = new IntSet(); while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index a6e064a4ed..ac7216449b 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -16,8 +16,6 @@ package com.android.launcher3.provider; -import static android.os.Process.myUserHandle; - import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY; import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS; import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS; @@ -49,8 +47,8 @@ import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.logging.FileLog; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DeviceGridState; -import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -85,12 +83,12 @@ public class RestoreDbTask { /** * Tries to restore the backup DB if needed */ - public static void restoreIfNeeded(Context context, ModelDbController dbController) { + public static void restoreIfNeeded(Context context, DatabaseHelper helper) { if (!isPending(context)) { return; } - if (!performRestore(context, dbController)) { - dbController.createEmptyDB(); + if (!performRestore(context, helper)) { + helper.createEmptyDB(helper.getWritableDatabase()); } // Obtain InvariantDeviceProfile first before setting pending to false, so @@ -104,12 +102,12 @@ public class RestoreDbTask { idp.reinitializeAfterRestore(context); } - private static boolean performRestore(Context context, ModelDbController controller) { - SQLiteDatabase db = controller.getDb(); + private static boolean performRestore(Context context, DatabaseHelper helper) { + SQLiteDatabase db = helper.getWritableDatabase(); try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, controller, db, new BackupManager(context)); - task.restoreAppWidgetIdsIfExists(context, controller); + task.sanitizeDB(context, helper, db, new BackupManager(context)); + task.restoreAppWidgetIdsIfExists(context, helper); t.commit(); return true; } catch (Exception e) { @@ -131,10 +129,10 @@ public class RestoreDbTask { * @return number of items deleted. */ @VisibleForTesting - protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db, + protected int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids - long myProfileId = controller.getSerialNumberForUser(myUserHandle()); + long myProfileId = helper.getDefaultUserSerial(); long oldProfileId = getDefaultProfileId(db); LongSparseArray oldManagedProfileIds = getManagedProfileIds(db, oldProfileId); LongSparseArray profileMapping = new LongSparseArray<>(oldManagedProfileIds.size() @@ -146,7 +144,7 @@ public class RestoreDbTask { long oldManagedProfileId = oldManagedProfileIds.keyAt(i); UserHandle user = getUserForAncestralSerialNumber(backupManager, oldManagedProfileId); if (user != null) { - long newManagedProfileId = controller.getSerialNumberForUser(user); + long newManagedProfileId = helper.getSerialNumberForUser(user); profileMapping.put(oldManagedProfileId, newManagedProfileId); } } @@ -215,7 +213,7 @@ public class RestoreDbTask { } // Override shortcuts - maybeOverrideShortcuts(context, controller, db, myProfileId); + maybeOverrideShortcuts(context, helper, db, myProfileId); return itemsDeleted; } @@ -323,11 +321,11 @@ public class RestoreDbTask { .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType())); } - private void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) { + private void restoreAppWidgetIdsIfExists(Context context, DatabaseHelper helper) { LauncherPrefs lp = LauncherPrefs.get(context); if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) { AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID); - AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, controller, + AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, helper, IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(), IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(), host); @@ -345,7 +343,7 @@ public class RestoreDbTask { APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } - protected static void maybeOverrideShortcuts(Context context, ModelDbController controller, + protected static void maybeOverrideShortcuts(Context context, DatabaseHelper helper, SQLiteDatabase db, long currentUser) { Map activityOverrides = ApiWrapper.getActivityOverrides( context); @@ -369,7 +367,7 @@ public class RestoreDbTask { if (override != null) { ContentValues values = new ContentValues(); values.put(Favorites.PROFILE_ID, - controller.getSerialNumberForUser(override.getUser())); + helper.getSerialNumberForUser(override.getUser())); values.put(Favorites.INTENT, AppInfo.makeLaunchIntent(override).toUri(0)); db.update(Favorites.TABLE_NAME, values, String.format("%s=?", Favorites._ID), new String[]{String.valueOf(c.getInt(idIndex))}); diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java index 7c5ef4db0c..e509235688 100644 --- a/src/com/android/launcher3/util/ContentWriter.java +++ b/src/com/android/launcher3/util/ContentWriter.java @@ -26,7 +26,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; -import com.android.launcher3.model.ModelDbController; +import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.pm.UserCache; /** @@ -106,7 +106,7 @@ public class ContentWriter { public int commit() { if (mCommitParams != null) { - mCommitParams.mDbController.update( + mCommitParams.mDatabaseHelper.getWritableDatabase().update( Favorites.TABLE_NAME, getValues(mContext), mCommitParams.mWhere, mCommitParams.mSelectionArgs); } @@ -115,12 +115,12 @@ public class ContentWriter { public static final class CommitParams { - final ModelDbController mDbController; + final DatabaseHelper mDatabaseHelper; final String mWhere; final String[] mSelectionArgs; - public CommitParams(ModelDbController controller, String where, String[] selectionArgs) { - mDbController = controller; + public CommitParams(DatabaseHelper helper, String where, String[] selectionArgs) { + mDatabaseHelper = helper; mWhere = where; mSelectionArgs = selectionArgs; } diff --git a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java index cea95e5a50..0a1a9ba6a9 100644 --- a/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java +++ b/tests/src/com/android/launcher3/model/DbDowngradeHelperTest.java @@ -39,7 +39,6 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; -import com.android.launcher3.pm.UserCache; import org.junit.Before; import org.junit.Test; @@ -223,9 +222,7 @@ public class DbDowngradeHelperTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, DB_FILE, - UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, - () -> { }); + super(mContext, DB_FILE, false); } @Override diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt index 63dbaa752d..f24f0dab76 100644 --- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt +++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt @@ -15,7 +15,6 @@ */ package com.android.launcher3.model -import android.content.ContentValues import android.content.Context import android.content.Intent import android.database.Cursor @@ -24,7 +23,6 @@ import android.graphics.Point import android.os.Process import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.InvariantDeviceProfile import com.android.launcher3.LauncherPrefs import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE @@ -33,7 +31,10 @@ import com.android.launcher3.config.FeatureFlags import com.android.launcher3.model.GridSizeMigrationUtil.DbReader import com.android.launcher3.pm.UserCache import com.android.launcher3.provider.LauncherDbUtils +import com.android.launcher3.util.LauncherModelHelper +import com.android.launcher3.util.LauncherModelHelper.* import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -42,12 +43,11 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GridSizeMigrationUtilTest { - + private lateinit var modelHelper: LauncherModelHelper private lateinit var context: Context + private lateinit var db: SQLiteDatabase private lateinit var validPackages: Set private lateinit var idp: InvariantDeviceProfile - private lateinit var dbHelper: DatabaseHelper - private lateinit var db: SQLiteDatabase private val testPackage1 = "com.android.launcher3.validpackage1" private val testPackage2 = "com.android.launcher3.validpackage2" private val testPackage3 = "com.android.launcher3.validpackage3" @@ -61,17 +61,13 @@ class GridSizeMigrationUtilTest { @Before fun setUp() { - context = InstrumentationRegistry.getInstrumentation().targetContext - dbHelper = - DatabaseHelper( - context, - null, - UserCache.INSTANCE.get(context)::getSerialNumberForUser - ) {} - db = dbHelper.writableDatabase + modelHelper = LauncherModelHelper() + context = modelHelper.sandboxContext + db = modelHelper.provider.db validPackages = setOf( + TEST_PACKAGE, testPackage1, testPackage2, testPackage3, @@ -90,6 +86,11 @@ class GridSizeMigrationUtilTest { addTableToDb(db, userSerial, false, TMP_TABLE) } + @After + fun tearDown() { + modelHelper.destroy() + } + /** * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not * needed anymore @@ -98,26 +99,26 @@ class GridSizeMigrationUtilTest { @Throws(Exception::class) fun testMigration() { // Src Hotseat icons - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) // Src grid icons // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ 9 // _ _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 3, testPackage9, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 3, testPackage9, 9, TMP_CONTENT_URI) // Dest hotseat icons - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2) // Dest grid icons - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage10) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -125,7 +126,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -136,13 +138,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items var c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -167,13 +168,12 @@ class GridSizeMigrationUtilTest { // Check workspace items c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -209,30 +209,30 @@ class GridSizeMigrationUtilTest { fun testMigrationBackAndForth() { // Hotseat items in grid A // 1 2 _ 3 4 - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) // Workspace items in grid A // _ _ _ _ _ // _ _ _ _ 5 // _ _ 6 _ 7 // _ _ 8 _ _ // _ _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 1, testPackage5, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage6, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 2, testPackage7, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage8, 8, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 1, testPackage5, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage6, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 4, 2, testPackage7, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage8, 8, TMP_CONTENT_URI) // Hotseat items in grid B // 2 _ _ _ - addItem(ITEM_TYPE_SHORTCUT, 0, CONTAINER_HOTSEAT, 0, 0, testPackage2) + modelHelper.addItem(SHORTCUT, 0, HOTSEAT, 0, 0, testPackage2) // Workspace items in grid B // _ _ _ _ // _ _ _ 10 // _ _ _ _ // _ _ _ _ - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 3, testPackage10) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 3, testPackage10) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -241,7 +241,8 @@ class GridSizeMigrationUtilTest { val readerGridB = DbReader(db, TABLE_NAME, context, validPackages) // migrate from A -> B GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -252,13 +253,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B var c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -272,13 +272,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -295,11 +294,12 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage8]).isEqualTo(Triple(0, 3, 1)) // add item in B - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 2, testPackage9) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 2, testPackage9) // migrate from B -> A GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridB, readerGridA, 5, @@ -309,13 +309,12 @@ class GridSizeMigrationUtilTest { ) // Check hotseat items in grid A c = - db.query( - TMP_TABLE, + context.contentResolver.query( + TMP_CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -329,13 +328,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid A c = - db.query( - TMP_TABLE, + context.contentResolver.query( + TMP_CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -356,11 +354,12 @@ class GridSizeMigrationUtilTest { assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2)) // remove item from B - db.delete(TMP_TABLE, "$_ID=7", null) + modelHelper.deleteItem(7, TMP_TABLE) // migrate from A -> B GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, readerGridA, readerGridB, idp.numDatabaseHotseatIcons, @@ -371,13 +370,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -391,13 +389,12 @@ class GridSizeMigrationUtilTest { // Check workspace items in grid B c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, CELLX, CELLY, INTENT), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -446,28 +443,10 @@ class GridSizeMigrationUtilTest { fun migrateToLargerHotseat() { val srcHotseatItems = intArrayOf( - addItem( - ITEM_TYPE_APPLICATION, - 0, - CONTAINER_HOTSEAT, - 0, - 0, - testPackage1, - 1, - TMP_TABLE - ), - addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE), - addItem( - ITEM_TYPE_APPLICATION, - 2, - CONTAINER_HOTSEAT, - 0, - 0, - testPackage3, - 3, - TMP_TABLE - ), - addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI), + modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI), + modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI), + modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) ) val numSrcDatabaseHotseatIcons = srcHotseatItems.size idp.numDatabaseHotseatIcons = 6 @@ -476,7 +455,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -487,13 +467,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -522,11 +501,11 @@ class GridSizeMigrationUtilTest { @Test fun migrateFromLargerHotseat() { - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE) - addItem(ITEM_TYPE_SHORTCUT, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 5, CONTAINER_HOTSEAT, 0, 0, testPackage5, 5, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 2, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 3, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI) + modelHelper.addItem(SHORTCUT, 4, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 5, HOTSEAT, 0, 0, testPackage5, 5, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -534,7 +513,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -545,13 +525,12 @@ class GridSizeMigrationUtilTest { // Check hotseat items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(SCREEN, INTENT), "container=$CONTAINER_HOTSEAT", null, SCREEN, - null, null ) ?: throw IllegalStateException() @@ -589,11 +568,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("4,4") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 2, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 2, 3, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 1, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 3, 2, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 3, 3, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 6 @@ -602,7 +581,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -613,13 +593,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -651,11 +630,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("2,2") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 5 @@ -663,7 +642,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -674,13 +654,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -712,11 +691,11 @@ class GridSizeMigrationUtilTest { enableNewMigrationLogic("5,5") // Setup src grid - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 1, testPackage1, 5, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 1, 1, testPackage2, 6, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 0, 0, testPackage3, 7, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 1, 0, testPackage4, 8, TMP_TABLE) - addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 0, 0, testPackage5, 9, TMP_TABLE) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 0, 1, testPackage1, 5, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 0, DESKTOP, 1, 1, testPackage2, 6, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 0, 0, testPackage3, 7, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 1, DESKTOP, 1, 0, testPackage4, 8, TMP_CONTENT_URI) + modelHelper.addItem(APP_ICON, 2, DESKTOP, 0, 0, testPackage5, 9, TMP_CONTENT_URI) idp.numDatabaseHotseatIcons = 4 idp.numColumns = 4 @@ -724,7 +703,8 @@ class GridSizeMigrationUtilTest { val srcReader = DbReader(db, TMP_TABLE, context, validPackages) val destReader = DbReader(db, TABLE_NAME, context, validPackages) GridSizeMigrationUtil.migrate( - dbHelper, + context, + db, srcReader, destReader, idp.numDatabaseHotseatIcons, @@ -735,13 +715,12 @@ class GridSizeMigrationUtilTest { // Get workspace items val c = - db.query( - TABLE_NAME, + context.contentResolver.query( + CONTENT_URI, arrayOf(INTENT, SCREEN), "container=$CONTAINER_DESKTOP", null, null, - null, null ) ?: throw IllegalStateException() @@ -768,48 +747,4 @@ class GridSizeMigrationUtilTest { private fun enableNewMigrationLogic(srcGridSize: String) { LauncherPrefs.get(context).putSync(WORKSPACE_SIZE.to(srcGridSize)) } - - private fun addItem( - type: Int, - screen: Int, - container: Int, - x: Int, - y: Int, - packageName: String? - ): Int { - return addItem( - type, - screen, - container, - x, - y, - packageName, - dbHelper.generateNewItemId(), - TABLE_NAME - ) - } - - private fun addItem( - type: Int, - screen: Int, - container: Int, - x: Int, - y: Int, - packageName: String?, - id: Int, - tableName: String - ): Int { - val values = ContentValues() - values.put(_ID, id) - values.put(CONTAINER, container) - values.put(SCREEN, screen) - values.put(CELLX, x) - values.put(CELLY, y) - values.put(SPANX, 1) - values.put(SPANY, 1) - values.put(ITEM_TYPE, type) - values.put(INTENT, Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)) - db.insert(tableName, null, values) - return id - } } diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 78812c0778..d192be408c 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -59,6 +59,7 @@ import androidx.test.filters.SmallTest; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.util.Executors; @@ -101,7 +102,7 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, mApp, ums); + mLoaderCursor = new LoaderCursor(mCursor, Favorites.CONTENT_URI, mApp, ums); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java index 54b8489134..2b6f9ff193 100644 --- a/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java +++ b/tests/src/com/android/launcher3/provider/LauncherDbUtilsTest.java @@ -45,7 +45,6 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.R; import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DbDowngradeHelper; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.settings.SettingsActivity; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.IOUtils; @@ -166,11 +165,12 @@ public class LauncherDbUtilsTest { private class MyDatabaseHelper extends DatabaseHelper { MyDatabaseHelper() { - super(mContext, null, UserCache.INSTANCE.get(mContext)::getSerialNumberForUser, - () -> { }); + super(mContext, null, false); } @Override protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } + + protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index 1b1b294966..67de1f5fb1 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -46,7 +46,6 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.DatabaseHelper; -import com.android.launcher3.model.ModelDbController; import org.junit.Test; import org.junit.runner.RunWith; @@ -64,13 +63,13 @@ public class RestoreDbTaskTest { @Test public void testGetProfileId() throws Exception { - SQLiteDatabase db = new MyModelDbController(23).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(23).getWritableDatabase(); assertEquals(23, new RestoreDbTask().getDefaultProfileId(db)); } @Test public void testMigrateProfileId() throws Exception { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -90,7 +89,7 @@ public class RestoreDbTaskTest { @Test public void testChangeDefaultColumn() throws Exception { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < 5; i++) { ContentValues values = new ContentValues(); @@ -121,20 +120,20 @@ public class RestoreDbTaskTest { long workProfileId = myProfileId + 2; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); - SQLiteDatabase db = controller.getDb(); + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); BackupManager bm = spy(new BackupManager(context)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - controller.users.put(workProfileId, mWorkUser); + helper.users.put(workProfileId, mWorkUser); - addIconsBulk(controller, 10, 1, myProfileId_old); - addIconsBulk(controller, 6, 2, workProfileId_old); + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, controller, controller.getDb(), bm); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -152,20 +151,20 @@ public class RestoreDbTaskTest { long myProfileId_old = myProfileId + 1; long workProfileId_old = myProfileId + 3; - MyModelDbController controller = new MyModelDbController(myProfileId); - SQLiteDatabase db = controller.getDb(); + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); BackupManager bm = spy(new BackupManager(context)); doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); // Work profile is not migrated doReturn(null).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); - addIconsBulk(controller, 10, 1, myProfileId_old); - addIconsBulk(controller, 6, 2, workProfileId_old); + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); assertEquals(10, getItemCountForProfile(db, myProfileId_old)); assertEquals(6, getItemCountForProfile(db, workProfileId_old)); RestoreDbTask task = new RestoreDbTask(); - task.sanitizeDB(context, controller, controller.getDb(), bm); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); // All the data has been migrated to the new user ids assertEquals(0, getItemCountForProfile(db, myProfileId_old)); @@ -174,13 +173,12 @@ public class RestoreDbTaskTest { assertEquals(10, getCount(db, "select * from favorites")); } - private void addIconsBulk(MyModelDbController controller, - int count, int screen, long profileId) { + private void addIconsBulk(DatabaseHelper helper, int count, int screen, long profileId) { int columns = LauncherAppState.getIDP(getInstrumentation().getTargetContext()).numColumns; String packageName = getInstrumentation().getContext().getPackageName(); for (int i = 0; i < count; i++) { ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites._ID, controller.generateNewItemId()); + values.put(LauncherSettings.Favorites._ID, helper.generateNewItemId()); values.put(LauncherSettings.Favorites.CONTAINER, CONTAINER_DESKTOP); values.put(LauncherSettings.Favorites.SCREEN, screen); values.put(LauncherSettings.Favorites.CELLX, i % columns); @@ -191,11 +189,11 @@ public class RestoreDbTaskTest { values.put(LauncherSettings.Favorites.ITEM_TYPE, ITEM_TYPE_APPLICATION); values.put(LauncherSettings.Favorites.INTENT, new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); - - controller.insert(TABLE_NAME, values); + helper.getWritableDatabase().insert(TABLE_NAME, null, values); } } + @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( @@ -218,7 +216,7 @@ public class RestoreDbTaskTest { } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { - SQLiteDatabase db = new MyModelDbController(42).getDb(); + SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); @@ -256,15 +254,14 @@ public class RestoreDbTaskTest { } } - private class MyModelDbController extends ModelDbController { + private class MyDatabaseHelper extends DatabaseHelper { - public final LongSparseArray users = new LongSparseArray<>(); + public final LongSparseArray users; - MyModelDbController(long profileId) { - super(getInstrumentation().getTargetContext()); + MyDatabaseHelper(long profileId) { + super(getInstrumentation().getTargetContext(), null, false); + users = new LongSparseArray<>(); users.put(profileId, myUserHandle()); - mOpenHelper = new DatabaseHelper(getInstrumentation().getTargetContext(), null, - this::getSerialNumberForUser, () -> { }); } @Override @@ -272,5 +269,10 @@ public class RestoreDbTaskTest { int index = users.indexOfValue(user); return index >= 0 ? users.keyAt(index) : -1; } + + @Override + protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { } + + protected void onEmptyDbCreated() { } } } diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index 6fca965600..bf31e39ccc 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -363,6 +363,12 @@ public class LauncherModelHelper { sandboxContext.getContentResolver().insert(contentUri, values); } + public void deleteItem(int itemId, @NonNull final String tableName) { + final Uri uri = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + tableName + "/" + itemId); + sandboxContext.getContentResolver().delete(uri, null, null); + } + /** * Sets up a mock provider to load the provided layout by default, next time the layout loads */ @@ -420,7 +426,7 @@ public class LauncherModelHelper { } public SQLiteDatabase getDb() { - return getModelDbController().getDb(); + return getModelDbController().getDatabaseHelper().getWritableDatabase(); } }