summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher2/LauncherModel.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher2/LauncherModel.java')
-rw-r--r--src/com/android/launcher2/LauncherModel.java198
1 files changed, 138 insertions, 60 deletions
diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java
index 92be7e4df..792759399 100644
--- a/src/com/android/launcher2/LauncherModel.java
+++ b/src/com/android/launcher2/LauncherModel.java
@@ -103,7 +103,7 @@ public class LauncherModel extends BroadcastReceiver {
private WeakReference<Callbacks> mCallbacks;
// < only access in worker thread >
- private AllAppsList mAllAppsList;
+ private AllAppsList mBgAllAppsList;
// The lock that must be acquired before referencing any static bg data structures. Unlike
// other locks, this one can generally be held long-term because we never expect any of these
@@ -115,9 +115,9 @@ public class LauncherModel extends BroadcastReceiver {
// LauncherModel to their ids
static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
- // sBgItems is passed to bindItems, which expects a list of all folders and shortcuts created by
- // LauncherModel that are directly on the home screen (however, no widgets or shortcuts
- // within folders).
+ // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
+ // created by LauncherModel that are directly on the home screen (however, no widgets or
+ // shortcuts within folders).
static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();
// sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()
@@ -129,7 +129,6 @@ public class LauncherModel extends BroadcastReceiver {
// sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database
static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();
-
// </ only access in worker thread >
private IconCache mIconCache;
@@ -151,7 +150,7 @@ public class LauncherModel extends BroadcastReceiver {
public void bindAllApplications(ArrayList<ApplicationInfo> apps);
public void bindAppsAdded(ArrayList<ApplicationInfo> apps);
public void bindAppsUpdated(ArrayList<ApplicationInfo> apps);
- public void bindAppsRemoved(ArrayList<ApplicationInfo> apps, boolean permanent);
+ public void bindAppsRemoved(ArrayList<String> packageNames, boolean permanent);
public void bindPackagesUpdated();
public boolean isAllAppsVisible();
public boolean isAllAppsButtonRank(int rank);
@@ -162,7 +161,7 @@ public class LauncherModel extends BroadcastReceiver {
LauncherModel(LauncherApplication app, IconCache iconCache) {
mAppsCanBeOnExternalStorage = !Environment.isExternalStorageEmulated();
mApp = app;
- mAllAppsList = new AllAppsList(iconCache);
+ mBgAllAppsList = new AllAppsList(iconCache);
mIconCache = iconCache;
mDefaultIcon = Utilities.createIconBitmap(
@@ -249,12 +248,38 @@ public class LauncherModel extends BroadcastReceiver {
}
}
+ static void checkItemInfo(final ItemInfo item) {
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+ final long itemId = item.id;
+ Runnable r = new Runnable() {
+ public void run() {
+ synchronized (sBgLock) {
+ ItemInfo modelItem = sBgItemsIdMap.get(itemId);
+ if (modelItem != null && item != modelItem) {
+ // the modelItem needs to match up perfectly with item if our model is
+ // to be consistent with the database-- for now, just require
+ // modelItem == item
+ String msg = "item: " + ((item != null) ? item.toString() : "null") +
+ "modelItem: " +
+ ((modelItem != null) ? modelItem.toString() : "null") +
+ "Error: ItemInfo passed to checkItemInfo doesn't match original";
+ RuntimeException e = new RuntimeException(msg);
+ e.setStackTrace(stackTrace);
+ throw e;
+ }
+ }
+ }
+ };
+ runOnWorkerThread(r);
+ }
+
static void updateItemInDatabaseHelper(Context context, final ContentValues values,
final ItemInfo item, final String callingFunction) {
final long itemId = item.id;
final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);
final ContentResolver cr = context.getContentResolver();
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
Runnable r = new Runnable() {
public void run() {
cr.update(uri, values, null, null);
@@ -272,14 +297,36 @@ public class LauncherModel extends BroadcastReceiver {
throw new RuntimeException(msg);
}
+ if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ // Item is in a folder, make sure this folder exists
+ if (!sBgFolders.containsKey(item.container)) {
+ // An items container is being set to a that of an item which is not in
+ // the list of Folders.
+ String msg = "item: " + item + " container being set to: " +
+ item.container + ", not in the list of folders";
+ RuntimeException e = new RuntimeException(msg);
+ e.setStackTrace(stackTrace);
+ Launcher.dumpDebugLogsToConsole();
+ throw e;
+ }
+ }
+
// Items are added/removed from the corresponding FolderInfo elsewhere, such
// as in Workspace.onDrop. Here, we just add/remove them from the list of items
// that are on the desktop, as appropriate
if (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- if (!sBgWorkspaceItems.contains(modelItem)) {
- sBgWorkspaceItems.add(modelItem);
-
+ switch (modelItem.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ if (!sBgWorkspaceItems.contains(modelItem)) {
+ sBgWorkspaceItems.add(modelItem);
+ }
+ break;
+ default:
+ break;
}
} else {
sBgWorkspaceItems.remove(modelItem);
@@ -295,6 +342,11 @@ public class LauncherModel extends BroadcastReceiver {
*/
static void moveItemInDatabase(Context context, final ItemInfo item, final long container,
final int screen, final int cellX, final int cellY) {
+ String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id +
+ " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY +
+ ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")";
+ Launcher.sDumpLogs.add(transaction);
+ Log.d(TAG, transaction);
item.container = container;
item.cellX = cellX;
item.cellY = cellY;
@@ -322,7 +374,11 @@ public class LauncherModel extends BroadcastReceiver {
*/
static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,
final int screen, final int cellX, final int cellY, final int spanX, final int spanY) {
- item.container = container;
+ String transaction = "DbDebug Modify item (" + item.title + ") in db, id: " + item.id +
+ " (" + item.container + ", " + item.screen + ", " + item.cellX + ", " + item.cellY +
+ ") --> " + "(" + container + ", " + screen + ", " + cellX + ", " + cellY + ")";
+ Launcher.sDumpLogs.add(transaction);
+ Log.d(TAG, transaction);
item.cellX = cellX;
item.cellY = cellY;
item.spanX = spanX;
@@ -345,7 +401,7 @@ public class LauncherModel extends BroadcastReceiver {
values.put(LauncherSettings.Favorites.SPANY, item.spanY);
values.put(LauncherSettings.Favorites.SCREEN, item.screen);
- updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");
+ updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");
}
/**
@@ -487,10 +543,19 @@ public class LauncherModel extends BroadcastReceiver {
values.put(LauncherSettings.Favorites._ID, item.id);
item.updateValuesWithCoordinates(values, item.cellX, item.cellY);
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+
Runnable r = new Runnable() {
public void run() {
+ String transaction = "DbDebug Add item (" + item.title + ") to db, id: "
+ + item.id + " (" + container + ", " + screen + ", " + cellX + ", "
+ + cellY + ")";
+ Launcher.sDumpLogs.add(transaction);
+ Log.d(TAG, transaction);
+
cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :
LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);
+
// Lock on mBgLock *after* the db operation
synchronized (sBgLock) {
if (sBgItemsIdMap.containsKey(item.id)) {
@@ -508,6 +573,16 @@ public class LauncherModel extends BroadcastReceiver {
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
sBgWorkspaceItems.add(item);
+ } else {
+ if (!sBgFolders.containsKey(item.container)) {
+ // Adding an item to a folder that doesn't exist.
+ String msg = "adding item: " + item + " to a folder that " +
+ " doesn't exist";
+ RuntimeException e = new RuntimeException(msg);
+ e.setStackTrace(stackTrace);
+ Launcher.dumpDebugLogsToConsole();
+ throw e;
+ }
}
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -554,14 +629,35 @@ public class LauncherModel extends BroadcastReceiver {
static void deleteItemFromDatabase(Context context, final ItemInfo item) {
final ContentResolver cr = context.getContentResolver();
final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+
Runnable r = new Runnable() {
public void run() {
+ String transaction = "DbDebug Delete item (" + item.title + ") from db, id: "
+ + item.id + " (" + item.container + ", " + item.screen + ", " + item.cellX +
+ ", " + item.cellY + ")";
+ Launcher.sDumpLogs.add(transaction);
+ Log.d(TAG, transaction);
+
cr.delete(uriToDelete, null, null);
+
// Lock on mBgLock *after* the db operation
synchronized (sBgLock) {
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
sBgFolders.remove(item.id);
+ for (ItemInfo info: sBgItemsIdMap.values()) {
+ if (info.container == item.id) {
+ // We are deleting a folder which still contains items that
+ // think they are contained by that folder.
+ String msg = "deleting a folder (" + item + ") which still " +
+ "contains items (" + info + ")";
+ RuntimeException e = new RuntimeException(msg);
+ e.setStackTrace(stackTrace);
+ Launcher.dumpDebugLogsToConsole();
+ throw e;
+ }
+ }
sBgWorkspaceItems.remove(item);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
@@ -1685,7 +1781,7 @@ public class LauncherModel extends BroadcastReceiver {
// shallow copy
@SuppressWarnings("unchecked")
final ArrayList<ApplicationInfo> list
- = (ArrayList<ApplicationInfo>) mAllAppsList.data.clone();
+ = (ArrayList<ApplicationInfo>) mBgAllAppsList.data.clone();
Runnable r = new Runnable() {
public void run() {
final long t = SystemClock.uptimeMillis();
@@ -1732,7 +1828,7 @@ public class LauncherModel extends BroadcastReceiver {
int batchSize = -1;
while (i < N && !mStopped) {
if (i == 0) {
- mAllAppsList.clear();
+ mBgAllAppsList.clear();
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
apps = packageManager.queryIntentActivities(mainIntent, 0);
if (DEBUG_LOADERS) {
@@ -1770,15 +1866,15 @@ public class LauncherModel extends BroadcastReceiver {
startIndex = i;
for (int j=0; i<N && j<batchSize; j++) {
// This builds the icon bitmaps.
- mAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
+ mBgAllAppsList.add(new ApplicationInfo(packageManager, apps.get(i),
mIconCache, mLabelCache));
i++;
}
final boolean first = i <= batchSize;
final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
- final ArrayList<ApplicationInfo> added = mAllAppsList.added;
- mAllAppsList.added = new ArrayList<ApplicationInfo>();
+ final ArrayList<ApplicationInfo> added = mBgAllAppsList.added;
+ mBgAllAppsList.added = new ArrayList<ApplicationInfo>();
mHandler.post(new Runnable() {
public void run() {
@@ -1861,42 +1957,45 @@ public class LauncherModel extends BroadcastReceiver {
case OP_ADD:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
- mAllAppsList.addPackage(context, packages[i]);
+ mBgAllAppsList.addPackage(context, packages[i]);
}
break;
case OP_UPDATE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);
- mAllAppsList.updatePackage(context, packages[i]);
+ mBgAllAppsList.updatePackage(context, packages[i]);
}
break;
case OP_REMOVE:
case OP_UNAVAILABLE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
- mAllAppsList.removePackage(packages[i]);
+ mBgAllAppsList.removePackage(packages[i]);
}
break;
}
ArrayList<ApplicationInfo> added = null;
- ArrayList<ApplicationInfo> removed = null;
ArrayList<ApplicationInfo> modified = null;
- if (mAllAppsList.added.size() > 0) {
- added = mAllAppsList.added;
- mAllAppsList.added = new ArrayList<ApplicationInfo>();
+ if (mBgAllAppsList.added.size() > 0) {
+ added = new ArrayList<ApplicationInfo>(mBgAllAppsList.added);
+ mBgAllAppsList.added.clear();
}
- if (mAllAppsList.removed.size() > 0) {
- removed = mAllAppsList.removed;
- mAllAppsList.removed = new ArrayList<ApplicationInfo>();
- for (ApplicationInfo info: removed) {
- mIconCache.remove(info.intent.getComponent());
- }
+ if (mBgAllAppsList.modified.size() > 0) {
+ modified = new ArrayList<ApplicationInfo>(mBgAllAppsList.modified);
+ mBgAllAppsList.modified.clear();
}
- if (mAllAppsList.modified.size() > 0) {
- modified = mAllAppsList.modified;
- mAllAppsList.modified = new ArrayList<ApplicationInfo>();
+ // We may be removing packages that have no associated launcher application, so we
+ // pass through the removed package names directly.
+ // NOTE: We flush the icon cache aggressively in removePackage() above.
+ final ArrayList<String> removedPackageNames = new ArrayList<String>();
+ if (mBgAllAppsList.removed.size() > 0) {
+ mBgAllAppsList.removed.clear();
+
+ for (int i = 0; i < N; ++i) {
+ removedPackageNames.add(packages[i]);
+ }
}
final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;
@@ -1927,14 +2026,13 @@ public class LauncherModel extends BroadcastReceiver {
}
});
}
- if (removed != null) {
+ if (!removedPackageNames.isEmpty()) {
final boolean permanent = mOp != OP_UNAVAILABLE;
- final ArrayList<ApplicationInfo> removedFinal = removed;
mHandler.post(new Runnable() {
public void run() {
Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;
if (callbacks == cb && cb != null) {
- callbacks.bindAppsRemoved(removedFinal, permanent);
+ callbacks.bindAppsRemoved(removedPackageNames, permanent);
}
}
});
@@ -1953,26 +2051,6 @@ public class LauncherModel extends BroadcastReceiver {
}
/**
- * Returns all the Workspace ShortcutInfos associated with a particular package.
- * @param intent
- * @return
- */
- ArrayList<ShortcutInfo> getShortcutInfosForPackage(String packageName) {
- ArrayList<ShortcutInfo> infos = new ArrayList<ShortcutInfo>();
- synchronized (sBgLock) {
- for (ItemInfo i : sBgWorkspaceItems) {
- if (i instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) i;
- if (packageName.equals(info.getPackageName())) {
- infos.add(info);
- }
- }
- }
- }
- return infos;
- }
-
- /**
* This is called from the code that adds shortcuts from the intent receiver. This
* doesn't have a Cursor, but
*/
@@ -2422,10 +2500,10 @@ public class LauncherModel extends BroadcastReceiver {
public void dumpState() {
Log.d(TAG, "mCallbacks=" + mCallbacks);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mAllAppsList.data);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mAllAppsList.added);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mAllAppsList.removed);
- ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mAllAppsList.modified);
+ ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);
+ ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);
+ ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);
+ ApplicationInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);
if (mLoaderTask != null) {
mLoaderTask.dumpState();
} else {