Defend against overlapping items in the workspace.
Should the Launcher's database become corrupted by
mysterious forces (e.g.: third-party launchers; botched
upgrades; smoke monsters) in such a way as to cause two
items to share the same cell, we now ignore loading the
latter.
Prevents a runtime crash (http://b/2655516).
Bug: 2655516
Change-Id: Ia514746f04f0e51b2cd07e9290589a6eab75bdd2
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 6127649..26671ad 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -670,6 +670,28 @@
}
}
+ // check & update map of what's occupied; used to discard overlapping/invalid items
+ private boolean checkItemPlacement(ItemInfo occupied[][][], ItemInfo item) {
+ for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
+ for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
+ if (occupied[item.screen][x][y] != null) {
+ Log.e(TAG, "Error loading shortcut " + item
+ + " into cell (" + item.screen + ":"
+ + x + "," + y
+ + ") occupied by "
+ + occupied[item.screen][x][y]);
+ return false;
+ }
+ }
+ }
+ for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {
+ for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {
+ occupied[item.screen][x][y] = item;
+ }
+ }
+ return true;
+ }
+
private void loadWorkspace() {
long t = SystemClock.uptimeMillis();
@@ -688,6 +710,8 @@
final Cursor c = contentResolver.query(
LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
+ final ItemInfo occupied[][][] = new ItemInfo[Launcher.SCREEN_COUNT][Launcher.NUMBER_CELLS_X][Launcher.NUMBER_CELLS_Y];
+
try {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
final int intentIndex = c.getColumnIndexOrThrow
@@ -762,6 +786,11 @@
info.cellX = c.getInt(cellXIndex);
info.cellY = c.getInt(cellYIndex);
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, info)) {
+ break;
+ }
+
switch (container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
mItems.add(info);
@@ -798,6 +827,11 @@
folderInfo.cellX = c.getInt(cellXIndex);
folderInfo.cellY = c.getInt(cellYIndex);
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, folderInfo)) {
+ break;
+ }
+
switch (container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
mItems.add(folderInfo);
@@ -841,7 +875,12 @@
liveFolderInfo.cellY = c.getInt(cellYIndex);
liveFolderInfo.baseIntent = intent;
liveFolderInfo.displayMode = c.getInt(displayModeIndex);
-
+
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, liveFolderInfo)) {
+ break;
+ }
+
loadLiveFolderIcon(context, c, iconTypeIndex, iconPackageIndex,
iconResourceIndex, liveFolderInfo);
@@ -884,6 +923,11 @@
}
appWidgetInfo.container = c.getInt(containerIndex);
+ // check & update map of what's occupied
+ if (!checkItemPlacement(occupied, appWidgetInfo)) {
+ break;
+ }
+
mAppWidgets.add(appWidgetInfo);
}
break;
@@ -916,6 +960,19 @@
if (DEBUG_LOADERS) {
Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
+ Log.d(TAG, "workspace layout: ");
+ for (int y = 0; y < Launcher.NUMBER_CELLS_Y; y++) {
+ String line = "";
+ for (int s = 0; s < Launcher.SCREEN_COUNT; s++) {
+ if (s > 0) {
+ line += " | ";
+ }
+ for (int x = 0; x < Launcher.NUMBER_CELLS_X; x++) {
+ line += ((occupied[s][x][y] != null) ? "#" : ".");
+ }
+ }
+ Log.d(TAG, "[ " + line + " ]");
+ }
}
}