diff options
Diffstat (limited to 'src/com/android/launcher3/LauncherModel.java')
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 223 |
1 files changed, 149 insertions, 74 deletions
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index b60477fa0..b5922c6a3 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -17,6 +17,7 @@ package com.android.launcher3; import android.app.SearchManager; +import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -33,7 +34,6 @@ import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -55,6 +55,7 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.model.MigrateFromRestoreTask; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.CursorIconInfo; @@ -203,7 +204,7 @@ public class LauncherModel extends BroadcastReceiver public void bindComponentsRemoved(ArrayList<String> packageNames, ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason); public void bindAllPackages(WidgetsModel model); - public void bindSearchablesChanged(); + public void bindSearchProviderChanged(); public boolean isAllAppsButtonRank(int rank); public void onPageBoundSynchronously(int page); public void dumpLogsToLocalData(); @@ -257,7 +258,7 @@ public class LauncherModel extends BroadcastReceiver /** Runs the specified runnable immediately if called from the worker thread, otherwise it is * posted on the worker thread handler. */ - private static void runOnWorkerThread(Runnable r) { + @Thunk static void runOnWorkerThread(Runnable r) { if (sWorkerThread.getThreadId() == Process.myTid()) { r.run(); } else { @@ -266,19 +267,6 @@ public class LauncherModel extends BroadcastReceiver } } - /** - * Runs the specified runnable after the loader is complete - */ - @Thunk void runAfterBindCompletes(Runnable r) { - if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) { - synchronized (mBindCompleteRunnables) { - mBindCompleteRunnables.add(r); - } - } else { - runOnWorkerThread(r); - } - } - boolean canMigrateFromOldLauncherDb(Launcher launcher) { return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ; } @@ -892,8 +880,13 @@ public class LauncherModel extends BroadcastReceiver } private void assertWorkspaceLoaded() { - if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) { - throw new RuntimeException("Trying to add shortcut while loader is running"); + if (LauncherAppState.isDogfoodBuild()) { + synchronized (mLock) { + if (!mHasLoaderCompletedOnce || + (mLoaderTask != null && mLoaderTask.mIsLoadingAndBindingWorkspace)) { + throw new RuntimeException("Trying to add shortcut while loader is running"); + } + } } } @@ -1133,7 +1126,7 @@ public class LauncherModel extends BroadcastReceiver * Update the order of the workspace screens in the database. The array list contains * a list of screen ids in the order that they should appear. */ - void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) { + public void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) { final ArrayList<Long> screensCopy = new ArrayList<Long>(screens); final ContentResolver cr = context.getContentResolver(); final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; @@ -1280,14 +1273,14 @@ public class LauncherModel extends BroadcastReceiver if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { // If we have changed locale we need to clear out the labels in all apps/workspace. forceReload(); - } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) || - SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) { + } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action)) { Callbacks callbacks = getCallback(); if (callbacks != null) { - callbacks.bindSearchablesChanged(); + callbacks.bindSearchProviderChanged(); } } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action) || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { + UserManagerCompat.getInstance(context).enableAndResetCache(); forceReload(); } } @@ -1388,16 +1381,6 @@ public class LauncherModel extends BroadcastReceiver mHandler.post(r); } } - - // Run all the bind complete runnables after workspace is bound. - if (!mBindCompleteRunnables.isEmpty()) { - synchronized (mBindCompleteRunnables) { - for (final Runnable r : mBindCompleteRunnables) { - runOnWorkerThread(r); - } - mBindCompleteRunnables.clear(); - } - } } public void stopLoader() { @@ -1411,7 +1394,7 @@ public class LauncherModel extends BroadcastReceiver /** * Loads the workspace screen ids in an ordered list. */ - @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) { + public static ArrayList<Long> loadWorkspaceScreensDb(Context context) { final ContentResolver contentResolver = context.getContentResolver(); final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI; @@ -1439,15 +1422,6 @@ public class LauncherModel extends BroadcastReceiver return mAllAppsLoaded; } - boolean isLoadingWorkspace() { - synchronized (mLock) { - if (mLoaderTask != null) { - return mLoaderTask.isLoadingWorkspace(); - } - } - return false; - } - /** * Runnable for the thread that loads the contents of the launcher: * - workspace icons @@ -1466,10 +1440,6 @@ public class LauncherModel extends BroadcastReceiver mFlags = flags; } - boolean isLoadingWorkspace() { - return mIsLoadingAndBindingWorkspace; - } - private void loadAndBindWorkspace() { mIsLoadingAndBindingWorkspace = true; @@ -1641,11 +1611,12 @@ public class LauncherModel extends BroadcastReceiver } // check & update map of what's occupied; used to discard overlapping/invalid items - private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) { + private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item, + ArrayList<Long> workspaceScreens) { LauncherAppState app = LauncherAppState.getInstance(); InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); - final int countX = (int) profile.numColumns; - final int countY = (int) profile.numRows; + final int countX = profile.numColumns; + final int countY = profile.numRows; long containerIndex = item.screenId; if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { @@ -1687,7 +1658,12 @@ public class LauncherModel extends BroadcastReceiver occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items); return true; } - } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { + } else if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { + if (!workspaceScreens.contains((Long) item.screenId)) { + // The item has an invalid screen id. + return false; + } + } else { // Skip further checking if it is not the hotseat or workspace container return true; } @@ -1754,8 +1730,27 @@ public class LauncherModel extends BroadcastReceiver LauncherAppState app = LauncherAppState.getInstance(); InvariantDeviceProfile profile = app.getInvariantDeviceProfile(); - int countX = (int) profile.numColumns; - int countY = (int) profile.numRows; + int countX = profile.numColumns; + int countY = profile.numRows; + + if (MigrateFromRestoreTask.ENABLED && MigrateFromRestoreTask.shouldRunTask(mContext)) { + long migrationStartTime = System.currentTimeMillis(); + Log.v(TAG, "Starting workspace migration after restore"); + try { + MigrateFromRestoreTask task = new MigrateFromRestoreTask(mContext); + // Clear the flags before starting the task, so that we do not run the task + // again, in case there was an uncaught error. + MigrateFromRestoreTask.clearFlags(mContext); + task.execute(); + } catch (Exception e) { + Log.e(TAG, "Error during grid migration", e); + + // Clear workspace. + mFlags = mFlags | LOADER_FLAG_CLEAR_WORKSPACE; + } + Log.v(TAG, "Workspace migration completed in " + + (System.currentTimeMillis() - migrationStartTime)); + } if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) { Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true); @@ -1776,6 +1771,7 @@ public class LauncherModel extends BroadcastReceiver clearSBgDataStructures(); final HashMap<String, Integer> installingPkgs = PackageInstallerCompat .getInstance(mContext).updateAndGetActiveSessionCache(); + sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext)); final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); final ArrayList<Long> restoredRows = new ArrayList<Long>(); @@ -1977,6 +1973,7 @@ public class LauncherModel extends BroadcastReceiver } catch (URISyntaxException e) { Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, true); + itemsToRemove.add(id); continue; } @@ -2047,7 +2044,7 @@ public class LauncherModel extends BroadcastReceiver } // check & update map of what's occupied - if (!checkItemPlacement(occupied, info)) { + if (!checkItemPlacement(occupied, info, sBgWorkspaceScreens)) { itemsToRemove.add(id); break; } @@ -2098,7 +2095,7 @@ public class LauncherModel extends BroadcastReceiver folderInfo.options = c.getInt(optionsIndex); // check & update map of what's occupied - if (!checkItemPlacement(occupied, folderInfo)) { + if (!checkItemPlacement(occupied, folderInfo, sBgWorkspaceScreens)) { itemsToRemove.add(id); break; } @@ -2163,14 +2160,18 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provider.provider); - int status = restoreStatus; + // The provider is available. So the widget is either + // available or not available. We do not need to track + // any future restore updates. + int status = restoreStatus & + ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; if (!wasProviderReady) { // If provider was not previously ready, update the // status and UI flag. // Id would be valid only if the widget restore broadcast was received. if (isIdValid) { - status = LauncherAppWidgetInfo.RESTORE_COMPLETED; + status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } else { status &= ~LauncherAppWidgetInfo .FLAG_PROVIDER_NOT_READY; @@ -2214,13 +2215,14 @@ public class LauncherModel extends BroadcastReceiver if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP && container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) { Log.e(TAG, "Widget found where container != " + - "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!"); + "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!"); + itemsToRemove.add(id); continue; } appWidgetInfo.container = container; // check & update map of what's occupied - if (!checkItemPlacement(occupied, appWidgetInfo)) { + if (!checkItemPlacement(occupied, appWidgetInfo, sBgWorkspaceScreens)) { itemsToRemove.add(id); break; } @@ -2279,6 +2281,21 @@ public class LauncherModel extends BroadcastReceiver } } + // Sort all the folder items and make sure the first 3 items are high resolution. + for (FolderInfo folder : sBgFolders) { + Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR); + int pos = 0; + for (ShortcutInfo info : folder.contents) { + if (info.usingLowResIcon) { + info.updateIcon(mIconCache, false); + } + pos ++; + if (pos >= FolderIcon.NUM_ITEMS_IN_PREVIEW) { + break; + } + } + } + if (restoredRows.size() > 0) { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); @@ -2294,8 +2311,6 @@ public class LauncherModel extends BroadcastReceiver null, sWorker); } - sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext)); - // Remove any empty screens ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens); for (ItemInfo item: sBgItemsIdMap) { @@ -2657,13 +2672,24 @@ public class LauncherModel extends BroadcastReceiver callbacks.finishBindingItems(); } + mIsLoadingAndBindingWorkspace = false; + + // Run all the bind complete runnables after workspace is bound. + if (!mBindCompleteRunnables.isEmpty()) { + synchronized (mBindCompleteRunnables) { + for (final Runnable r : mBindCompleteRunnables) { + runOnWorkerThread(r); + } + mBindCompleteRunnables.clear(); + } + } + // If we're profiling, ensure this is the last thing in the queue. if (DEBUG_LOADERS) { Log.d(TAG, "bound workspace in " + (SystemClock.uptimeMillis()-t) + "ms"); } - mIsLoadingAndBindingWorkspace = false; } }; if (isLoadingSynchronously) { @@ -2792,12 +2818,27 @@ public class LauncherModel extends BroadcastReceiver final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user); if (heuristic != null) { - runAfterBindCompletes(new Runnable() { + final Runnable r = new Runnable() { @Override public void run() { heuristic.processUserApps(apps); } + }; + runOnMainThread(new Runnable() { + + @Override + public void run() { + // Check isLoadingWorkspace on the UI thread, as it is updated on + // the UI thread. + if (mIsLoadingAndBindingWorkspace) { + synchronized (mBindCompleteRunnables) { + mBindCompleteRunnables.add(r); + } + } else { + runOnWorkerThread(r); + } + } }); } } @@ -2825,8 +2866,7 @@ public class LauncherModel extends BroadcastReceiver // Cleanup any data stored for a deleted user. ManagedProfileHeuristic.processAllUsers(profiles, mContext); - loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks), - true /* refresh */); + loadAndBindWidgetsAndShortcuts(tryGetCallbacks(oldCallbacks), true /* refresh */); if (DEBUG_LOADERS) { Log.d(TAG, "Icons processed in " + (SystemClock.uptimeMillis() - loadTime) + "ms"); @@ -2895,7 +2935,7 @@ public class LauncherModel extends BroadcastReceiver } // Reload widget list. No need to refresh, as we only want to update the icons and labels. - loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false); + loadAndBindWidgetsAndShortcuts(callbacks, false); } void enqueuePackageUpdated(PackageUpdatedTask task) { @@ -3155,7 +3195,15 @@ public class LauncherModel extends BroadcastReceiver if (mUser.equals(widgetInfo.user) && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && packageSet.contains(widgetInfo.providerName.getPackageName())) { - widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; + widgetInfo.restoreStatus &= + ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY & + ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; + + // adding this flag ensures that launcher shows 'click to setup' + // if the widget has a config activity. In case there is no config + // activity, it will be marked as 'restored' during bind. + widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + widgets.add(widgetInfo); updateItemInDatabase(context, widgetInfo); } @@ -3235,8 +3283,36 @@ public class LauncherModel extends BroadcastReceiver }); } - // onProvidersChanged method (API >= 17) already refreshed the widget list - loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17); + // Update widgets + if (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE) { + // Always refresh for a package event on secondary user + boolean needToRefresh = !mUser.equals(UserHandleCompat.myUserHandle()); + + // Refresh widget list, if the package already had a widget. + synchronized (sBgLock) { + if (sBgWidgetProviders != null) { + HashSet<String> pkgSet = new HashSet<>(); + Collections.addAll(pkgSet, mPackages); + + for (ComponentKey key : sBgWidgetProviders.keySet()) { + needToRefresh |= key.user.equals(mUser) && + pkgSet.contains(key.componentName.getPackageName()); + } + } + } + + if (!needToRefresh && mOp != OP_REMOVE) { + // Refresh widget list, if there is any newly added widget + PackageManager pm = context.getPackageManager(); + for (String pkg : mPackages) { + needToRefresh |= !pm.queryBroadcastReceivers( + new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE) + .setPackage(pkg), 0).isEmpty(); + } + } + + loadAndBindWidgetsAndShortcuts(callbacks, needToRefresh); + } // Write all the logs to disk mHandler.post(new Runnable() { @@ -3310,13 +3386,12 @@ public class LauncherModel extends BroadcastReceiver } } - public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks, - final boolean refresh) { + public void loadAndBindWidgetsAndShortcuts(final Callbacks callbacks, final boolean refresh) { runOnWorkerThread(new Runnable() { @Override public void run() { - updateWidgetsModel(context, refresh); + updateWidgetsModel(refresh); final WidgetsModel model = mBgWidgetsModel.clone(); mHandler.post(new Runnable() { @@ -3340,10 +3415,10 @@ public class LauncherModel extends BroadcastReceiver * * @see #loadAndBindWidgetsAndShortcuts */ - @Thunk void updateWidgetsModel(Context context, boolean refresh) { - PackageManager packageManager = context.getPackageManager(); + @Thunk void updateWidgetsModel(boolean refresh) { + PackageManager packageManager = mApp.getContext().getPackageManager(); final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>(); - widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh)); + widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh)); Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0)); mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts); |