diff options
11 files changed, 556 insertions, 214 deletions
diff --git a/robolectric_tests/src/com/android/launcher3/model/BaseGridChangesTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseGridChangesTestCase.java new file mode 100644 index 000000000..07834fcd0 --- /dev/null +++ b/robolectric_tests/src/com/android/launcher3/model/BaseGridChangesTestCase.java @@ -0,0 +1,121 @@ +package com.android.launcher3.model; + +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.sqlite.SQLiteDatabase; + +import com.android.launcher3.LauncherProvider; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.util.TestLauncherProvider; + +import org.junit.Before; +import org.robolectric.Robolectric; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowContentResolver; +import org.robolectric.shadows.ShadowLog; + +public abstract class BaseGridChangesTestCase { + + + public static final int DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP; + public static final int HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT; + + public static final int APP_ICON = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + public static final int SHORTCUT = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; + public static final int NO__ICON = -1; + + public static final String TEST_PACKAGE = "com.android.launcher3.validpackage"; + + public Context mContext; + public TestLauncherProvider mProvider; + public SQLiteDatabase mDb; + + @Before + public void setUpBaseCase() { + ShadowLog.stream = System.out; + + mContext = RuntimeEnvironment.application; + mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class); + ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider); + mDb = mProvider.getDb(); + } + + /** + * Adds a dummy item in the DB. + * @param type {@link #APP_ICON} or {@link #SHORTCUT} or >= 2 for + * folder (where the type represents the number of items in the folder). + */ + public int addItem(int type, int screen, int container, int x, int y) { + int id = LauncherSettings.Settings.call(mContext.getContentResolver(), + LauncherSettings.Settings.METHOD_NEW_ITEM_ID) + .getInt(LauncherSettings.Settings.EXTRA_VALUE); + + ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites._ID, id); + values.put(LauncherSettings.Favorites.CONTAINER, container); + values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.CELLX, x); + values.put(LauncherSettings.Favorites.CELLY, y); + values.put(LauncherSettings.Favorites.SPANX, 1); + values.put(LauncherSettings.Favorites.SPANY, 1); + + if (type == APP_ICON || type == SHORTCUT) { + values.put(LauncherSettings.Favorites.ITEM_TYPE, type); + values.put(LauncherSettings.Favorites.INTENT, + new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0)); + } else { + values.put(LauncherSettings.Favorites.ITEM_TYPE, + LauncherSettings.Favorites.ITEM_TYPE_FOLDER); + // Add folder items. + for (int i = 0; i < type; i++) { + addItem(APP_ICON, 0, id, 0, 0); + } + } + + mContext.getContentResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values); + return id; + } + + public int[][][] createGrid(int[][][] typeArray) { + return createGrid(typeArray, 1); + } + + /** + * Initializes the DB with dummy 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) { + LauncherSettings.Settings.call(mContext.getContentResolver(), + LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); + 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(mContext.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); + } + } + } + } + + return ids; + } +} diff --git a/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java b/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java new file mode 100644 index 000000000..53287a98b --- /dev/null +++ b/robolectric_tests/src/com/android/launcher3/model/GridBackupTableTest.java @@ -0,0 +1,115 @@ +package com.android.launcher3.model; + + +import static android.database.DatabaseUtils.queryNumEntries; + +import static com.android.launcher3.LauncherSettings.Favorites.BACKUP_TABLE_NAME; +import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; +import static com.android.launcher3.provider.LauncherDbUtils.tableExists; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.content.ContentValues; +import android.graphics.Point; + +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +/** + * Unit tests for {@link GridBackupTable} + */ +@RunWith(RobolectricTestRunner.class) +public class GridBackupTableTest extends BaseGridChangesTestCase { + + private static final int BACKUP_ITEM_COUNT = 12; + + @Before + public void setupGridData() { + 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}, + }}); + assertEquals(BACKUP_ITEM_COUNT, queryNumEntries(mDb, TABLE_NAME)); + } + + @Test + public void backupTableCreated() { + GridBackupTable backupTable = new GridBackupTable(mContext, mDb, 4, 4, 4); + assertFalse(backupTable.backupOrRestoreAsNeeded()); + Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + + assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); + + // One extra entry for properties + assertEquals(BACKUP_ITEM_COUNT + 1, queryNumEntries(mDb, BACKUP_TABLE_NAME)); + } + + @Test + public void backupTableRestored() { + assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded()); + Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + + // Delete entries + mDb.delete(TABLE_NAME, null, null); + assertEquals(0, queryNumEntries(mDb, TABLE_NAME)); + + GridBackupTable backupTable = new GridBackupTable(mContext, mDb, 3, 3, 3); + assertTrue(backupTable.backupOrRestoreAsNeeded()); + + // Items have been restored + assertEquals(BACKUP_ITEM_COUNT, queryNumEntries(mDb, TABLE_NAME)); + + Point outSize = new Point(); + assertEquals(4, backupTable.getRestoreHotseatAndGridSize(outSize)); + assertEquals(4, outSize.x); + assertEquals(4, outSize.y); + } + + @Test + public void backupTableRemovedOnAdd() { + assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded()); + Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + + assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); + + addItem(1, 2, DESKTOP, 1, 1); + assertFalse(tableExists(mDb, BACKUP_TABLE_NAME)); + } + + @Test + public void backupTableRemovedOnDelete() { + assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded()); + Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + + assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); + + mContext.getContentResolver().delete(Favorites.CONTENT_URI, null, null); + assertFalse(tableExists(mDb, BACKUP_TABLE_NAME)); + } + + @Test + public void backupTableRetainedOnUpdate() { + assertFalse(new GridBackupTable(mContext, mDb, 4, 4, 4).backupOrRestoreAsNeeded()); + Settings.call(mContext.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); + + assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); + + ContentValues values = new ContentValues(); + values.put(Favorites.RANK, 4); + // Something was updated + assertTrue(mContext.getContentResolver() + .update(Favorites.CONTENT_URI, values, null, null) > 0); + + // Backup table remains + assertTrue(tableExists(mDb, BACKUP_TABLE_NAME)); + } +} diff --git a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java index d4188aa8e..ce07a273f 100644 --- a/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java +++ b/robolectric_tests/src/com/android/launcher3/model/GridSizeMigrationTaskTest.java @@ -5,29 +5,21 @@ import static com.android.launcher3.model.GridSizeMigrationTask.getWorkspaceScre import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; import android.database.Cursor; import android.graphics.Point; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherSettings; import com.android.launcher3.config.FlagOverrideRule; import com.android.launcher3.config.FlagOverrideRule.FlagOverride; import com.android.launcher3.model.GridSizeMigrationTask.MultiStepMigrationTask; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.TestLauncherProvider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.shadows.ShadowContentResolver; import java.util.HashSet; import java.util.LinkedList; @@ -36,47 +28,33 @@ import java.util.LinkedList; * Unit tests for {@link GridSizeMigrationTask} */ @RunWith(RobolectricTestRunner.class) -public class GridSizeMigrationTaskTest { - - private static final int DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP; - private static final int HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT; - - private static final int APPLICATION = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; - private static final int SHORTCUT = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; - - private static final String TEST_PACKAGE = "com.android.launcher3.validpackage"; +public class GridSizeMigrationTaskTest extends BaseGridChangesTestCase { @Rule public final FlagOverrideRule flags = new FlagOverrideRule(); private HashSet<String> mValidPackages; private InvariantDeviceProfile mIdp; - private Context mContext; - private TestLauncherProvider mProvider; @Before public void setUp() { mValidPackages = new HashSet<>(); mValidPackages.add(TEST_PACKAGE); mIdp = new InvariantDeviceProfile(); - mContext = RuntimeEnvironment.application; - - mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class); - ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider); } @Test public void testHotseatMigration_apps_dropped() throws Exception { int[] hotseatItems = { - addItem(APPLICATION, 0, HOTSEAT, 0, 0), + addItem(APP_ICON, 0, HOTSEAT, 0, 0), addItem(SHORTCUT, 1, HOTSEAT, 0, 0), -1, addItem(SHORTCUT, 3, HOTSEAT, 0, 0), - addItem(APPLICATION, 4, HOTSEAT, 0, 0), + addItem(APP_ICON, 4, HOTSEAT, 0, 0), }; mIdp.numHotseatIcons = 3; - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3) + new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]); @@ -85,7 +63,7 @@ public class GridSizeMigrationTaskTest { @Test public void testHotseatMigration_shortcuts_dropped() throws Exception { int[] hotseatItems = { - addItem(APPLICATION, 0, HOTSEAT, 0, 0), + addItem(APP_ICON, 0, HOTSEAT, 0, 0), addItem(30, 1, HOTSEAT, 0, 0), -1, addItem(SHORTCUT, 3, HOTSEAT, 0, 0), @@ -93,7 +71,7 @@ public class GridSizeMigrationTaskTest { }; mIdp.numHotseatIcons = 3; - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, 5, 3) + new GridSizeMigrationTask(mContext, mDb, mValidPackages, 5, 3) .migrateHotseat(); // First item is dropped as it has the least weight. verifyHotseat(hotseatItems[1], hotseatItems[3], hotseatItems[4]); @@ -138,7 +116,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Column 2 and row 2 got removed. @@ -158,7 +136,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column get moved to new screen @@ -183,7 +161,7 @@ public class GridSizeMigrationTaskTest { { 3, 1, -1, 4}, }}); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on the 3rd @@ -215,7 +193,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, -1, 6}, }}); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -244,7 +222,7 @@ public class GridSizeMigrationTaskTest { { 5, 2, 7, -1}, }}, 0); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 4)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -269,7 +247,7 @@ public class GridSizeMigrationTaskTest { { 5, 6, 7, -1}, }}, 0); - new GridSizeMigrationTask(mContext, mIdp, mValidPackages, + new GridSizeMigrationTask(mContext, mDb, mValidPackages, new Point(4, 4), new Point(3, 3)).migrateWorkspace(); // Items in the second column of the first screen should get placed on a new screen. @@ -283,54 +261,13 @@ public class GridSizeMigrationTaskTest { }}); } - private int[][][] createGrid(int[][][] typeArray) throws Exception { - return createGrid(typeArray, 1); - } - - /** - * Initializes the DB with dummy 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. - * @return the same grid representation where each entry is the corresponding item id. - */ - private int[][][] createGrid(int[][][] typeArray, int startScreen) throws Exception { - LauncherSettings.Settings.call(mContext.getContentResolver(), - LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB); - 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(mContext.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); - } - } - } - } - - return ids; - } - /** * Verifies that the workspace items are arranged in the provided order. * @param ids A 3d array where the first dimension represents the screen, and the rest two * represent the workspace grid. */ private void verifyWorkspace(int[][][] ids) { - IntArray allScreens = getWorkspaceScreenIds(mContext); + IntArray allScreens = getWorkspaceScreenIds(mDb); assertEquals(ids.length, allScreens.size()); int total = 0; @@ -367,42 +304,6 @@ public class GridSizeMigrationTaskTest { c.close(); } - /** - * Adds a dummy item in the DB. - * @param type {@link #APPLICATION} or {@link #SHORTCUT} or >= 2 for - * folder (where the type represents the number of items in the folder). - */ - private int addItem(int type, int screen, int container, int x, int y) throws Exception { - int id = LauncherSettings.Settings.call(mContext.getContentResolver(), - LauncherSettings.Settings.METHOD_NEW_ITEM_ID) - .getInt(LauncherSettings.Settings.EXTRA_VALUE); - - ContentValues values = new ContentValues(); - values.put(LauncherSettings.Favorites._ID, id); - values.put(LauncherSettings.Favorites.CONTAINER, container); - values.put(LauncherSettings.Favorites.SCREEN, screen); - values.put(LauncherSettings.Favorites.CELLX, x); - values.put(LauncherSettings.Favorites.CELLY, y); - values.put(LauncherSettings.Favorites.SPANX, 1); - values.put(LauncherSettings.Favorites.SPANY, 1); - - if (type == APPLICATION || type == SHORTCUT) { - values.put(LauncherSettings.Favorites.ITEM_TYPE, type); - values.put(LauncherSettings.Favorites.INTENT, - new Intent(Intent.ACTION_MAIN).setPackage(TEST_PACKAGE).toUri(0)); - } else { - values.put(LauncherSettings.Favorites.ITEM_TYPE, - LauncherSettings.Favorites.ITEM_TYPE_FOLDER); - // Add folder items. - for (int i = 0; i < type; i++) { - addItem(APPLICATION, 0, id, 0, 0); - } - } - - mContext.getContentResolver().insert(LauncherSettings.Favorites.CONTENT_URI, values); - return id; - } - @Test public void testMultiStepMigration_small_to_large() throws Exception { MultiStepMigrationTaskVerifier verifier = new MultiStepMigrationTaskVerifier(); @@ -435,7 +336,7 @@ public class GridSizeMigrationTaskTest { private final LinkedList<Point> mPoints; public MultiStepMigrationTaskVerifier(int... points) { - super(null, null); + super(null, null, null); mPoints = new LinkedList<>(); for (int i = 0; i < points.length; i += 2) { diff --git a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java index 32808f572..31e303eb3 100644 --- a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java +++ b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java @@ -23,6 +23,11 @@ public class TestLauncherProvider extends LauncherProvider { } } + public SQLiteDatabase getDb() { + createDbIfNotExists(); + return mOpenHelper.getWritableDatabase(); + } + @Override protected void notifyListeners() { } diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 8ed3314ef..24dc17a8b 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -16,6 +16,9 @@ package com.android.launcher3; +import static com.android.launcher3.provider.LauncherDbUtils.dropTable; +import static com.android.launcher3.provider.LauncherDbUtils.tableExists; + import android.annotation.TargetApi; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; @@ -210,6 +213,7 @@ public class LauncherProvider extends ContentProvider { addModifiedTime(initialValues); final int rowId = dbInsertAndCheck(mOpenHelper, db, args.table, null, initialValues); if (rowId < 0) return null; + mOpenHelper.onAddOrDeleteOp(db); uri = ContentUris.withAppendedId(uri, rowId); notifyListeners(); @@ -282,6 +286,7 @@ public class LauncherProvider extends ContentProvider { return 0; } } + mOpenHelper.onAddOrDeleteOp(db); t.commit(); } @@ -290,15 +295,30 @@ public class LauncherProvider extends ContentProvider { return values.length; } + @TargetApi(Build.VERSION_CODES.M) @Override public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { createDbIfNotExists(); try (SQLiteTransaction t = new SQLiteTransaction(mOpenHelper.getWritableDatabase())) { - ContentProviderResult[] result = super.applyBatch(operations); + boolean isAddOrDelete = !Utilities.ATLEAST_MARSHMALLOW; + + final int numOperations = operations.size(); + final ContentProviderResult[] results = new ContentProviderResult[numOperations]; + for (int i = 0; i < numOperations; i++) { + ContentProviderOperation op = operations.get(i); + results[i] = op.apply(this, results, i); + + isAddOrDelete |= (op.isInsert() || op.isDelete()) && + results[i].count != null && results[i].count > 0; + } + if (isAddOrDelete) { + mOpenHelper.onAddOrDeleteOp(t.getDb()); + } + t.commit(); reloadLauncherIfExternal(); - return result; + return results; } } @@ -315,6 +335,7 @@ public class LauncherProvider extends ContentProvider { } int count = db.delete(args.table, args.where, args.args); if (count > 0) { + mOpenHelper.onAddOrDeleteOp(db); notifyListeners(); reloadLauncherIfExternal(); } @@ -381,6 +402,17 @@ public class LauncherProvider extends ContentProvider { mOpenHelper.removeGhostWidgets(mOpenHelper.getWritableDatabase()); return null; } + case LauncherSettings.Settings.METHOD_NEW_TRANSACTION: { + Bundle result = new Bundle(); + result.putBinder(LauncherSettings.Settings.EXTRA_VALUE, + new SQLiteTransaction(mOpenHelper.getWritableDatabase())); + return result; + } + case LauncherSettings.Settings.METHOD_REFRESH_BACKUP_TABLE: { + mOpenHelper.mBackupTableExists = + tableExists(mOpenHelper.getReadableDatabase(), Favorites.BACKUP_TABLE_NAME); + return null; + } } return null; } @@ -528,17 +560,19 @@ public class LauncherProvider extends ContentProvider { private final Context mContext; private int mMaxItemId = -1; private int mMaxScreenId = -1; + private boolean mBackupTableExists; DatabaseHelper(Context context, Handler widgetHostResetHandler) { this(context, widgetHostResetHandler, LauncherFiles.LAUNCHER_DB); // 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(Favorites.TABLE_NAME)) { + if (!tableExists(getReadableDatabase(), Favorites.TABLE_NAME)) { Log.e(TAG, "Tables are missing after onCreate has been called. Trying to recreate"); // This operation is a no-op if the table already exists. addFavoritesTable(getWritableDatabase(), true); } + mBackupTableExists = tableExists(getReadableDatabase(), Favorites.BACKUP_TABLE_NAME); initIds(); } @@ -564,18 +598,6 @@ public class LauncherProvider extends ContentProvider { } } - private boolean tableExists(String tableName) { - Cursor c = getReadableDatabase().query( - true, "sqlite_master", new String[] {"tbl_name"}, - "tbl_name = ?", new String[] {tableName}, - null, null, null, null, null); - try { - return c.getCount() > 0; - } finally { - c.close(); - } - } - @Override public void onCreate(SQLiteDatabase db) { if (LOGD) Log.d(TAG, "creating new launcher database"); @@ -590,6 +612,13 @@ public class LauncherProvider extends ContentProvider { onEmptyDbCreated(); } + protected void onAddOrDeleteOp(SQLiteDatabase db) { + if (mBackupTableExists) { + dropTable(db, Favorites.BACKUP_TABLE_NAME); + mBackupTableExists = false; + } + } + /** * Overriden in tests. */ @@ -733,7 +762,7 @@ public class LauncherProvider extends ContentProvider { Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP); db.execSQL(query); } - db.execSQL("DROP TABLE IF EXISTS workspaceScreens"); + dropTable(db, "workspaceScreens"); } case 28: // DB Upgraded successfully @@ -762,8 +791,8 @@ public class LauncherProvider extends ContentProvider { */ public void createEmptyDB(SQLiteDatabase db) { try (SQLiteTransaction t = new SQLiteTransaction(db)) { - db.execSQL("DROP TABLE IF EXISTS " + Favorites.TABLE_NAME); - db.execSQL("DROP TABLE IF EXISTS workspaceScreens"); + dropTable(db, Favorites.TABLE_NAME); + dropTable(db, "workspaceScreens"); onCreate(db); t.commit(); } diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index 79c820873..e248ba016 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -89,6 +89,11 @@ public class LauncherSettings { public static final String TABLE_NAME = "favorites"; /** + * Backup table created when when the favorites table is modified during grid migration + */ + public static final String BACKUP_TABLE_NAME = "favorites_bakup"; + + /** * The content:// style URL for this table */ public static final Uri CONTENT_URI = Uri.parse("content://" + @@ -231,8 +236,13 @@ public class LauncherSettings { public static final String OPTIONS = "options"; public static void addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional) { + addTableToDb(db, myProfileId, optional, TABLE_NAME); + } + + public static void addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional, + String tableName) { String ifNotExists = optional ? " IF NOT EXISTS " : ""; - db.execSQL("CREATE TABLE " + ifNotExists + TABLE_NAME + " (" + + db.execSQL("CREATE TABLE " + ifNotExists + tableName + " (" + "_id INTEGER PRIMARY KEY," + "title TEXT," + "intent TEXT," + @@ -279,6 +289,10 @@ public class LauncherSettings { public static final String METHOD_REMOVE_GHOST_WIDGETS = "remove_ghost_widgets"; + public static final String METHOD_NEW_TRANSACTION = "new_db_transaction"; + + public static final String METHOD_REFRESH_BACKUP_TABLE = "refresh_backup_table"; + public static final String EXTRA_VALUE = "value"; public static Bundle call(ContentResolver cr, String method) { diff --git a/src/com/android/launcher3/model/GridBackupTable.java b/src/com/android/launcher3/model/GridBackupTable.java new file mode 100644 index 000000000..804a04019 --- /dev/null +++ b/src/com/android/launcher3/model/GridBackupTable.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2018 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 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.graphics.Point; +import android.os.Process; +import android.util.Log; + +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; +import com.android.launcher3.compat.UserManagerCompat; + +/** + * Helper class to backup and restore Favorites table into a separate table + * 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; + + 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; + + public GridBackupTable(Context context, SQLiteDatabase db, + int hotseatSize, int gridX, int gridY) { + mContext = context; + mDb = db; + + mOldHotseatSize = hotseatSize; + mOldGridX = gridX; + mOldGridY = gridY; + } + + public boolean backupOrRestoreAsNeeded() { + // Check if backup table exists + if (!tableExists(mDb, BACKUP_TABLE_NAME)) { + if (Settings.call(mContext.getContentResolver(), Settings.METHOD_WAS_EMPTY_DB_CREATED) + .getBoolean(Settings.EXTRA_VALUE, false)) { + // No need to copy if empty DB was created. + return false; + } + + copyTable(Favorites.TABLE_NAME, BACKUP_TABLE_NAME); + encodeDBProperties(); + return false; + } + + if (!loadDbProperties()) { + return false; + } + copyTable(BACKUP_TABLE_NAME, Favorites.TABLE_NAME); + Log.d(TAG, "Backup table found"); + return true; + } + + public int getRestoreHotseatAndGridSize(Point outGridSize) { + outGridSize.set(mRestoredGridX, mRestoredGridY); + return mRestoredHotseatSize; + } + + private void copyTable(String from, String to) { + long userSerial = UserManagerCompat.getInstance(mContext).getSerialNumberForUser( + Process.myUserHandle()); + dropTable(mDb, to); + Favorites.addTableToDb(mDb, userSerial, false, to); + mDb.execSQL("INSERT INTO " + to + " SELECT * FROM " + from + " where _id > " + ID_PROPERTY); + } + + private void encodeDBProperties() { + 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); + mDb.insert(BACKUP_TABLE_NAME, null, values); + } + + private boolean 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 + "_id=" + ID_PROPERTY, null, null, null, null)) { + if (!c.moveToNext()) { + Log.e(TAG, "Meta data not found in backup table"); + return false; + } + if (mDb.getVersion() != c.getInt(0)) { + return false; + } + + mRestoredGridX = c.getInt(1); + mRestoredGridY = c.getInt(2); + mRestoredHotseatSize = c.getInt(3); + return true; + } + } +} diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index a9ddccb67..1c7bffac3 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -1,10 +1,10 @@ package com.android.launcher3.model; +import static com.android.launcher3.LauncherSettings.Settings.EXTRA_VALUE; import static com.android.launcher3.Utilities.getPointString; import static com.android.launcher3.Utilities.parsePoint; import android.content.ComponentName; -import android.content.ContentProviderOperation; import android.content.ContentValues; import android.content.Context; import android.content.Intent; @@ -12,24 +12,27 @@ import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.graphics.Point; import android.util.Log; +import android.util.SparseArray; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; -import com.android.launcher3.LauncherProvider; import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.provider.LauncherDbUtils; +import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; -import com.android.launcher3.util.IntSet; import com.android.launcher3.util.IntSparseArrayMap; import java.util.ArrayList; @@ -60,13 +63,13 @@ public class GridSizeMigrationTask { private static final float WT_WIDGET_FACTOR = 0.6f; private static final float WT_FOLDER_FACTOR = 0.5f; - private final Context mContext; - private final InvariantDeviceProfile mIdp; + protected final SQLiteDatabase mDb; + protected final Context mContext; - private final ContentValues mTempValues = new ContentValues(); protected final IntArray mEntryToRemove = new IntArray(); - private final ArrayList<ContentProviderOperation> mUpdateOperations = new ArrayList<>(); protected final ArrayList<DbEntry> mCarryOver = new ArrayList<>(); + + private final SparseArray<ContentValues> mUpdateOperations = new SparseArray<>(); private final HashSet<String> mValidPackages; private final int mSrcX, mSrcY; @@ -76,11 +79,11 @@ public class GridSizeMigrationTask { private final int mSrcHotseatSize; private final int mDestHotseatSize; - protected GridSizeMigrationTask(Context context, InvariantDeviceProfile idp, + protected GridSizeMigrationTask(Context context, SQLiteDatabase db, HashSet<String> validPackages, Point sourceSize, Point targetSize) { mContext = context; + mDb = db; mValidPackages = validPackages; - mIdp = idp; mSrcX = sourceSize.x; mSrcY = sourceSize.y; @@ -95,11 +98,10 @@ public class GridSizeMigrationTask { mSrcHotseatSize = mDestHotseatSize = -1; } - protected GridSizeMigrationTask(Context context, - InvariantDeviceProfile idp, HashSet<String> validPackages, - int srcHotseatSize, int destHotseatSize) { + protected GridSizeMigrationTask(Context context, SQLiteDatabase db, + HashSet<String> validPackages, int srcHotseatSize, int destHotseatSize) { mContext = context; - mIdp = idp; + mDb = db; mValidPackages = validPackages; mSrcHotseatSize = srcHotseatSize; @@ -118,20 +120,21 @@ public class GridSizeMigrationTask { */ private boolean applyOperations() throws Exception { // Update items - if (!mUpdateOperations.isEmpty()) { - mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, mUpdateOperations); + int updateCount = mUpdateOperations.size(); + for (int i = 0; i < updateCount; i++) { + mDb.update(Favorites.TABLE_NAME, mUpdateOperations.valueAt(i), + "_id=" + mUpdateOperations.keyAt(i), null); } if (!mEntryToRemove.isEmpty()) { if (DEBUG) { Log.d(TAG, "Removing items: " + mEntryToRemove.toConcatString()); } - mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI, - Utilities.createDbSelectionQuery( - LauncherSettings.Favorites._ID, mEntryToRemove), null); + mDb.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( + Favorites._ID, mEntryToRemove), null); } - return !mUpdateOperations.isEmpty() || !mEntryToRemove.isEmpty(); + return updateCount > 0 || !mEntryToRemove.isEmpty(); } /** @@ -181,24 +184,17 @@ public class GridSizeMigrationTask { } @VisibleForTesting - static IntArray getWorkspaceScreenIds(Context context) { - IntSet set = new IntSet(); - try (Cursor c = context.getContentResolver().query(Favorites.CONTENT_URI, - new String[] {Favorites.SCREEN}, + static IntArray getWorkspaceScreenIds(SQLiteDatabase db) { + return LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, - null, Favorites.SCREEN)) { - while (c.moveToNext()) { - set.add(c.getInt(0)); - } - } - return set.getArray(); + Favorites.SCREEN, Favorites.SCREEN); } /** * @return true if any DB change was made */ protected boolean migrateWorkspace() throws Exception { - IntArray allScreens = getWorkspaceScreenIds(mContext); + IntArray allScreens = getWorkspaceScreenIds(mDb); if (allScreens.isEmpty()) { throw new Exception("Unable to get workspace screens"); } @@ -230,8 +226,7 @@ public class GridSizeMigrationTask { int newScreenId = LauncherSettings.Settings.call( mContext.getContentResolver(), LauncherSettings.Settings.METHOD_NEW_SCREEN_ID) - .getInt(LauncherSettings.Settings.EXTRA_VALUE); - + .getInt(EXTRA_VALUE); for (DbEntry item : placement.finalPlacedItems) { if (!mCarryOver.remove(itemMap.get(item.id))) { throw new Exception("Unable to find matching items"); @@ -362,11 +357,9 @@ public class GridSizeMigrationTask { * Updates an item in the DB. */ protected void update(DbEntry item) { - mTempValues.clear(); - item.addToContentValues(mTempValues); - mUpdateOperations.add(ContentProviderOperation - .newUpdate(LauncherSettings.Favorites.getContentUri(item.id)) - .withValues(mTempValues).build()); + ContentValues values = new ContentValues(); + item.addToContentValues(values); + mUpdateOperations.put(item.id, values); } /** @@ -612,13 +605,13 @@ public class GridSizeMigrationTask { } private ArrayList<DbEntry> loadHotseatEntries() { - Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + Cursor c = queryWorkspace( new String[]{ Favorites._ID, // 0 Favorites.ITEM_TYPE, // 1 Favorites.INTENT, // 2 Favorites.SCREEN}, // 3 - Favorites.CONTAINER + " = " + Favorites.CONTAINER_HOTSEAT, null, null, null); + Favorites.CONTAINER + " = " + Favorites.CONTAINER_HOTSEAT); final int indexId = c.getColumnIndexOrThrow(Favorites._ID); final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE); @@ -796,8 +789,7 @@ public class GridSizeMigrationTask { } protected Cursor queryWorkspace(String[] columns, String where) { - return mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, - columns, where, null, null, null); + return mDb.query(Favorites.TABLE_NAME, columns, where, null, null, null, null); } /** @@ -864,11 +856,11 @@ public class GridSizeMigrationTask { } public void addToContentValues(ContentValues values) { - values.put(LauncherSettings.Favorites.SCREEN, screenId); - values.put(LauncherSettings.Favorites.CELLX, cellX); - values.put(LauncherSettings.Favorites.CELLY, cellY); - values.put(LauncherSettings.Favorites.SPANX, spanX); - values.put(LauncherSettings.Favorites.SPANY, spanY); + values.put(Favorites.SCREEN, screenId); + values.put(Favorites.CELLX, cellX); + values.put(Favorites.CELLY, cellY); + values.put(Favorites.SPANX, spanX); + values.put(Favorites.SPANY, spanY); } } @@ -907,34 +899,43 @@ public class GridSizeMigrationTask { } long migrationStartTime = System.currentTimeMillis(); - try { + try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call( + context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION) + .getBinder(Settings.EXTRA_VALUE)) { + + int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, + idp.numHotseatIcons); + Point sourceSize = parsePoint(prefs.getString( + KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)); + boolean dbChanged = false; + GridBackupTable backupTable = new GridBackupTable(context, transaction.getDb(), + srcHotseatCount, sourceSize.x, sourceSize.y); + if (backupTable.backupOrRestoreAsNeeded()) { + dbChanged = true; + srcHotseatCount = backupTable.getRestoreHotseatAndGridSize(sourceSize); + } + HashSet<String> validPackages = getValidPackages(context); // Hotseat - int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, - idp.numHotseatIcons); if (srcHotseatCount != idp.numHotseatIcons) { // Migrate hotseat. - - dbChanged = new GridSizeMigrationTask(context, LauncherAppState.getIDP(context), + dbChanged = new GridSizeMigrationTask(context, transaction.getDb(), validPackages, srcHotseatCount, idp.numHotseatIcons).migrateHotseat(); } // Grid size Point targetSize = new Point(idp.numColumns, idp.numRows); - Point sourceSize = parsePoint(prefs.getString( - KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString)); - - if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize, - targetSize)) { + if (new MultiStepMigrationTask(validPackages, context, transaction.getDb()) + .migrate(sourceSize, targetSize)) { dbChanged = true; } if (dbChanged) { // Make sure we haven't removed everything. final Cursor c = context.getContentResolver().query( - LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); + Favorites.CONTENT_URI, null, null, null, null); boolean hasData = c.moveToNext(); c.close(); if (!hasData) { @@ -942,6 +943,8 @@ public class GridSizeMigrationTask { } } + transaction.commit(); + Settings.call(context.getContentResolver(), Settings.METHOD_REFRESH_BACKUP_TABLE); return true; } catch (Exception e) { Log.e(TAG, "Error during grid migration", e); @@ -982,19 +985,24 @@ public class GridSizeMigrationTask { */ public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception { - GridSizeMigrationTask task = new GridSizeMigrationTask( - context, LauncherAppState.getIDP(context), getValidPackages(context), - Integer.MAX_VALUE, Integer.MAX_VALUE); - - // Load all the valid entries - ArrayList<DbEntry> items = task.loadHotseatEntries(); - // Delete any entry marked for deletion by above load. - task.applyOperations(); - IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>(); - for (DbEntry item : items) { - positions.put(item.screenId, item); + try (SQLiteTransaction transaction = (SQLiteTransaction) Settings.call( + context.getContentResolver(), Settings.METHOD_NEW_TRANSACTION) + .getBinder(Settings.EXTRA_VALUE)) { + GridSizeMigrationTask task = new GridSizeMigrationTask( + context, transaction.getDb(), getValidPackages(context), + Integer.MAX_VALUE, Integer.MAX_VALUE); + + // Load all the valid entries + ArrayList<DbEntry> items = task.loadHotseatEntries(); + // Delete any entry marked for deletion by above load. + task.applyOperations(); + IntSparseArrayMap<Object> positions = new IntSparseArrayMap<>(); + for (DbEntry item : items) { + positions.put(item.screenId, item); + } + transaction.commit(); + return positions; } - return positions; } /** @@ -1003,10 +1011,13 @@ public class GridSizeMigrationTask { protected static class MultiStepMigrationTask { private final HashSet<String> mValidPackages; private final Context mContext; + private final SQLiteDatabase mDb; - public MultiStepMigrationTask(HashSet<String> validPackages, Context context) { + public MultiStepMigrationTask(HashSet<String> validPackages, Context context, + SQLiteDatabase db) { mValidPackages = validPackages; mContext = context; + mDb = db; } public boolean migrate(Point sourceSize, Point targetSize) throws Exception { @@ -1042,7 +1053,7 @@ public class GridSizeMigrationTask { } protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception { - return new GridSizeMigrationTask(mContext, LauncherAppState.getIDP(mContext), + return new GridSizeMigrationTask(mContext, mDb, mValidPackages, sourceSize, nextSize).migrateWorkspace(); } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index b79478ac6..2c843f96c 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -21,6 +21,7 @@ import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; +import android.os.Binder; import android.util.Log; import com.android.launcher3.LauncherAppState; @@ -103,10 +104,22 @@ public class LauncherDbUtils { return out; } + public static boolean tableExists(SQLiteDatabase db, String tableName) { + try (Cursor c = db.query(true, "sqlite_master", new String[] {"tbl_name"}, + "tbl_name = ?", new String[] {tableName}, + null, null, null, null, null)) { + return c.getCount() > 0; + } + } + + public static void dropTable(SQLiteDatabase db, String tableName) { + db.execSQL("DROP TABLE IF EXISTS " + tableName); + } + /** * Utility class to simplify managing sqlite transactions */ - public static class SQLiteTransaction implements AutoCloseable { + public static class SQLiteTransaction extends Binder implements AutoCloseable { private final SQLiteDatabase mDb; public SQLiteTransaction(SQLiteDatabase db) { @@ -122,5 +135,9 @@ public class LauncherDbUtils { public void close() { mDb.endTransaction(); } + + public SQLiteDatabase getDb() { + return mDb; + } } } diff --git a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java index 9166b8358..6d839f352 100644 --- a/src/com/android/launcher3/provider/LossyScreenMigrationTask.java +++ b/src/com/android/launcher3/provider/LossyScreenMigrationTask.java @@ -37,29 +37,21 @@ import java.util.ArrayList; */ public class LossyScreenMigrationTask extends GridSizeMigrationTask { - private final SQLiteDatabase mDb; - private final IntSparseArrayMap<DbEntry> mOriginalItems; private final IntSparseArrayMap<DbEntry> mUpdates; protected LossyScreenMigrationTask( Context context, InvariantDeviceProfile idp, SQLiteDatabase db) { // Decrease the rows count by 1 - super(context, idp, getValidPackages(context), + super(context, db, getValidPackages(context), new Point(idp.numColumns, idp.numRows + 1), new Point(idp.numColumns, idp.numRows)); - mDb = db; mOriginalItems = new IntSparseArrayMap<>(); mUpdates = new IntSparseArrayMap<>(); } @Override - protected Cursor queryWorkspace(String[] columns, String where) { - return mDb.query(Favorites.TABLE_NAME, columns, where, null, null, null, null); - } - - @Override protected void update(DbEntry item) { mUpdates.put(item.id, item.copy()); } diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java index 17c66b4d9..bcca4d850 100644 --- a/src/com/android/launcher3/provider/RestoreDbTask.java +++ b/src/com/android/launcher3/provider/RestoreDbTask.java @@ -16,6 +16,8 @@ package com.android.launcher3.provider; +import static com.android.launcher3.provider.LauncherDbUtils.dropTable; + import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -111,7 +113,7 @@ public class RestoreDbTask { db.execSQL("ALTER TABLE favorites RENAME TO favorites_old;"); Favorites.addTableToDb(db, newProfileId, false); db.execSQL("INSERT INTO favorites SELECT * FROM favorites_old;"); - db.execSQL("DROP TABLE favorites_old;"); + dropTable(db, "favorites_old"); } /** |