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
This commit is contained in:
Sunny Goyal
2016-03-03 16:58:55 -08:00
parent 58b53b5dff
commit 1024a80f2c
12 changed files with 262 additions and 255 deletions
+54 -34
View File
@@ -1594,8 +1594,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) {
@@ -2591,10 +2590,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;
@@ -3593,10 +3592,6 @@ public class Launcher extends Activity
// TODO
}
protected void disableVoiceButtonProxy(boolean disable) {
// NO-OP
}
public boolean launcherCallbacksProvidesSearch() {
return (mLauncherCallbacks != null && mLauncherCallbacks.providesSearch());
}
@@ -4002,6 +3997,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.
*
@@ -4017,19 +4022,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
@@ -4041,7 +4058,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.
@@ -4077,46 +4094,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 "
@@ -4422,15 +4435,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;
}
@@ -4441,6 +4454,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;
@@ -102,6 +102,10 @@ public class LauncherAppWidgetHost extends AppWidgetHost {
callback.run();
}
}
if (Utilities.ATLEAST_MARSHMALLOW) {
mLauncher.notifyWidgetProvidersChanged();
}
}
public AppWidgetHostView createView(Context context, int appWidgetId,
@@ -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;
}
+45 -186
View File
@@ -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;
@@ -69,7 +66,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;
@@ -138,11 +134,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
@@ -169,12 +163,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);
@@ -1778,8 +1766,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);
@@ -1788,6 +1776,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);
@@ -2157,10 +2146,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 &&
@@ -2779,7 +2772,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 "
@@ -2871,7 +2863,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");
@@ -2880,8 +2872,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");
@@ -2948,9 +2938,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) {
@@ -3316,177 +3303,49 @@ 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 (LauncherAppState.isDogfoodBuild()) {
throw e;
}
// Ignore the crash. We can live with a state widget list.
Log.e(TAG, "PM call failed for " + pkg, e);
}
}
}
loadAndBindWidgetsAndShortcuts(callbacks, needToRefresh);
}
// Write all the logs to disk
mHandler.post(new Runnable() {
public void run() {
Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.dumpLogsToLocalData();
}
}
});
}
}
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 (!LauncherAppState.isDogfoodBuild() &&
(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;
}
} 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) {
runOnWorkerThread(new Runnable() {
@Override
public void run() {
updateWidgetsModel(refresh);
// 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() {
@Override
public void run() {
Callbacks cb = getCallback();
if (callbacks == cb && cb != null) {
callbacks.bindAllPackages(mFgWidgetsModel);
callbacks.notifyWidgetProvidersChanged();
}
}
});
// update the Widget entries inside DB on the worker thread.
LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(
mFgWidgetsModel.getRawList());
}
}
}
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);
}
}
});
}
/**
* 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 (!LauncherAppState.isDogfoodBuild() &&
(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;
public void refreshAndBindWidgetsAndShortcuts(
final Callbacks callbacks, final boolean bindFirst) {
runOnWorkerThread(new Runnable() {
@Override
public void run() {
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(
model.getRawList());
}
if (sBgShortcutProviders != null) {
widgetsAndShortcuts.addAll(sBgShortcutProviders);
}
}
mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);
mFgWidgetsModel = mBgWidgetsModel.clone();
});
}
@Thunk static boolean isPackageDisabled(Context context, String packageName,
@@ -702,7 +702,7 @@ public class LauncherStateTransitionAnimation {
private void startWorkspaceSearchBarAnimation(
final Workspace.State toWorkspaceState, int duration, AnimatorSet animation) {
final SearchDropTargetBar.State toSearchBarState =
toWorkspaceState.getSearchDropTargetBarState();
toWorkspaceState.searchDropTargetBarState;
mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration, animation);
}
+31 -17
View File
@@ -68,6 +68,7 @@ import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.AccessibilityDragSource;
import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate;
import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
@@ -180,22 +181,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;
}
};
}
private State mState = State.NORMAL;
private boolean mIsSwitchingState = false;
@@ -2017,10 +2016,16 @@ public class Workspace extends PagedView
Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(mState,
toState, toPage, animated, layerViews);
boolean shouldNotifyWidgetChange = !mState.shouldUpdateWidget
&& toState.shouldUpdateWidget;
// Update the current state
mState = toState;
updateAccessibilityFlags();
if (shouldNotifyWidgetChange) {
mLauncher.notifyWidgetProvidersChanged();
}
return workspaceAnim;
}
@@ -4400,13 +4405,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 {
@@ -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();
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
@@ -692,7 +692,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);
@@ -704,6 +705,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()) {
@@ -733,9 +735,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) {
@@ -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 (!LauncherAppState.isDogfoodBuild() &&
(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());
@@ -332,6 +332,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();