diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2016-03-03 16:58:55 -0800 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2016-03-09 20:21:22 -0800 |
commit | 2e1efb480a9b77a97cb623d4f5faf6802a417422 (patch) | |
tree | 8c6c0f0f7d91c7fc7d4d8ca23092f5fa4be720c9 /src/com/android/launcher3/LauncherModel.java | |
parent | 726eb822d38ad422f37b74c4b0fc504a423ab926 (diff) | |
download | android_packages_apps_Trebuchet-2e1efb480a9b77a97cb623d4f5faf6802a417422.tar.gz android_packages_apps_Trebuchet-2e1efb480a9b77a97cb623d4f5faf6802a417422.tar.bz2 android_packages_apps_Trebuchet-2e1efb480a9b77a97cb623d4f5faf6802a417422.zip |
Changing the widget loading strategy
Widget is loaded only when the user enters the overview mode and we keep
the list updated as long as the user is in the overview mode. Once the user
leaves the overview mode, we stop responding to widget updates
Bug: 26077457
Change-Id: I9e4904b8f1300bfe0d77e2bc5f59aa6963fad8d1
Diffstat (limited to 'src/com/android/launcher3/LauncherModel.java')
-rw-r--r-- | src/com/android/launcher3/LauncherModel.java | 213 |
1 files changed, 41 insertions, 172 deletions
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f707ec501..3877b9496 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -17,7 +17,6 @@ package com.android.launcher3; import android.app.SearchManager; -import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -34,7 +33,6 @@ import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; -import android.os.DeadObjectException; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -42,7 +40,6 @@ import android.os.Looper; import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; -import android.os.TransactionTooLargeException; import android.provider.BaseColumns; import android.text.TextUtils; import android.util.Log; @@ -73,7 +70,6 @@ import java.net.URISyntaxException; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -137,11 +133,9 @@ public class LauncherModel extends BroadcastReceiver @Thunk WeakReference<Callbacks> mCallbacks; // < only access in worker thread > - AllAppsList mBgAllAppsList; + private final AllAppsList mBgAllAppsList; // Entire list of widgets. - WidgetsModel mBgWidgetsModel; - // Keep a clone of widgets that can be accessed from non-worker thread. - WidgetsModel mFgWidgetsModel; + private final WidgetsModel mBgWidgetsModel; // 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 @@ -168,12 +162,6 @@ public class LauncherModel extends BroadcastReceiver // sBgWorkspaceScreens is the ordered set of workspace screens. static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>(); - // sBgWidgetProviders is the set of widget providers including custom internal widgets - public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders; - - // sBgShortcutProviders is the set of custom shortcut providers - public static List<ResolveInfo> sBgShortcutProviders; - // sPendingPackages is a set of packages which could be on sdcard and are not available yet static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages = new HashMap<UserHandleCompat, HashSet<String>>(); @@ -209,7 +197,8 @@ public class LauncherModel extends BroadcastReceiver public void bindRestoreItemsChange(HashSet<ItemInfo> updates); public void bindComponentsRemoved(ArrayList<String> packageNames, ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason); - public void bindAllPackages(WidgetsModel model); + public void notifyWidgetProvidersChanged(); + public void bindWidgetsModel(WidgetsModel model); public void bindSearchProviderChanged(); public boolean isAllAppsButtonRank(int rank); public void onPageBoundSynchronously(int page); @@ -245,7 +234,6 @@ public class LauncherModel extends BroadcastReceiver mApp = app; mBgAllAppsList = new AllAppsList(iconCache, appFilter); mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter); - mFgWidgetsModel = mBgWidgetsModel.clone(); mIconCache = iconCache; mLauncherApps = LauncherAppsCompat.getInstance(context); @@ -1701,8 +1689,8 @@ public class LauncherModel extends BroadcastReceiver .getInstance(mContext).updateAndGetActiveSessionCache(); sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext)); - final ArrayList<Long> itemsToRemove = new ArrayList<Long>(); - final ArrayList<Long> restoredRows = new ArrayList<Long>(); + final ArrayList<Long> itemsToRemove = new ArrayList<>(); + final ArrayList<Long> restoredRows = new ArrayList<>(); final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI; if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri); final Cursor c = contentResolver.query(contentUri, null, null, null, null); @@ -1711,6 +1699,7 @@ public class LauncherModel extends BroadcastReceiver // Load workspace in reverse order to ensure that latest items are loaded first (and // before any earlier duplicates) final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>(); + HashMap<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null; try { final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); @@ -2070,10 +2059,14 @@ public class LauncherModel extends BroadcastReceiver final boolean wasProviderReady = (restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0; - final LauncherAppWidgetProviderInfo provider = - LauncherModel.getProviderInfo(context, + if (widgetProvidersMap == null) { + widgetProvidersMap = AppWidgetManagerCompat + .getInstance(mContext).getAllProvidersMap(); + } + final AppWidgetProviderInfo provider = widgetProvidersMap.get( + new ComponentKey( ComponentName.unflattenFromString(savedProvider), - user); + user)); final boolean isProviderReady = isValidProvider(provider); if (!isSafeMode && !customWidget && @@ -2695,7 +2688,6 @@ public class LauncherModel extends BroadcastReceiver final Callbacks callbacks = tryGetCallbacks(oldCallbacks); if (callbacks != null) { callbacks.bindAllApplications(list); - callbacks.bindAllPackages(mFgWidgetsModel); } if (DEBUG_LOADERS) { Log.d(TAG, "bound all " + list.size() + " apps from cache in " @@ -2787,7 +2779,7 @@ public class LauncherModel extends BroadcastReceiver callbacks.bindAllApplications(added); if (DEBUG_LOADERS) { Log.d(TAG, "bound " + added.size() + " apps in " - + (SystemClock.uptimeMillis() - bindTime) + "ms"); + + (SystemClock.uptimeMillis() - bindTime) + "ms"); } } else { Log.i(TAG, "not binding apps: no Launcher activity"); @@ -2796,8 +2788,6 @@ public class LauncherModel extends BroadcastReceiver }); // Cleanup any data stored for a deleted user. ManagedProfileHeuristic.processAllUsers(profiles, mContext); - - loadAndBindWidgetsAndShortcuts(tryGetCallbacks(oldCallbacks), true /* refresh */); if (DEBUG_LOADERS) { Log.d(TAG, "Icons processed in " + (SystemClock.uptimeMillis() - loadTime) + "ms"); @@ -2864,9 +2854,6 @@ public class LauncherModel extends BroadcastReceiver } }); } - - // Reload widget list. No need to refresh, as we only want to update the icons and labels. - loadAndBindWidgetsAndShortcuts(callbacks, false); } void enqueuePackageUpdated(PackageUpdatedTask task) { @@ -3230,169 +3217,51 @@ public class LauncherModel extends BroadcastReceiver }); } - // 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) { - try { - List<ResolveInfo> widgets = pm.queryBroadcastReceivers( - new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE) - .setPackage(pkg), 0); - needToRefresh |= widgets != null && !widgets.isEmpty(); - } catch (RuntimeException e) { - if (ProviderConfig.IS_DOGFOOD_BUILD) { - throw e; - } - // Ignore the crash. We can live with a state widget list. - Log.e(TAG, "PM call failed for " + pkg, e); + // Notify launcher of widget update. From marshmallow onwards we use AppWidgetHost to + // get widget update signals. + if (!Utilities.ATLEAST_MARSHMALLOW && + (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE)) { + mHandler.post(new Runnable() { + public void run() { + Callbacks cb = getCallback(); + if (callbacks == cb && cb != null) { + callbacks.notifyWidgetProvidersChanged(); } } - } - - loadAndBindWidgetsAndShortcuts(callbacks, needToRefresh); + }); } } } - public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context, - boolean refresh) { - ArrayList<LauncherAppWidgetProviderInfo> results = - new ArrayList<LauncherAppWidgetProviderInfo>(); - try { - synchronized (sBgLock) { - if (sBgWidgetProviders == null || refresh) { - HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders - = new HashMap<>(); - AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context); - LauncherAppWidgetProviderInfo info; - - List<AppWidgetProviderInfo> widgets = wm.getAllProviders(); - for (AppWidgetProviderInfo pInfo : widgets) { - info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo); - UserHandleCompat user = wm.getUser(info); - tmpWidgetProviders.put(new ComponentKey(info.provider, user), info); - } - - Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values(); - for (CustomAppWidget widget : customWidgets) { - info = new LauncherAppWidgetProviderInfo(context, widget); - UserHandleCompat user = wm.getUser(info); - tmpWidgetProviders.put(new ComponentKey(info.provider, user), info); - } - // Replace the global list at the very end, so that if there is an exception, - // previously loaded provider list is used. - sBgWidgetProviders = tmpWidgetProviders; - } - results.addAll(sBgWidgetProviders.values()); - return results; - } - } catch (Exception e) { - if (!ProviderConfig.IS_DOGFOOD_BUILD && - (e.getCause() instanceof TransactionTooLargeException || - e.getCause() instanceof DeadObjectException)) { - // the returned value may be incomplete and will not be refreshed until the next - // time Launcher starts. - // TODO: after figuring out a repro step, introduce a dirty bit to check when - // onResume is called to refresh the widget provider list. - synchronized (sBgLock) { - if (sBgWidgetProviders != null) { - results.addAll(sBgWidgetProviders.values()); - } - return results; + private void bindWidgetsModel(final Callbacks callbacks, final WidgetsModel model) { + mHandler.post(new Runnable() { + @Override + public void run() { + Callbacks cb = getCallback(); + if (callbacks == cb && cb != null) { + callbacks.bindWidgetsModel(model); } - } else { - throw e; - } - } - } - - public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name, - UserHandleCompat user) { - synchronized (sBgLock) { - if (sBgWidgetProviders == null) { - getWidgetProviders(ctx, false /* refresh */); } - return sBgWidgetProviders.get(new ComponentKey(name, user)); - } + }); } - public void loadAndBindWidgetsAndShortcuts(final Callbacks callbacks, final boolean refresh) { - + public void refreshAndBindWidgetsAndShortcuts( + final Callbacks callbacks, final boolean bindFirst) { runOnWorkerThread(new Runnable() { @Override public void run() { - updateWidgetsModel(refresh); - mHandler.post(new Runnable() { - @Override - public void run() { - Callbacks cb = getCallback(); - if (callbacks == cb && cb != null) { - callbacks.bindAllPackages(mFgWidgetsModel); - } - } - }); + if (bindFirst && !mBgWidgetsModel.isEmpty()) { + bindWidgetsModel(callbacks, mBgWidgetsModel.clone()); + } + final WidgetsModel model = mBgWidgetsModel.updateAndClone(mApp.getContext()); + bindWidgetsModel(callbacks, model); // update the Widget entries inside DB on the worker thread. LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews( - mFgWidgetsModel.getRawList()); + model.getRawList()); } }); } - /** - * Returns a list of ResolveInfos/AppWidgetInfos. - * - * @see #loadAndBindWidgetsAndShortcuts - */ - @Thunk void updateWidgetsModel(boolean refresh) { - Utilities.assertWorkerThread(); - PackageManager packageManager = mApp.getContext().getPackageManager(); - final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>(); - widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh)); - - // Update shortcut providers - synchronized (sBgLock) { - try { - Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); - List<ResolveInfo> providers = packageManager.queryIntentActivities(shortcutsIntent, 0); - sBgShortcutProviders = providers; - } catch (RuntimeException e) { - if (!ProviderConfig.IS_DOGFOOD_BUILD && - (e.getCause() instanceof TransactionTooLargeException || - e.getCause() instanceof DeadObjectException)) { - /** - * Ignore exception and use the cached list if available. - * Refer to {@link #getWidgetProviders(Context, boolean}} for more info. - */ - } else { - throw e; - } - } - if (sBgShortcutProviders != null) { - widgetsAndShortcuts.addAll(sBgShortcutProviders); - } - } - mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts); - mFgWidgetsModel = mBgWidgetsModel.clone(); - } - @Thunk static boolean isPackageDisabled(Context context, String packageName, UserHandleCompat user) { final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context); |