diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2016-03-10 04:22:37 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-03-10 04:22:37 +0000 |
commit | d856074d90b31390f1a70d09fde374cae925bf20 (patch) | |
tree | ed43689a78906f7a658c406f5f32793c59349160 /src/com/android | |
parent | 8fd5e938d34ee84d076b5c5d2575cc6c46c254ce (diff) | |
parent | 2e1efb480a9b77a97cb623d4f5faf6802a417422 (diff) | |
download | android_packages_apps_Trebuchet-d856074d90b31390f1a70d09fde374cae925bf20.tar.gz android_packages_apps_Trebuchet-d856074d90b31390f1a70d09fde374cae925bf20.tar.bz2 android_packages_apps_Trebuchet-d856074d90b31390f1a70d09fde374cae925bf20.zip |
Merge "Changing the widget loading strategy" into ub-launcher3-calgary
Diffstat (limited to 'src/com/android')
13 files changed, 261 insertions, 243 deletions
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 752567b59..c8eb9cc56 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1560,8 +1560,7 @@ public class Launcher extends Activity ItemInfo info = mPendingAddInfo; if (appWidgetInfo == null) { - appWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(this, - mAppWidgetManager.getAppWidgetInfo(appWidgetId)); + appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId); } if (appWidgetInfo.isCustomWidget) { @@ -2558,10 +2557,10 @@ public class Launcher extends Activity final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag(); if (v.isReadyForClickSetup()) { int widgetId = info.appWidgetId; - AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(widgetId); + LauncherAppWidgetProviderInfo appWidgetInfo = + mAppWidgetManager.getLauncherAppWidgetInfo(widgetId); if (appWidgetInfo != null) { - mPendingAddWidgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo( - this, appWidgetInfo); + mPendingAddWidgetInfo = appWidgetInfo; mPendingAddInfo.copyFrom(info); mPendingAddWidgetId = widgetId; @@ -3538,10 +3537,6 @@ public class Launcher extends Activity // TODO } - protected void disableVoiceButtonProxy(boolean disable) { - // NO-OP - } - public boolean launcherCallbacksProvidesSearch() { return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch()); } @@ -3955,6 +3950,16 @@ public class Launcher extends Activity sFolders = folders.clone(); } + private void bindSafeModeWidget(LauncherAppWidgetInfo item) { + PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, true); + view.updateIcon(mIconCache); + item.hostView = view; + item.hostView.updateAppWidget(null); + item.hostView.setOnClickListener(this); + addAppWidgetToWorkspace(item, null, false); + mWorkspace.requestLayout(); + } + /** * Add the views for a widget to the workspace. * @@ -3970,19 +3975,31 @@ public class Launcher extends Activity return; } + if (mIsSafeModeEnabled) { + bindSafeModeWidget(item); + return; + } + final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0; if (DEBUG_WIDGETS) { Log.d(TAG, "bindAppWidget: " + item); } - final Workspace workspace = mWorkspace; - LauncherAppWidgetProviderInfo appWidgetInfo = - LauncherModel.getProviderInfo(this, item.providerName, item.user); + final LauncherAppWidgetProviderInfo appWidgetInfo; - if (!mIsSafeModeEnabled - && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0) - && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { + // If the provider is not ready, bind as a pending widget. + appWidgetInfo = null; + } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { + // The widget id is not valid. Try to find the widget based on the provider info. + appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user); + } else { + appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId); + } + // If the provider is ready, but the width is not yet restored, try to restore it. + if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && + (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { if (appWidgetInfo == null) { if (DEBUG_WIDGETS) { Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId @@ -3994,7 +4011,7 @@ public class Launcher extends Activity } // If we do not have a valid id, try to bind an id. - if ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0) { + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { // Note: This assumes that the id remap broadcast is received before this step. // If that is not the case, the id remap will be ignored and user may see the // click to setup view. @@ -4030,46 +4047,42 @@ public class Launcher extends Activity : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; LauncherModel.updateItemInDatabase(this, item); - } else if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0) + } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) && (appWidgetInfo.configure == null)) { - // If the ID is already valid, verify if we need to configure or not. + // The widget was marked as UI not ready, but there is no configure activity to + // update the UI. item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; LauncherModel.updateItemInDatabase(this, item); } } - if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { - final int appWidgetId = item.appWidgetId; + if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { if (DEBUG_WIDGETS) { Log.d(TAG, "bindAppWidget: id=" + item.appWidgetId + " belongs to component " + appWidgetInfo.provider); } // Verify that we own the widget - AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId); - if (info == null || appWidgetInfo == null || - !info.provider.equals(appWidgetInfo.provider)) { - Log.e(TAG, "Removing invalid widget: id=" + item.appWidgetId + " info=" + info - + " appWidgetInfo=" + appWidgetInfo); + if (appWidgetInfo == null) { + Log.e(TAG, "Removing invalid widget: id=" + item.appWidgetId); deleteWidgetInfo(item); return; } - item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + item.hostView = mAppWidgetHost.createView(this, item.appWidgetId, appWidgetInfo); item.minSpanX = appWidgetInfo.minSpanX; item.minSpanY = appWidgetInfo.minSpanY; + addAppWidgetToWorkspace(item, appWidgetInfo, false); } else { - appWidgetInfo = null; PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, mIsSafeModeEnabled); view.updateIcon(mIconCache); item.hostView = view; item.hostView.updateAppWidget(null); item.hostView.setOnClickListener(this); + addAppWidgetToWorkspace(item, null, false); } - - addAppWidgetToWorkspace(item, appWidgetInfo, false); - workspace.requestLayout(); + mWorkspace.requestLayout(); if (DEBUG_WIDGETS) { Log.d(TAG, "bound widget id="+item.appWidgetId+" in " @@ -4407,15 +4420,15 @@ public class Launcher extends Activity } } - private Runnable mBindPackagesUpdatedRunnable = new Runnable() { + private Runnable mBindWidgetModelRunnable = new Runnable() { public void run() { - bindAllPackages(mWidgetsModel); + bindWidgetsModel(mWidgetsModel); } }; @Override - public void bindAllPackages(final WidgetsModel model) { - if (waitUntilResume(mBindPackagesUpdatedRunnable, true)) { + public void bindWidgetsModel(WidgetsModel model) { + if (waitUntilResume(mBindWidgetModelRunnable, true)) { mWidgetsModel = model; return; } @@ -4426,6 +4439,13 @@ public class Launcher extends Activity } } + @Override + public void notifyWidgetProvidersChanged() { + if (mWorkspace.getState().shouldUpdateWidget) { + mModel.refreshAndBindWidgetsAndShortcuts(this, mWidgetsView.isEmpty()); + } + } + private int mapConfigurationOriActivityInfoOri(int configOri) { final Display d = getWindowManager().getDefaultDisplay(); int naturalOri = Configuration.ORIENTATION_LANDSCAPE; diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index b07ccc362..8c23ff30d 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -102,6 +102,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost { callback.run(); } } + + if (Utilities.ATLEAST_MARSHMALLOW) { + mLauncher.notifyWidgetProvidersChanged(); + } } public AppWidgetHostView createView(Context context, int appWidgetId, diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 05d729e78..cad0f2c25 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -50,6 +50,7 @@ import com.android.launcher3.backup.nano.BackupProtos.Key; import com.android.launcher3.backup.nano.BackupProtos.Resource; import com.android.launcher3.backup.nano.BackupProtos.Screen; import com.android.launcher3.backup.nano.BackupProtos.Widget; +import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.model.GridSizeMigrationTask; @@ -660,12 +661,14 @@ public class LauncherBackupHelper implements BackupHelper { + getUserSelectionArg(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, where, null, null); + AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(mContext); try { cursor.moveToPosition(-1); while(cursor.moveToNext()) { final long id = cursor.getLong(ID_INDEX); final String providerName = cursor.getString(APPWIDGET_PROVIDER_INDEX); final ComponentName provider = ComponentName.unflattenFromString(providerName); + Key key = null; String backupKey = null; if (provider != null) { @@ -684,11 +687,14 @@ public class LauncherBackupHelper implements BackupHelper { } else if (backupKey != null) { if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount); if (backupWidgetCount < MAX_WIDGETS_PER_PASS) { - if (DEBUG) Log.d(TAG, "saving widget " + backupKey); - UserHandleCompat user = UserHandleCompat.myUserHandle(); - writeRowToBackup(key, packWidget(dpi, provider, user), data); - mKeys.add(key); - backupWidgetCount ++; + LauncherAppWidgetProviderInfo widgetInfo = widgetManager + .getLauncherAppWidgetInfo(cursor.getInt(APPWIDGET_ID_INDEX)); + if (widgetInfo != null) { + if (DEBUG) Log.d(TAG, "saving widget " + backupKey); + writeRowToBackup(key, packWidget(dpi, widgetInfo), data); + mKeys.add(key); + backupWidgetCount ++; + } } else { if (VERBOSE) Log.v(TAG, "deferring widget backup " + backupKey); // too many widgets for this pass, request another. @@ -1004,16 +1010,14 @@ public class LauncherBackupHelper implements BackupHelper { } /** Serialize a widget for persistence, including a checksum wrapper. */ - private Widget packWidget(int dpi, ComponentName provider, UserHandleCompat user) { - final LauncherAppWidgetProviderInfo info = - LauncherModel.getProviderInfo(mContext, provider, user); + private Widget packWidget(int dpi, LauncherAppWidgetProviderInfo info) { Widget widget = new Widget(); - widget.provider = provider.flattenToShortString(); + widget.provider = info.provider.flattenToShortString(); widget.label = info.label; widget.configure = info.configure != null; if (info.icon != 0) { widget.icon = new Resource(); - Drawable fullResIcon = mIconCache.getFullResIcon(provider.getPackageName(), info.icon); + Drawable fullResIcon = mIconCache.getFullResIcon(info.provider.getPackageName(), info.icon); Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext); widget.icon.data = Utilities.flattenBitmap(icon); widget.icon.dpi = dpi; @@ -1022,7 +1026,6 @@ public class LauncherBackupHelper implements BackupHelper { Point spans = info.getMinSpans(mIdp, mContext); widget.minSpanX = spans.x; widget.minSpanY = spans.y; - return widget; } 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); diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index 303785de5..8855cf037 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -403,7 +403,7 @@ public class LauncherStateTransitionAnimation { // Animate the search bar final SearchDropTargetBar.State toSearchBarState = - toWorkspaceState.getSearchDropTargetBarState(); + toWorkspaceState.searchDropTargetBarState; mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, animated ? revealDuration : 0, animation); diff --git a/src/com/android/launcher3/Stats.java b/src/com/android/launcher3/Stats.java index fdb2ff442..10a26ad59 100644 --- a/src/com/android/launcher3/Stats.java +++ b/src/com/android/launcher3/Stats.java @@ -145,6 +145,8 @@ public class Stats { LaunchSourceUtils.populateSourceDataFromAncestorProvider(v, sourceExtras); broadcastIntent.putExtra(EXTRA_SOURCE, sourceExtras); mLauncher.sendBroadcast(broadcastIntent, mLaunchBroadcastPermission); - mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras); + if (intent.getComponent() != null) { + mLauncher.getLogger().logAppLaunch(intent.getComponent().getPackageName(), shortcut, sourceExtras); + } } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index a74fa0dbc..0b72ef793 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -52,11 +52,11 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; -import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.widget.TextView; +import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.Launcher.CustomContentCallbacks; @@ -179,22 +179,20 @@ public class Workspace extends PagedView // in all apps or customize mode) enum State { - NORMAL (SearchDropTargetBar.State.SEARCH_BAR), - NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED), - SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET), - OVERVIEW (SearchDropTargetBar.State.INVISIBLE), - OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE); + NORMAL (SearchDropTargetBar.State.SEARCH_BAR, false), + NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE_TRANSLATED, false), + SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET, false), + OVERVIEW (SearchDropTargetBar.State.INVISIBLE, true), + OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE, true); - private final SearchDropTargetBar.State mBarState; + public final SearchDropTargetBar.State searchDropTargetBarState; + public final boolean shouldUpdateWidget; - State(SearchDropTargetBar.State searchBarState) { - mBarState = searchBarState; + State(SearchDropTargetBar.State searchBarState, boolean shouldUpdateWidget) { + searchDropTargetBarState = searchBarState; + this.shouldUpdateWidget = shouldUpdateWidget; } - - public SearchDropTargetBar.State getSearchDropTargetBarState() { - return mBarState; - } - }; + } @ViewDebug.ExportedProperty(category = "launcher") private State mState = State.NORMAL; @@ -1914,6 +1912,8 @@ public class Workspace extends PagedView Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(mState, toState, animated, layerViews); + boolean shouldNotifyWidgetChange = !mState.shouldUpdateWidget + && toState.shouldUpdateWidget; // Update the current state mState = toState; updateAccessibilityFlags(); @@ -1923,6 +1923,10 @@ public class Workspace extends PagedView invalidate(); // This will call dispatchDraw(), which calls getVisiblePages(). } + if (shouldNotifyWidgetChange) { + mLauncher.notifyWidgetProvidersChanged(); + } + return workspaceAnim; } @@ -4148,13 +4152,22 @@ public class Workspace extends PagedView }); } - void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) { + public void widgetsRestored(ArrayList<LauncherAppWidgetInfo> changedInfo) { if (!changedInfo.isEmpty()) { DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, mLauncher.getAppWidgetHost()); - if (LauncherModel.getProviderInfo(getContext(), - changedInfo.get(0).providerName, - changedInfo.get(0).user) != null) { + + LauncherAppWidgetInfo item = changedInfo.get(0); + final AppWidgetProviderInfo widgetInfo; + if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { + widgetInfo = AppWidgetManagerCompat + .getInstance(mLauncher).findProvider(item.providerName, item.user); + } else { + widgetInfo = AppWidgetManagerCompat.getInstance(mLauncher) + .getAppWidgetInfo(item.appWidgetId); + } + + if (widgetInfo != null) { // Re-inflate the widgets which have changed status widgetRefresh.run(); } else { diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index f0221bc24..811cacfc0 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; @@ -28,7 +29,9 @@ import android.os.Bundle; import com.android.launcher3.IconCache; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.util.ComponentKey; +import java.util.HashMap; import java.util.List; public abstract class AppWidgetManagerCompat { @@ -62,6 +65,11 @@ public abstract class AppWidgetManagerCompat { return mAppWidgetManager.getAppWidgetInfo(appWidgetId); } + public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(int appWidgetId) { + AppWidgetProviderInfo info = getAppWidgetInfo(appWidgetId); + return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); + } + public abstract List<AppWidgetProviderInfo> getAllProviders(); public abstract String loadLabel(LauncherAppWidgetProviderInfo info); @@ -81,4 +89,8 @@ public abstract class AppWidgetManagerCompat { public abstract Bitmap getBadgeBitmap(LauncherAppWidgetProviderInfo info, Bitmap bitmap, int imageWidth, int imageHeight); + public abstract LauncherAppWidgetProviderInfo findProvider( + ComponentName provider, UserHandleCompat user); + + public abstract HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap(); } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java index e9d2510e8..de9414ed2 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -31,7 +32,9 @@ import android.os.Bundle; import com.android.launcher3.IconCache; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.util.ComponentKey; +import java.util.HashMap; import java.util.List; class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { @@ -91,4 +94,25 @@ class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { int imageWidth, int imageHeight) { return bitmap; } + + @Override + public LauncherAppWidgetProviderInfo findProvider( + ComponentName provider, UserHandleCompat user) { + for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) { + if (info.provider.equals(provider)) { + return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); + } + } + return null; + } + + @Override + public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() { + HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>(); + UserHandleCompat user = UserHandleCompat.myUserHandle(); + for (AppWidgetProviderInfo info : mAppWidgetManager.getInstalledProviders()) { + result.put(new ComponentKey(info.provider, user), info); + } + return result; + } } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java index 3bc3d0d80..a1570e66a 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; @@ -40,8 +41,10 @@ import android.widget.Toast; import com.android.launcher3.IconCache; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; +import com.android.launcher3.util.ComponentKey; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -145,4 +148,28 @@ class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { c.setBitmap(null); return bitmap; } + + @Override + public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandleCompat user) { + for (AppWidgetProviderInfo info : mAppWidgetManager + .getInstalledProvidersForProfile(user.getUser())) { + if (info.provider.equals(provider)) { + return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); + } + } + return null; + } + + @Override + public HashMap<ComponentKey, AppWidgetProviderInfo> getAllProvidersMap() { + HashMap<ComponentKey, AppWidgetProviderInfo> result = new HashMap<>(); + for (UserHandle user : mUserManager.getUserProfiles()) { + UserHandleCompat userHandle = UserHandleCompat.fromUser(user); + for (AppWidgetProviderInfo info : + mAppWidgetManager.getInstalledProvidersForProfile(user)) { + result.put(new ComponentKey(info.provider, userHandle), info); + } + } + return result; + } } diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java index 19ec3ed64..931466c3b 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationTask.java +++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java @@ -23,8 +23,8 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Utilities; import com.android.launcher3.backup.nano.BackupProtos; +import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.PackageInstallerCompat; -import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.util.LongArrayMap; import java.util.ArrayList; @@ -696,7 +696,8 @@ public class GridSizeMigrationTask { Favorites.SPANX, // 4 Favorites.SPANY, // 5 Favorites.INTENT, // 6 - Favorites.APPWIDGET_PROVIDER}, // 7 + Favorites.APPWIDGET_PROVIDER, // 7 + Favorites.APPWIDGET_ID}, // 8 Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP + " AND " + Favorites.SCREEN + " = " + screen, null, null, null); @@ -708,6 +709,7 @@ public class GridSizeMigrationTask { final int indexSpanY = c.getColumnIndexOrThrow(Favorites.SPANY); final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT); final int indexAppWidgetProvider = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER); + final int indexAppWidgetId = c.getColumnIndexOrThrow(Favorites.APPWIDGET_ID); ArrayList<DbEntry> entries = new ArrayList<>(); while (c.moveToNext()) { @@ -737,9 +739,9 @@ public class GridSizeMigrationTask { entry.weight = Math.max(WT_WIDGET_MIN, WT_WIDGET_FACTOR * entry.spanX * entry.spanY); - // Migration happens for current user only. - LauncherAppWidgetProviderInfo pInfo = LauncherModel.getProviderInfo( - mContext, cn, UserHandleCompat.myUserHandle()); + int widgetId = c.getInt(indexAppWidgetId); + LauncherAppWidgetProviderInfo pInfo = AppWidgetManagerCompat.getInstance( + mContext).getLauncherAppWidgetInfo(widgetId); Point spans = pInfo == null ? mWidgetMinSize.get(provider) : pInfo.getMinSpans(mIdp, mContext); if (spans != null) { diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index 99a53ff36..e043c948f 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -1,9 +1,13 @@ package com.android.launcher3.model; +import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.ResolveInfo; +import android.os.DeadObjectException; +import android.os.TransactionTooLargeException; import android.util.Log; import com.android.launcher3.AppFilter; @@ -16,6 +20,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.config.ProviderConfig; import java.util.ArrayList; import java.util.Collections; @@ -95,8 +100,41 @@ public class WidgetsModel { return mRawList; } - public void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) { + public boolean isEmpty() { + return mRawList.isEmpty(); + } + + public WidgetsModel updateAndClone(Context context) { Utilities.assertWorkerThread(); + + try { + final ArrayList<Object> widgetsAndShortcuts = new ArrayList<>(); + // Widgets + for (AppWidgetProviderInfo widgetInfo : + AppWidgetManagerCompat.getInstance(context).getAllProviders()) { + widgetsAndShortcuts.add(LauncherAppWidgetProviderInfo + .fromProviderInfo(context, widgetInfo)); + } + // Shortcuts + widgetsAndShortcuts.addAll(context.getPackageManager().queryIntentActivities( + new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)); + setWidgetsAndShortcuts(widgetsAndShortcuts); + } 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. + } else { + throw e; + } + } + return clone(); + } + + private void setWidgetsAndShortcuts(ArrayList<Object> rawWidgetsShortcuts) { mRawList = rawWidgetsShortcuts; if (DEBUG) { Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index d7ed9ed6b..2a08d2ddd 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -327,6 +327,10 @@ public class WidgetsContainerView extends BaseContainerView mAdapter.notifyDataSetChanged(); } + public boolean isEmpty() { + return mAdapter.getItemCount() == 0; + } + private WidgetPreviewLoader getWidgetPreviewLoader() { if (mWidgetPreviewLoader == null) { mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache(); |