Revert "Revert "Revert "Revert "Revert "Revert "Changing GridMigrationTask to use ModelDbController directly"""""" am: 7bc6cdee56

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23219852

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