diff options
Diffstat (limited to 'src/com/android/launcher2/LauncherModel.java')
-rw-r--r-- | src/com/android/launcher2/LauncherModel.java | 198 |
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 { |