Loading src/com/android/launcher3/LauncherProvider.java +4 −4 Original line number Diff line number Diff line Loading @@ -483,7 +483,7 @@ public class LauncherProvider extends ContentProvider { LauncherSettings.Favorites.CONTAINER + " FROM " + Favorites.TABLE_NAME + ")"; IntArray folderIds = LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, IntArray folderIds = LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME, Favorites._ID, selection, null, null); if (!folderIds.isEmpty()) { db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( Loading Loading @@ -835,8 +835,8 @@ public class LauncherProvider extends ContentProvider { case 27: { // Update the favorites table so that the screen ids are ordered based on // workspace page rank. IntArray finalScreens = LauncherDbUtils.queryIntArray(db, "workspaceScreens", BaseColumns._ID, null, null, "screenRank"); IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db, "workspaceScreens", BaseColumns._ID, null, null, "screenRank"); int[] original = finalScreens.toArray(); Arrays.sort(original); String updatemap = ""; Loading Loading @@ -919,7 +919,7 @@ public class LauncherProvider extends ContentProvider { Log.e(TAG, "getAppWidgetIds not supported", e); return; } final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db, final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME, Favorites.APPWIDGET_ID, "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null)); for (int widgetId : allWidgets) { Loading src/com/android/launcher3/provider/LauncherDbUtils.java +4 −4 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ import com.android.launcher3.util.IntArray; */ public class LauncherDbUtils { public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName, String selection, String groupBy, String orderBy) { public static IntArray queryIntArray(boolean distinct, SQLiteDatabase db, String tableName, String columnName, String selection, String groupBy, String orderBy) { IntArray out = new IntArray(); try (Cursor c = db.query(tableName, new String[] { columnName }, selection, null, groupBy, null, orderBy)) { try (Cursor c = db.query(distinct, tableName, new String[] { columnName }, selection, null, groupBy, null, orderBy, null)) { while (c.moveToNext()) { out.add(c.getInt(0)); } Loading src/com/android/launcher3/provider/RestoreDbTask.java +39 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.launcher3.provider; import static com.android.launcher3.model.DeviceGridState.TYPE_MULTI_DISPLAY; import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; Loading Loading @@ -96,7 +97,7 @@ public class RestoreDbTask { try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); task.backupWorkspace(context, db); task.sanitizeDB(helper, db, new BackupManager(context)); task.sanitizeDB(context, helper, db, new BackupManager(context)); task.restoreAppWidgetIdsIfExists(context); t.commit(); return true; Loading Loading @@ -139,7 +140,7 @@ public class RestoreDbTask { GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows); if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) { int itemsDeleted = sanitizeDB(helper, db, backupManager); int itemsDeleted = sanitizeDB(context, helper, db, backupManager); LauncherAppState.getInstance(context).getModel().forceReload(); restoreAppWidgetIdsIfExists(context); if (itemsDeleted == 0) { Loading @@ -156,11 +157,12 @@ public class RestoreDbTask { * the restored apps get installed. * 3. If the user serial for any restored profile is different than that of the previous * device, update the entries to the new profile id. * 4. If restored from a single display backup, remove gaps between screenIds * * @return number of items deleted. */ private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { private int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids long myProfileId = helper.getDefaultUserSerial(); long oldProfileId = getDefaultProfileId(db); Loading Loading @@ -236,9 +238,42 @@ public class RestoreDbTask { if (myProfileId != oldProfileId) { changeDefaultColumn(db, myProfileId); } // If restored from a single display backup, remove gaps between screenIds if (Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE) != TYPE_MULTI_DISPLAY) { removeScreenIdGaps(db); } return itemsDeleted; } /** * Remove gaps between screenIds to make sure no empty pages are left in between. * * e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4] */ protected void removeScreenIdGaps(SQLiteDatabase db) { FileLog.d(TAG, "Removing gaps between screenIds"); IntArray distinctScreens = LauncherDbUtils.queryIntArray(true, db, Favorites.TABLE_NAME, Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, null, Favorites.SCREEN); if (distinctScreens.isEmpty()) { return; } StringBuilder sql = new StringBuilder("UPDATE ").append(Favorites.TABLE_NAME) .append(" SET ").append(Favorites.SCREEN).append(" =\nCASE\n"); int screenId = distinctScreens.contains(0) ? 0 : 1; for (int i = 0; i < distinctScreens.size(); i++) { sql.append("WHEN ").append(Favorites.SCREEN).append(" == ") .append(distinctScreens.get(i)).append(" THEN ").append(screenId++).append("\n"); } sql.append("ELSE screen\nEND WHERE ").append(Favorites.CONTAINER).append(" = ") .append(Favorites.CONTAINER_DESKTOP).append(";"); db.execSQL(sql.toString()); } /** * Updates profile id of all entries from {@param oldProfileId} to {@param newProfileId}. */ Loading tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.launcher3.provider; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.content.ContentValues; Loading Loading @@ -87,6 +88,56 @@ public class RestoreDbTaskTest { assertEquals(1, getCount(db, "select * from favorites where profileId = 33")); } @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( new int[]{1, 2, 5, 6, 6, 7, 9, 9}, new int[]{1, 2, 3, 4, 4, 5, 6, 6}); } @Test public void testRemoveScreenIdGaps_firstScreenOccupied() { runRemoveScreenIdGapsTest( new int[]{0, 2, 5, 6, 6, 7, 9, 9}, new int[]{0, 1, 2, 3, 3, 4, 5, 5}); } @Test public void testRemoveScreenIdGaps_noGap() { runRemoveScreenIdGapsTest( new int[]{0, 1, 1, 2, 3, 3, 4, 5}, new int[]{0, 1, 1, 2, 3, 3, 4, 5}); } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); values.put(Favorites._ID, i); values.put(Favorites.SCREEN, screenIds[i]); values.put(Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP); db.insert(Favorites.TABLE_NAME, null, values); } // Verify items are added assertEquals(screenIds.length, getCount(db, "select * from favorites where container = -100")); new RestoreDbTask().removeScreenIdGaps(db); // verify screenId gaps removed int[] resultScreenIds = new int[screenIds.length]; try (Cursor c = db.rawQuery( "select screen from favorites where container = -100 order by screen", null)) { int i = 0; while (c.moveToNext()) { resultScreenIds[i++] = c.getInt(0); } } assertArrayEquals(expectedScreenIds, resultScreenIds); } private int getCount(SQLiteDatabase db, String sql) { try (Cursor c = db.rawQuery(sql, null)) { return c.getCount(); Loading Loading
src/com/android/launcher3/LauncherProvider.java +4 −4 Original line number Diff line number Diff line Loading @@ -483,7 +483,7 @@ public class LauncherProvider extends ContentProvider { LauncherSettings.Favorites.CONTAINER + " FROM " + Favorites.TABLE_NAME + ")"; IntArray folderIds = LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME, IntArray folderIds = LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME, Favorites._ID, selection, null, null); if (!folderIds.isEmpty()) { db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery( Loading Loading @@ -835,8 +835,8 @@ public class LauncherProvider extends ContentProvider { case 27: { // Update the favorites table so that the screen ids are ordered based on // workspace page rank. IntArray finalScreens = LauncherDbUtils.queryIntArray(db, "workspaceScreens", BaseColumns._ID, null, null, "screenRank"); IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db, "workspaceScreens", BaseColumns._ID, null, null, "screenRank"); int[] original = finalScreens.toArray(); Arrays.sort(original); String updatemap = ""; Loading Loading @@ -919,7 +919,7 @@ public class LauncherProvider extends ContentProvider { Log.e(TAG, "getAppWidgetIds not supported", e); return; } final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db, final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME, Favorites.APPWIDGET_ID, "itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null)); for (int widgetId : allWidgets) { Loading
src/com/android/launcher3/provider/LauncherDbUtils.java +4 −4 Original line number Diff line number Diff line Loading @@ -31,11 +31,11 @@ import com.android.launcher3.util.IntArray; */ public class LauncherDbUtils { public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName, String selection, String groupBy, String orderBy) { public static IntArray queryIntArray(boolean distinct, SQLiteDatabase db, String tableName, String columnName, String selection, String groupBy, String orderBy) { IntArray out = new IntArray(); try (Cursor c = db.query(tableName, new String[] { columnName }, selection, null, groupBy, null, orderBy)) { try (Cursor c = db.query(distinct, tableName, new String[] { columnName }, selection, null, groupBy, null, orderBy, null)) { while (c.moveToNext()) { out.add(c.getInt(0)); } Loading
src/com/android/launcher3/provider/RestoreDbTask.java +39 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.launcher3.provider; import static com.android.launcher3.model.DeviceGridState.TYPE_MULTI_DISPLAY; import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; Loading Loading @@ -96,7 +97,7 @@ public class RestoreDbTask { try (SQLiteTransaction t = new SQLiteTransaction(db)) { RestoreDbTask task = new RestoreDbTask(); task.backupWorkspace(context, db); task.sanitizeDB(helper, db, new BackupManager(context)); task.sanitizeDB(context, helper, db, new BackupManager(context)); task.restoreAppWidgetIdsIfExists(context); t.commit(); return true; Loading Loading @@ -139,7 +140,7 @@ public class RestoreDbTask { GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons, idp.numColumns, idp.numRows); if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) { int itemsDeleted = sanitizeDB(helper, db, backupManager); int itemsDeleted = sanitizeDB(context, helper, db, backupManager); LauncherAppState.getInstance(context).getModel().forceReload(); restoreAppWidgetIdsIfExists(context); if (itemsDeleted == 0) { Loading @@ -156,11 +157,12 @@ public class RestoreDbTask { * the restored apps get installed. * 3. If the user serial for any restored profile is different than that of the previous * device, update the entries to the new profile id. * 4. If restored from a single display backup, remove gaps between screenIds * * @return number of items deleted. */ private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { private int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager) throws Exception { // Primary user ids long myProfileId = helper.getDefaultUserSerial(); long oldProfileId = getDefaultProfileId(db); Loading Loading @@ -236,9 +238,42 @@ public class RestoreDbTask { if (myProfileId != oldProfileId) { changeDefaultColumn(db, myProfileId); } // If restored from a single display backup, remove gaps between screenIds if (Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE) != TYPE_MULTI_DISPLAY) { removeScreenIdGaps(db); } return itemsDeleted; } /** * Remove gaps between screenIds to make sure no empty pages are left in between. * * e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4] */ protected void removeScreenIdGaps(SQLiteDatabase db) { FileLog.d(TAG, "Removing gaps between screenIds"); IntArray distinctScreens = LauncherDbUtils.queryIntArray(true, db, Favorites.TABLE_NAME, Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, null, Favorites.SCREEN); if (distinctScreens.isEmpty()) { return; } StringBuilder sql = new StringBuilder("UPDATE ").append(Favorites.TABLE_NAME) .append(" SET ").append(Favorites.SCREEN).append(" =\nCASE\n"); int screenId = distinctScreens.contains(0) ? 0 : 1; for (int i = 0; i < distinctScreens.size(); i++) { sql.append("WHEN ").append(Favorites.SCREEN).append(" == ") .append(distinctScreens.get(i)).append(" THEN ").append(screenId++).append("\n"); } sql.append("ELSE screen\nEND WHERE ").append(Favorites.CONTAINER).append(" = ") .append(Favorites.CONTAINER_DESKTOP).append(";"); db.execSQL(sql.toString()); } /** * Updates profile id of all entries from {@param oldProfileId} to {@param newProfileId}. */ Loading
tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.launcher3.provider; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import android.content.ContentValues; Loading Loading @@ -87,6 +88,56 @@ public class RestoreDbTaskTest { assertEquals(1, getCount(db, "select * from favorites where profileId = 33")); } @Test public void testRemoveScreenIdGaps_firstScreenEmpty() { runRemoveScreenIdGapsTest( new int[]{1, 2, 5, 6, 6, 7, 9, 9}, new int[]{1, 2, 3, 4, 4, 5, 6, 6}); } @Test public void testRemoveScreenIdGaps_firstScreenOccupied() { runRemoveScreenIdGapsTest( new int[]{0, 2, 5, 6, 6, 7, 9, 9}, new int[]{0, 1, 2, 3, 3, 4, 5, 5}); } @Test public void testRemoveScreenIdGaps_noGap() { runRemoveScreenIdGapsTest( new int[]{0, 1, 1, 2, 3, 3, 4, 5}, new int[]{0, 1, 1, 2, 3, 3, 4, 5}); } private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) { SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase(); // Add some mock data for (int i = 0; i < screenIds.length; i++) { ContentValues values = new ContentValues(); values.put(Favorites._ID, i); values.put(Favorites.SCREEN, screenIds[i]); values.put(Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP); db.insert(Favorites.TABLE_NAME, null, values); } // Verify items are added assertEquals(screenIds.length, getCount(db, "select * from favorites where container = -100")); new RestoreDbTask().removeScreenIdGaps(db); // verify screenId gaps removed int[] resultScreenIds = new int[screenIds.length]; try (Cursor c = db.rawQuery( "select screen from favorites where container = -100 order by screen", null)) { int i = 0; while (c.moveToNext()) { resultScreenIds[i++] = c.getInt(0); } } assertArrayEquals(expectedScreenIds, resultScreenIds); } private int getCount(SQLiteDatabase db, String sql) { try (Cursor c = db.rawQuery(sql, null)) { return c.getCount(); Loading