Robustly fixed issue where migration from different versions of DB data
tables was causing crashes upon grid size switching.
Bug: 304687723
Test: Verified behavior through unit test. Also manually tested that
factory resetting device -> adding shortcuts to the workspace ->
changing the grid size didn't cause any issues and resulted in normal
behavior.
Change-Id: I1945004d2c9a2d6f2b74d9597b39763ed4962e7b
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 105d5f3..34ebaf2 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -19,8 +19,13 @@
import android.database.sqlite.SQLiteDatabase;
import android.provider.BaseColumns;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.model.data.ItemInfo;
+import java.util.LinkedHashMap;
+import java.util.stream.Collectors;
+
/**
* Settings related utilities.
*/
@@ -289,28 +294,51 @@
public static void addTableToDb(SQLiteDatabase db, long myProfileId, boolean optional,
String tableName) {
- String ifNotExists = optional ? " IF NOT EXISTS " : "";
- db.execSQL("CREATE TABLE " + ifNotExists + tableName + " (" +
- "_id INTEGER PRIMARY KEY," +
- "title TEXT," +
- "intent TEXT," +
- "container INTEGER," +
- "screen INTEGER," +
- "cellX INTEGER," +
- "cellY INTEGER," +
- "spanX INTEGER," +
- "spanY INTEGER," +
- "itemType INTEGER," +
- "appWidgetId INTEGER NOT NULL DEFAULT -1," +
- "icon BLOB," +
- "appWidgetProvider TEXT," +
- "modified INTEGER NOT NULL DEFAULT 0," +
- "restored INTEGER NOT NULL DEFAULT 0," +
- "profileId INTEGER DEFAULT " + myProfileId + "," +
- "rank INTEGER NOT NULL DEFAULT 0," +
- "options INTEGER NOT NULL DEFAULT 0," +
- APPWIDGET_SOURCE + " INTEGER NOT NULL DEFAULT " + CONTAINER_UNKNOWN +
- ");");
+ db.execSQL("CREATE TABLE " + (optional ? " IF NOT EXISTS " : "") + tableName + " ("
+ + getJoinedColumnsToTypes(myProfileId) + ");");
+ }
+
+ // LinkedHashMap maintains Order of Insertion
+ @NonNull
+ private static LinkedHashMap<String, String> getColumnsToTypes(long profileId) {
+ final LinkedHashMap<String, String> columnsToTypes = new LinkedHashMap<>();
+ columnsToTypes.put(_ID, "INTEGER PRIMARY KEY");
+ columnsToTypes.put(TITLE, "TEXT");
+ columnsToTypes.put(INTENT, "TEXT");
+ columnsToTypes.put(CONTAINER, "INTEGER");
+ columnsToTypes.put(SCREEN, "INTEGER");
+ columnsToTypes.put(CELLX, "INTEGER");
+ columnsToTypes.put(CELLY, "INTEGER");
+ columnsToTypes.put(SPANX, "INTEGER");
+ columnsToTypes.put(SPANY, "INTEGER");
+ columnsToTypes.put(ITEM_TYPE, "INTEGER");
+ columnsToTypes.put(APPWIDGET_ID, "INTEGER NOT NULL DEFAULT -1");
+ columnsToTypes.put(ICON, "BLOB");
+ columnsToTypes.put(APPWIDGET_PROVIDER, "TEXT");
+ columnsToTypes.put(MODIFIED, "INTEGER NOT NULL DEFAULT 0");
+ columnsToTypes.put(RESTORED, "INTEGER NOT NULL DEFAULT 0");
+ columnsToTypes.put(PROFILE_ID, "INTEGER DEFAULT " + profileId);
+ columnsToTypes.put(RANK, "INTEGER NOT NULL DEFAULT 0");
+ columnsToTypes.put(OPTIONS, "INTEGER NOT NULL DEFAULT 0");
+ columnsToTypes.put(APPWIDGET_SOURCE, "INTEGER NOT NULL DEFAULT -1");
+ return columnsToTypes;
+ }
+
+ private static String getJoinedColumnsToTypes(long profileId) {
+ return getColumnsToTypes(profileId)
+ .entrySet()
+ .stream()
+ .map(it -> it.getKey() + " " + it.getValue())
+ .collect(Collectors.joining(", "));
+ }
+
+ /**
+ * Returns an ordered list of columns in the Favorites table as one string, ready to use in
+ * an SQL statement.
+ */
+ @NonNull
+ public static String getColumns(long profileId) {
+ return String.join(", ", getColumnsToTypes(profileId).keySet());
}
}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 575551b..30958d9 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -16,6 +16,7 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.LauncherSettings.Favorites.getColumns;
import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
import android.content.ContentValues;
@@ -48,7 +49,6 @@
* A set of utility methods for Launcher DB used for DB updates and migration.
*/
public class LauncherDbUtils {
-
/**
* Returns a string which can be used as a where clause for DB query to match the given itemId
*/
@@ -90,10 +90,12 @@
if (fromDb != toDb) {
toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db");
toDb.execSQL(
- "INSERT INTO " + toTable + " SELECT * FROM from_db." + fromTable);
+ "INSERT INTO " + toTable + " SELECT " + getColumns(userSerial)
+ + " FROM from_db." + fromTable);
toDb.execSQL("DETACH DATABASE 'from_db'");
} else {
- toDb.execSQL("INSERT INTO " + toTable + " SELECT * FROM " + fromTable);
+ toDb.execSQL("INSERT INTO " + toTable + " SELECT " + getColumns(userSerial) + " FROM "
+ + fromTable);
}
}