Merge "Changing the widget loading strategy" into ub-launcher3-calgary

am: d856074d90

* commit 'd856074d90b31390f1a70d09fde374cae925bf20':
  Changing the widget loading strategy
This commit is contained in:
Sunny Goyal
2016-03-10 04:26:22 +00:00
committed by android-build-merger
13 changed files with 265 additions and 247 deletions
+54 -34
View File
@@ -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;
@@ -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 -176
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;
@@ -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,167 +3217,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 (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);
}
}
}
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;
}
} 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 (!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;
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,
@@ -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);
+3 -1
View File
@@ -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);
}
}
}
+31 -18
View File
@@ -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 {
@@ -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;
@@ -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) {
@@ -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());
@@ -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();