From eb27546cc378fd970c3b4620e46a5f1152f4beba Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 12 Apr 2023 15:50:32 -0700 Subject: [PATCH] Removing remaining code around ENABLE_DATABASE_RESTORE ENABLE_DATABASE_RESTORE feature is already removed Also migrating some tests from BackupRestoreTest to RestoreDbTaskTest Bug: 270392706 Test: Presubmit Flag: N/A Change-Id: I71822bbc2232008b3d2b4b9fbed0db5d889591e4 --- .../hybridhotseat/HotseatRestoreHelper.java | 11 +- .../launcher3/AppWidgetsRestoredReceiver.java | 6 - .../android/launcher3/LauncherSettings.java | 11 - .../launcher3/model/GridBackupTable.java | 120 +--------- .../launcher3/provider/RestoreDbTask.java | 60 +---- .../android/launcher3/util/ContentWriter.java | 14 +- .../launcher3/model/BackupRestoreTest.java | 211 ------------------ .../launcher3/provider/RestoreDbTaskTest.java | 128 ++++++++++- .../launcher3/util/LauncherModelHelper.java | 53 ----- 9 files changed, 132 insertions(+), 482 deletions(-) delete mode 100644 tests/src/com/android/launcher3/model/BackupRestoreTest.java diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java index 4956fa1b86..726abff5da 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatRestoreHelper.java @@ -21,7 +21,6 @@ import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.Context; -import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.GridBackupTable; @@ -42,10 +41,7 @@ public class HotseatRestoreHelper { context.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_TRANSACTION) .getBinder(LauncherSettings.Settings.EXTRA_VALUE)) { - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - GridBackupTable backupTable = new GridBackupTable(context, - transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns, - idp.numRows); + GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb()); backupTable.createCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE); transaction.commit(); LauncherSettings.Settings.call(context.getContentResolver(), @@ -67,10 +63,7 @@ public class HotseatRestoreHelper { if (!tableExists(transaction.getDb(), HYBRID_HOTSEAT_BACKUP_TABLE)) { return; } - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - GridBackupTable backupTable = new GridBackupTable(context, - transaction.getDb(), idp.numDatabaseHotseatIcons, idp.numColumns, - idp.numRows); + GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb()); backupTable.restoreFromCustomBackupTable(HYBRID_HOTSEAT_BACKUP_TABLE, true); transaction.commit(); LauncherAppState.getInstance(context).getModel().forceReload(); diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index 9d5b08eab5..e54337050d 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -107,12 +107,6 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { cursor.close(); } } - // attempt to update widget id in backup table as well - new ContentWriter(context, ContentWriter.CommitParams.backupCommitParams( - "appWidgetId=? and profileId=?", args)) - .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]) - .put(LauncherSettings.Favorites.RESTORED, state) - .commit(); } LauncherAppState app = LauncherAppState.getInstanceNoCreate(); diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 1bbb09afe4..82dbe53da8 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -138,11 +138,6 @@ public class LauncherSettings { public static final String TABLE_NAME = "favorites"; - /** - * Backup table created when the favorites table is modified during grid migration - */ - public static final String BACKUP_TABLE_NAME = "favorites_bakup"; - /** * Backup table created when user hotseat is moved to workspace for hybrid hotseat */ @@ -164,12 +159,6 @@ public class LauncherSettings { public static final Uri CONTENT_URI = Uri.parse("content://" + LauncherProvider.AUTHORITY + "/" + TABLE_NAME); - /** - * The content:// style URL for "favorites_bakup" table - */ - public static final Uri BACKUP_CONTENT_URI = Uri.parse("content://" - + LauncherProvider.AUTHORITY + "/" + BACKUP_TABLE_NAME); - /** * The content:// style URL for "favorites_preview" table */ diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java index 51cbf4b770..6bd8518c95 100644 --- a/src/com/android/launcher3/model/GridBackupTable.java +++ b/src/com/android/launcher3/model/GridBackupTable.java @@ -15,18 +15,12 @@ */ package com.android.launcher3.model; -import static com.android.launcher3.LauncherSettings.Favorites.BACKUP_TABLE_NAME; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; import static com.android.launcher3.provider.LauncherDbUtils.tableExists; -import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Process; -import android.util.Log; - -import androidx.annotation.IntDef; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.pm.UserCache; @@ -36,50 +30,13 @@ import com.android.launcher3.pm.UserCache; * within the same data base. */ public class GridBackupTable { - private static final String TAG = "GridBackupTable"; - - private static final int ID_PROPERTY = -1; - - private static final String KEY_HOTSEAT_SIZE = Favorites.SCREEN; - private static final String KEY_GRID_X_SIZE = Favorites.SPANX; - private static final String KEY_GRID_Y_SIZE = Favorites.SPANY; - private static final String KEY_DB_VERSION = Favorites.RANK; - - public static final int OPTION_REQUIRES_SANITIZATION = 1; - - /** STATE_NOT_FOUND indicates backup doesn't exist in the db. */ - private static final int STATE_NOT_FOUND = 0; - /** - * STATE_RAW indicates the backup has not yet been sanitized. This implies it might still - * posses app info that doesn't exist in the workspace and needed to be sanitized before - * put into use. - */ - private static final int STATE_RAW = 1; - /** STATE_SANITIZED indicates the backup has already been sanitized, thus can be used as-is. */ - private static final int STATE_SANITIZED = 2; private final Context mContext; private final SQLiteDatabase mDb; - private final int mOldHotseatSize; - private final int mOldGridX; - private final int mOldGridY; - - private int mRestoredHotseatSize; - private int mRestoredGridX; - private int mRestoredGridY; - - @IntDef({STATE_NOT_FOUND, STATE_RAW, STATE_SANITIZED}) - private @interface BackupState { } - - public GridBackupTable(Context context, SQLiteDatabase db, int hotseatSize, int gridX, - int gridY) { + public GridBackupTable(Context context, SQLiteDatabase db) { mContext = context; mDb = db; - - mOldHotseatSize = hotseatSize; - mOldGridX = gridX; - mOldGridY = gridY; } /** @@ -89,7 +46,6 @@ public class GridBackupTable { long profileId = UserCache.INSTANCE.get(mContext).getSerialNumberForUser( Process.myUserHandle()); copyTable(mDb, Favorites.TABLE_NAME, tableName, profileId); - encodeDBProperties(0); } /** @@ -114,78 +70,6 @@ public class GridBackupTable { private static void copyTable(SQLiteDatabase db, String from, String to, long userSerial) { dropTable(db, to); Favorites.addTableToDb(db, userSerial, false, to); - db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from + " where _id > " + ID_PROPERTY); - } - - private void encodeDBProperties(int options) { - ContentValues values = new ContentValues(); - values.put(Favorites._ID, ID_PROPERTY); - values.put(KEY_DB_VERSION, mDb.getVersion()); - values.put(KEY_GRID_X_SIZE, mOldGridX); - values.put(KEY_GRID_Y_SIZE, mOldGridY); - values.put(KEY_HOTSEAT_SIZE, mOldHotseatSize); - values.put(Favorites.OPTIONS, options); - mDb.insert(BACKUP_TABLE_NAME, null, values); - } - - /** - * Load DB properties from grid backup table. - */ - public @BackupState int loadDBProperties() { - try (Cursor c = mDb.query(BACKUP_TABLE_NAME, new String[] { - KEY_DB_VERSION, // 0 - KEY_GRID_X_SIZE, // 1 - KEY_GRID_Y_SIZE, // 2 - KEY_HOTSEAT_SIZE, // 3 - Favorites.OPTIONS}, // 4 - "_id=" + ID_PROPERTY, null, null, null, null)) { - if (!c.moveToNext()) { - Log.e(TAG, "Meta data not found in backup table"); - return STATE_NOT_FOUND; - } - if (!validateDBVersion(mDb.getVersion(), c.getInt(0))) { - return STATE_NOT_FOUND; - } - - mRestoredGridX = c.getInt(1); - mRestoredGridY = c.getInt(2); - mRestoredHotseatSize = c.getInt(3); - boolean isSanitized = (c.getInt(4) & OPTION_REQUIRES_SANITIZATION) == 0; - return isSanitized ? STATE_SANITIZED : STATE_RAW; - } - } - - /** - * Restore workspace from raw backup if available. - */ - public boolean restoreFromRawBackupIfAvailable(long oldProfileId) { - if (!tableExists(mDb, Favorites.BACKUP_TABLE_NAME) - || loadDBProperties() != STATE_RAW - || mOldHotseatSize != mRestoredHotseatSize - || mOldGridX != mRestoredGridX - || mOldGridY != mRestoredGridY) { - // skip restore if dimensions in backup table differs from current setup. - return false; - } - copyTable(mDb, Favorites.BACKUP_TABLE_NAME, Favorites.TABLE_NAME, oldProfileId); - Log.d(TAG, "Backup restored"); - return true; - } - - /** - * Performs a backup on the workspace layout. - */ - public void doBackup(long profileId, int options) { - copyTable(mDb, Favorites.TABLE_NAME, Favorites.BACKUP_TABLE_NAME, profileId); - encodeDBProperties(options); - } - - private static boolean validateDBVersion(int expected, int actual) { - if (expected != actual) { - Log.e(TAG, String.format("Launcher.db version mismatch, expecting %d but %d was found", - expected, actual)); - return false; - } - return true; + db.execSQL("INSERT INTO " + to + " SELECT * FROM " + from); } } diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index c4eb14f8c2..ba5249c144 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -39,21 +39,19 @@ import android.util.LongSparseArray; import android.util.SparseLongArray; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.AppWidgetsRestoredReceiver; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.DeviceGridState; -import com.android.launcher3.model.GridBackupTable; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.LauncherAppWidgetInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; -import com.android.launcher3.pm.UserCache; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.uioverrides.ApiWrapper; import com.android.launcher3.util.IntArray; @@ -108,7 +106,6 @@ public class RestoreDbTask { SQLiteDatabase db = helper.getWritableDatabase(); try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); - task.backupWorkspace(context, db); task.sanitizeDB(context, helper, db, new BackupManager(context)); task.restoreAppWidgetIdsIfExists(context); t.commit(); @@ -119,49 +116,6 @@ public class RestoreDbTask { } } - /** - * Restore the workspace if backup is available. - */ - public static boolean restoreIfPossible(@NonNull Context context, - @NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) { - final SQLiteDatabase db = helper.getWritableDatabase(); - try (SQLiteTransaction t = new SQLiteTransaction(db)) { - RestoreDbTask task = new RestoreDbTask(); - task.restoreWorkspace(context, db, helper, backupManager); - t.commit(); - return true; - } catch (Exception e) { - FileLog.e(TAG, "Failed to restore db", e); - return false; - } - } - - /** - * Backup the workspace so that if things go south in restore, we can recover these entries. - */ - private void backupWorkspace(Context context, SQLiteDatabase db) throws Exception { - InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows) - .doBackup(getDefaultProfileId(db), GridBackupTable.OPTION_REQUIRES_SANITIZATION); - } - - private void restoreWorkspace(@NonNull Context context, @NonNull SQLiteDatabase db, - @NonNull DatabaseHelper helper, @NonNull BackupManager backupManager) - throws Exception { - final InvariantDeviceProfile idp = LauncherAppState.getIDP(context); - GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, - idp.numColumns, idp.numRows); - if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) { - int itemsDeleted = sanitizeDB(context, helper, db, backupManager); - LauncherAppState.getInstance(context).getModel().forceReload(); - restoreAppWidgetIdsIfExists(context); - if (itemsDeleted == 0) { - // all the items are restored, we no longer need the backup table - dropTable(db, Favorites.BACKUP_TABLE_NAME); - } - } - } - /** * Makes the following changes in the provider DB. * 1. Removes all entries belonging to any profiles that were not restored. @@ -174,7 +128,8 @@ public class RestoreDbTask { * * @return number of items deleted. */ - private int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, + @VisibleForTesting + protected int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids long myProfileId = helper.getDefaultUserSerial(); @@ -258,7 +213,7 @@ public class RestoreDbTask { } // Override shortcuts - maybeOverrideShortcuts(context, db, myProfileId); + maybeOverrideShortcuts(context, helper, db, myProfileId); return itemsDeleted; } @@ -388,8 +343,8 @@ public class RestoreDbTask { APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString())); } - protected static void maybeOverrideShortcuts(Context context, SQLiteDatabase db, - long currentUser) { + protected static void maybeOverrideShortcuts(Context context, DatabaseHelper helper, + SQLiteDatabase db, long currentUser) { Map activityOverrides = ApiWrapper.getActivityOverrides( context); @@ -412,8 +367,7 @@ public class RestoreDbTask { if (override != null) { ContentValues values = new ContentValues(); values.put(Favorites.PROFILE_ID, - UserCache.INSTANCE.get(context).getSerialNumberForUser( - override.getUser())); + helper.getSerialNumberForUser(override.getUser())); values.put(Favorites.INTENT, AppInfo.makeLaunchIntent(override).toUri(0)); db.update(Favorites.TABLE_NAME, values, String.format("%s=?", Favorites._ID), new String[]{String.valueOf(c.getInt(idIndex))}); diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java index ee64e9865d..55c2585f4a 100644 --- a/src/com/android/launcher3/util/ContentWriter.java +++ b/src/com/android/launcher3/util/ContentWriter.java @@ -118,21 +118,9 @@ public class ContentWriter { final String[] mSelectionArgs; public CommitParams(String where, String[] selectionArgs) { - this(LauncherSettings.Favorites.CONTENT_URI, where, selectionArgs); - } - - private CommitParams(Uri uri, String where, String[] selectionArgs) { - mUri = uri; + mUri = LauncherSettings.Favorites.CONTENT_URI; mWhere = where; mSelectionArgs = selectionArgs; } - - /** - * Creates commit params for backup table. - */ - public static CommitParams backupCommitParams(String where, String[] selectionArgs) { - return new CommitParams( - LauncherSettings.Favorites.BACKUP_CONTENT_URI, where, selectionArgs); - } } } diff --git a/tests/src/com/android/launcher3/model/BackupRestoreTest.java b/tests/src/com/android/launcher3/model/BackupRestoreTest.java deleted file mode 100644 index 41914de1ab..0000000000 --- a/tests/src/com/android/launcher3/model/BackupRestoreTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.model; - -import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE; -import static android.os.Process.myUserHandle; - -import static com.android.launcher3.LauncherSettings.Favorites.BACKUP_TABLE_NAME; -import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; -import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb; -import static com.android.launcher3.provider.LauncherDbUtils.dropTable; -import static com.android.launcher3.provider.LauncherDbUtils.tableExists; -import static com.android.launcher3.util.LauncherModelHelper.APP_ICON; -import static com.android.launcher3.util.LauncherModelHelper.NO__ICON; -import static com.android.launcher3.util.LauncherModelHelper.SHORTCUT; -import static com.android.launcher3.util.ReflectionHelpers.getField; -import static com.android.launcher3.util.ReflectionHelpers.setField; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - -import android.app.backup.BackupManager; -import android.content.pm.PackageInstaller; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.os.UserHandle; -import android.util.ArrayMap; -import android.util.LongSparseArray; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; - -import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.pm.UserCache; -import com.android.launcher3.provider.RestoreDbTask; -import com.android.launcher3.util.LauncherModelHelper; -import com.android.launcher3.util.SafeCloseable; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests to verify backup and restore flow. - */ -@SmallTest -@RunWith(AndroidJUnit4.class) -public class BackupRestoreTest { - - private static final int PER_USER_RANGE = 200000; - - - private long mCurrentMyProfileId; - private long mOldMyProfileId; - - private long mCurrentWorkProfileId; - private long mOldWorkProfileId; - - private BackupManager mBackupManager; - private LauncherModelHelper mModelHelper; - private SQLiteDatabase mDb; - private InvariantDeviceProfile mIdp; - - private UserHandle mWorkUserHandle; - - private SafeCloseable mUserChangeListener; - - @Before - public void setUp() { - mModelHelper = new LauncherModelHelper(); - - mCurrentMyProfileId = mModelHelper.defaultProfileId; - mOldMyProfileId = mCurrentMyProfileId + 1; - mCurrentWorkProfileId = mOldMyProfileId + 1; - mOldWorkProfileId = mCurrentWorkProfileId + 1; - - mWorkUserHandle = UserHandle.getUserHandleForUid(PER_USER_RANGE); - mUserChangeListener = UserCache.INSTANCE.get(mModelHelper.sandboxContext) - .addUserChangeListener(() -> { }); - - setupUserManager(); - setupBackupManager(); - RestoreDbTask.setPending(mModelHelper.sandboxContext); - mDb = mModelHelper.provider.getDb(); - mIdp = InvariantDeviceProfile.INSTANCE.get(mModelHelper.sandboxContext); - - } - - @After - public void tearDown() { - mUserChangeListener.close(); - mModelHelper.destroy(); - } - - private void setupUserManager() { - UserCache cache = UserCache.INSTANCE.get(mModelHelper.sandboxContext); - synchronized (cache) { - LongSparseArray users = getField(cache, "mUsers"); - users.clear(); - users.put(mCurrentMyProfileId, myUserHandle()); - users.put(mCurrentWorkProfileId, mWorkUserHandle); - - ArrayMap userMap = getField(cache, "mUserToSerialMap"); - userMap.clear(); - userMap.put(myUserHandle(), mCurrentMyProfileId); - userMap.put(mWorkUserHandle, mCurrentWorkProfileId); - } - } - - private void setupBackupManager() { - mBackupManager = spy(new BackupManager(mModelHelper.sandboxContext)); - doReturn(myUserHandle()).when(mBackupManager) - .getUserForAncestralSerialNumber(eq(mOldMyProfileId)); - doReturn(mWorkUserHandle).when(mBackupManager) - .getUserForAncestralSerialNumber(eq(mOldWorkProfileId)); - } - - @Test - public void testOnCreateDbIfNotExists_CreatesBackup() { - assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); - } - - @Test - public void testOnRestoreSessionWithValidCondition_PerformsRestore() throws Exception { - setupBackup(); - verifyTableIsFilled(BACKUP_TABLE_NAME, false); - verifyTableIsEmpty(TABLE_NAME); - createRestoreSession(); - verifyTableIsFilled(TABLE_NAME, true); - } - - private void setupBackup() { - createTableUsingOldProfileId(); - // setup grid for main user on first screen - mModelHelper.createGrid(new int[][][]{{ - { APP_ICON, APP_ICON, SHORTCUT, SHORTCUT}, - { SHORTCUT, SHORTCUT, NO__ICON, NO__ICON}, - { NO__ICON, NO__ICON, SHORTCUT, SHORTCUT}, - { APP_ICON, SHORTCUT, SHORTCUT, APP_ICON}, - }}, 1, mOldMyProfileId); - // setup grid for work profile on second screen - mModelHelper.createGrid(new int[][][]{{ - { NO__ICON, APP_ICON, SHORTCUT, SHORTCUT}, - { SHORTCUT, SHORTCUT, NO__ICON, NO__ICON}, - { NO__ICON, NO__ICON, SHORTCUT, SHORTCUT}, - { APP_ICON, SHORTCUT, SHORTCUT, NO__ICON}, - }}, 2, mOldWorkProfileId); - // simulates the creation of backup upon restore - new GridBackupTable(mModelHelper.sandboxContext, mDb, mIdp.numDatabaseHotseatIcons, - mIdp.numColumns, mIdp.numRows).doBackup( - mOldMyProfileId, GridBackupTable.OPTION_REQUIRES_SANITIZATION); - // reset favorites table - createTableUsingOldProfileId(); - } - - private void verifyTableIsEmpty(String tableName) { - assertEquals(0, getCount(mDb, "SELECT * FROM " + tableName)); - } - - private void verifyTableIsFilled(String tableName, boolean sanitized) { - assertEquals(sanitized ? 12 : 13, getCount(mDb, - "SELECT * FROM " + tableName + " WHERE profileId = " - + (sanitized ? mCurrentMyProfileId : mOldMyProfileId))); - assertEquals(10, getCount(mDb, "SELECT * FROM " + tableName + " WHERE profileId = " - + (sanitized ? mCurrentWorkProfileId : mOldWorkProfileId))); - } - - private void createTableUsingOldProfileId() { - // simulates the creation of favorites table on old device - dropTable(mDb, TABLE_NAME); - addTableToDb(mDb, mOldMyProfileId, false); - } - - private void createRestoreSession() throws Exception { - final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( - PackageInstaller.SessionParams.MODE_FULL_INSTALL); - final PackageInstaller installer = mModelHelper.sandboxContext.getPackageManager() - .getPackageInstaller(); - final int sessionId = installer.createSession(params); - final PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId); - setField(info, "installReason", INSTALL_REASON_DEVICE_RESTORE); - // TODO: (b/148410677) we should verify the following call instead - // InstallSessionHelper.INSTANCE.get(getContext()).restoreDbIfApplicable(info); - RestoreDbTask.restoreIfPossible(mModelHelper.sandboxContext, - mModelHelper.provider.getHelper(), mBackupManager); - } - - private static int getCount(SQLiteDatabase db, String sql) { - try (Cursor c = db.rawQuery(sql, null)) { - return c.getCount(); - } - } -} diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java index aa091b630d..67de1f5fb1 100644 --- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java @@ -15,17 +15,35 @@ */ package com.android.launcher3.provider; +import static android.os.Process.myUserHandle; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP; +import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import android.app.backup.BackupManager; import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.LongSparseArray; -import androidx.test.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.model.DatabaseHelper; @@ -39,6 +57,10 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class RestoreDbTaskTest { + private static final int PER_USER_RANGE = 200000; + + private final UserHandle mWorkUser = UserHandle.getUserHandleForUid(PER_USER_RANGE); + @Test public void testGetProfileId() throws Exception { SQLiteDatabase db = new MyDatabaseHelper(23).getWritableDatabase(); @@ -88,6 +110,90 @@ public class RestoreDbTaskTest { assertEquals(1, getCount(db, "select * from favorites where profileId = 33")); } + @Test + public void testSanitizeDB_bothProfiles() throws Exception { + Context context = getInstrumentation().getTargetContext(); + UserHandle myUser = myUserHandle(); + long myProfileId = context.getSystemService(UserManager.class) + .getSerialNumberForUser(myUser); + long myProfileId_old = myProfileId + 1; + long workProfileId = myProfileId + 2; + long workProfileId_old = myProfileId + 3; + + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); + BackupManager bm = spy(new BackupManager(context)); + doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); + doReturn(mWorkUser).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); + helper.users.put(workProfileId, mWorkUser); + + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); + assertEquals(10, getItemCountForProfile(db, myProfileId_old)); + assertEquals(6, getItemCountForProfile(db, workProfileId_old)); + + RestoreDbTask task = new RestoreDbTask(); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); + + // All the data has been migrated to the new user ids + assertEquals(0, getItemCountForProfile(db, myProfileId_old)); + assertEquals(0, getItemCountForProfile(db, workProfileId_old)); + assertEquals(10, getItemCountForProfile(db, myProfileId)); + assertEquals(6, getItemCountForProfile(db, workProfileId)); + } + + @Test + public void testSanitizeDB_workItemsRemoved() throws Exception { + Context context = getInstrumentation().getTargetContext(); + UserHandle myUser = myUserHandle(); + long myProfileId = context.getSystemService(UserManager.class) + .getSerialNumberForUser(myUser); + long myProfileId_old = myProfileId + 1; + long workProfileId_old = myProfileId + 3; + + MyDatabaseHelper helper = new MyDatabaseHelper(myProfileId); + SQLiteDatabase db = helper.getWritableDatabase(); + BackupManager bm = spy(new BackupManager(context)); + doReturn(myUserHandle()).when(bm).getUserForAncestralSerialNumber(eq(myProfileId_old)); + // Work profile is not migrated + doReturn(null).when(bm).getUserForAncestralSerialNumber(eq(workProfileId_old)); + + addIconsBulk(helper, 10, 1, myProfileId_old); + addIconsBulk(helper, 6, 2, workProfileId_old); + assertEquals(10, getItemCountForProfile(db, myProfileId_old)); + assertEquals(6, getItemCountForProfile(db, workProfileId_old)); + + RestoreDbTask task = new RestoreDbTask(); + task.sanitizeDB(context, helper, helper.getWritableDatabase(), bm); + + // All the data has been migrated to the new user ids + assertEquals(0, getItemCountForProfile(db, myProfileId_old)); + assertEquals(0, getItemCountForProfile(db, workProfileId_old)); + assertEquals(10, getItemCountForProfile(db, myProfileId)); + assertEquals(10, getCount(db, "select * from favorites")); + } + + private void addIconsBulk(DatabaseHelper helper, int count, int screen, long profileId) { + int columns = LauncherAppState.getIDP(getInstrumentation().getTargetContext()).numColumns; + String packageName = getInstrumentation().getContext().getPackageName(); + for (int i = 0; i < count; i++) { + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites._ID, helper.generateNewItemId()); + values.put(LauncherSettings.Favorites.CONTAINER, CONTAINER_DESKTOP); + values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.CELLX, i % columns); + values.put(LauncherSettings.Favorites.CELLY, i / columns); + values.put(LauncherSettings.Favorites.SPANX, 1); + values.put(LauncherSettings.Favorites.SPANY, 1); + values.put(LauncherSettings.Favorites.PROFILE_ID, profileId); + values.put(LauncherSettings.Favorites.ITEM_TYPE, ITEM_TYPE_APPLICATION); + values.put(LauncherSettings.Favorites.INTENT, + new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0)); + helper.getWritableDatabase().insert(TABLE_NAME, null, values); + } + } + + @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( @@ -116,7 +222,7 @@ public class RestoreDbTaskTest { ContentValues values = new ContentValues(); values.put(Favorites._ID, i); values.put(Favorites.SCREEN, screenIds[i]); - values.put(Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP); + values.put(Favorites.CONTAINER, CONTAINER_DESKTOP); db.insert(Favorites.TABLE_NAME, null, values); } // Verify items are added @@ -138,6 +244,10 @@ public class RestoreDbTaskTest { assertArrayEquals(expectedScreenIds, resultScreenIds); } + public int getItemCountForProfile(SQLiteDatabase db, long profileId) { + return getCount(db, "select * from favorites where profileId = " + profileId); + } + private int getCount(SQLiteDatabase db, String sql) { try (Cursor c = db.rawQuery(sql, null)) { return c.getCount(); @@ -146,16 +256,18 @@ public class RestoreDbTaskTest { private class MyDatabaseHelper extends DatabaseHelper { - private final long mProfileId; + public final LongSparseArray users; MyDatabaseHelper(long profileId) { - super(InstrumentationRegistry.getInstrumentation().getTargetContext(), null, false); - mProfileId = profileId; + super(getInstrumentation().getTargetContext(), null, false); + users = new LongSparseArray<>(); + users.put(profileId, myUserHandle()); } @Override - public long getDefaultUserSerial() { - return mProfileId; + public long getSerialNumberForUser(UserHandle user) { + int index = users.indexOfValue(user); + return index >= 0 ? users.keyAt(index) : -1; } @Override diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index 5548364927..9e88c06a9c 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -61,7 +61,6 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.model.AllAppsList; import com.android.launcher3.model.BgDataModel; import com.android.launcher3.model.BgDataModel.Callbacks; -import com.android.launcher3.model.DatabaseHelper; import com.android.launcher3.model.ItemInstallQueue; import com.android.launcher3.model.ModelDbController; import com.android.launcher3.model.data.AppInfo; @@ -371,54 +370,6 @@ public class LauncherModelHelper { sandboxContext.getContentResolver().delete(uri, null, null); } - public int[][][] createGrid(int[][][] typeArray) { - return createGrid(typeArray, 1); - } - - public int[][][] createGrid(int[][][] typeArray, int startScreen) { - LauncherSettings.Settings.call(sandboxContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); - LauncherSettings.Settings.call(sandboxContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG); - return createGrid(typeArray, startScreen, defaultProfileId); - } - - /** - * Initializes the DB with mock elements to represent the provided grid structure. - * @param typeArray A 3d array of item types. {@see #addItem(int, long, long, int, int)} for - * type definitions. The first dimension represents the screens and the next - * two represent the workspace grid. - * @param startScreen First screen id from where the icons will be added. - * @return the same grid representation where each entry is the corresponding item id. - */ - public int[][][] createGrid(int[][][] typeArray, int startScreen, long profileId) { - int[][][] ids = new int[typeArray.length][][]; - for (int i = 0; i < typeArray.length; i++) { - // Add screen to DB - int screenId = startScreen + i; - - // Keep the screen id counter up to date - LauncherSettings.Settings.call(sandboxContext.getContentResolver(), - LauncherSettings.Settings.METHOD_NEW_SCREEN_ID); - - ids[i] = new int[typeArray[i].length][]; - for (int y = 0; y < typeArray[i].length; y++) { - ids[i][y] = new int[typeArray[i][y].length]; - for (int x = 0; x < typeArray[i][y].length; x++) { - if (typeArray[i][y][x] < 0) { - // Empty cell - ids[i][y][x] = -1; - } else { - ids[i][y][x] = addItem( - typeArray[i][y][x], screenId, DESKTOP, x, y, profileId); - } - } - } - } - - return ids; - } - /** * Sets up a mock provider to load the provided layout by default, next time the layout loads */ @@ -479,10 +430,6 @@ public class LauncherModelHelper { public SQLiteDatabase getDb() { return mModelDbController.getDatabaseHelper().getWritableDatabase(); } - - public DatabaseHelper getHelper() { - return mModelDbController.getDatabaseHelper(); - } } public static boolean deleteContents(File dir) {