From 86222d23e28a09a7a26e7a0d4b4830ded2efb384 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 29 Mar 2017 15:30:43 -0700 Subject: Add support for getting widgets/shortucts for a particular package/user Bug: 34940468 Bug: 33553066 Change-Id: I5d0131df206c6a13d4227ad28c5b094bbf1343df --- src/com/android/launcher3/Launcher.java | 15 ++++-- src/com/android/launcher3/LauncherModel.java | 11 +++-- src/com/android/launcher3/WidgetPreviewLoader.java | 16 ++++++- .../launcher3/compat/AppWidgetManagerCompat.java | 14 ++++-- .../launcher3/compat/AppWidgetManagerCompatVL.java | 26 ++++++++--- .../launcher3/compat/AppWidgetManagerCompatVO.java | 53 ++++++++++++++++++++++ .../launcher3/compat/LauncherAppsCompat.java | 4 +- .../launcher3/compat/LauncherAppsCompatVL.java | 15 ++++-- .../launcher3/compat/LauncherAppsCompatVO.java | 22 +++++++-- src/com/android/launcher3/model/WidgetsModel.java | 51 ++++++++++++++++----- .../android/launcher3/popup/PopupPopulator.java | 4 +- 11 files changed, 191 insertions(+), 40 deletions(-) create mode 100644 src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java (limited to 'src/com/android') diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 4eeb3c0b6..dbf535a80 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -54,6 +54,7 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.support.annotation.Nullable; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -3929,13 +3930,17 @@ public class Launcher extends BaseActivity @Override public void notifyWidgetProvidersChanged() { - notifyWidgetProvidersChanged(false); + if (mWorkspace.getState().shouldUpdateWidget) { + refreshAndBindWidgetsForPackageUser(null); + } } - public void notifyWidgetProvidersChanged(boolean force) { - if (force || mWorkspace.getState().shouldUpdateWidget) { - mModel.refreshAndBindWidgetsAndShortcuts(this, mWidgetsView.isEmpty()); - } + /** + * @param packageUser if null, refreshes all widgets and shortcuts, otherwise only + * refreshes the widgets and shortcuts associated with the given package/user + */ + public void refreshAndBindWidgetsForPackageUser(@Nullable PackageUserKey packageUser) { + mModel.refreshAndBindWidgetsAndShortcuts(this, mWidgetsView.isEmpty(), packageUser); } public void lockScreenOrientation() { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 5a41eeb1f..d451e3de9 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -34,6 +34,7 @@ import android.os.Process; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; @@ -74,6 +75,7 @@ import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Provider; import com.android.launcher3.util.Thunk; @@ -1905,19 +1907,20 @@ public class LauncherModel extends BroadcastReceiver }); } - public void refreshAndBindWidgetsAndShortcuts( - final Callbacks callbacks, final boolean bindFirst) { + public void refreshAndBindWidgetsAndShortcuts(final Callbacks callbacks, + final boolean bindFirst, @Nullable final PackageUserKey packageUser) { runOnWorkerThread(new Runnable() { @Override public void run() { if (bindFirst && !mBgWidgetsModel.isEmpty()) { bindWidgetsModel(callbacks); } - ArrayList allWidgets = mBgWidgetsModel.update(mApp.getContext()); + ArrayList widgets = mBgWidgetsModel.update( + mApp.getContext(), packageUser); bindWidgetsModel(callbacks); // update the Widget entries inside DB on the worker thread. - mApp.getWidgetCache().removeObsoletePreviews(allWidgets); + mApp.getWidgetCache().removeObsoletePreviews(widgets, packageUser); } }); } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 49e68d75a..fc3b66887 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -25,6 +25,7 @@ import android.os.AsyncTask; import android.os.CancellationSignal; import android.os.Handler; import android.os.UserHandle; +import android.support.annotation.Nullable; import android.support.v4.graphics.ColorUtils; import android.util.Log; import android.util.LongSparseArray; @@ -36,6 +37,7 @@ import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.graphics.ShadowGenerator; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.SQLiteCacheHelper; import com.android.launcher3.util.Thunk; @@ -170,8 +172,12 @@ public class WidgetPreviewLoader { * 1. Any preview generated for an old package version is removed * 2. Any preview for an absent package is removed * This ensures that we remove entries for packages which changed while the launcher was dead. + * + * @param packageUser if provided, specifies that list only contains previews for the + * given package/user, otherwise the list contains all previews */ - public void removeObsoletePreviews(ArrayList list) { + public void removeObsoletePreviews(ArrayList list, + @Nullable PackageUserKey packageUser) { Preconditions.assertWorkerThread(); LongSparseArray> validPackages = new LongSparseArray<>(); @@ -187,6 +193,8 @@ public class WidgetPreviewLoader { } LongSparseArray> packagesToDelete = new LongSparseArray<>(); + long passedUserId = packageUser == null ? 0 + : mUserManager.getSerialNumberForUser(packageUser.mUser); Cursor c = null; try { c = mDb.query( @@ -199,6 +207,12 @@ public class WidgetPreviewLoader { long lastUpdated = c.getLong(2); long version = c.getLong(3); + if (packageUser != null && (!pkg.equals(packageUser.mPackageName) + || userId != passedUserId)) { + // This preview is associated with a different package/user, no need to remove. + continue; + } + HashSet packages = validPackages.get(userId); if (packages != null && packages.contains(pkg)) { long[] versions = getPackageVersion(pkg); diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index 7911bb213..3efbbfba5 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -22,12 +22,15 @@ import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; -import android.graphics.Bitmap; import android.os.Bundle; import android.os.UserHandle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.Utilities; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageUserKey; import java.util.HashMap; import java.util.List; @@ -40,7 +43,11 @@ public abstract class AppWidgetManagerCompat { public static AppWidgetManagerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext()); + if (Utilities.isAtLeastO()) { + sInstance = new AppWidgetManagerCompatVO(context.getApplicationContext()); + } else { + sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext()); + } } return sInstance; } @@ -63,7 +70,8 @@ public abstract class AppWidgetManagerCompat { return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); } - public abstract List getAllProviders(); + public abstract List getAllProviders( + @Nullable PackageUserKey packageUser); public abstract boolean bindAppWidgetIdIfAllowed( int appWidgetId, AppWidgetProviderInfo info, Bundle options); diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java index 61dd1a5b7..f239f5c31 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVL.java @@ -22,36 +22,48 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; +import android.support.annotation.Nullable; import android.widget.Toast; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.R; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; class AppWidgetManagerCompatVL extends AppWidgetManagerCompat { private final UserManager mUserManager; - private final PackageManager mPm; AppWidgetManagerCompatVL(Context context) { super(context); - mPm = context.getPackageManager(); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); } @Override - public List getAllProviders() { - ArrayList providers = new ArrayList(); - for (UserHandle user : mUserManager.getUserProfiles()) { - providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user)); + public List getAllProviders(@Nullable PackageUserKey packageUser) { + if (packageUser == null) { + ArrayList providers = new ArrayList(); + for (UserHandle user : mUserManager.getUserProfiles()) { + providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user)); + } + return providers; + } + // Only get providers for the given package/user. + List providers = new ArrayList<>(mAppWidgetManager + .getInstalledProvidersForProfile(packageUser.mUser)); + Iterator iterator = providers.iterator(); + while (iterator.hasNext()) { + if (!iterator.next().provider.getPackageName().equals(packageUser.mPackageName)) { + iterator.remove(); + } } return providers; } diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java new file mode 100644 index 000000000..bde8b7801 --- /dev/null +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatVO.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.compat; + +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProviderInfo; +import android.content.Context; +import android.os.UserHandle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import com.android.launcher3.util.PackageUserKey; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +class AppWidgetManagerCompatVO extends AppWidgetManagerCompatVL { + + AppWidgetManagerCompatVO(Context context) { + super(context); + } + + @Override + public List getAllProviders(@Nullable PackageUserKey packageUser) { + if (packageUser == null) { + return super.getAllProviders(null); + } + // TODO: don't use reflection once API and sdk are ready. + try { + return (List) AppWidgetManager.class.getMethod( + "getInstalledProvidersForPackage", String.class, UserHandle.class) + .invoke(mAppWidgetManager, packageUser.mPackageName, packageUser.mUser); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + Log.e("AppWidgetManagerCompat", "Failed to call new API", e); + } + return super.getAllProviders(packageUser); + } +} diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java index 4580b8108..f17d8deef 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -33,6 +33,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.graphics.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.util.LooperExecuter; +import com.android.launcher3.util.PackageUserKey; import java.util.List; @@ -83,7 +84,8 @@ public abstract class LauncherAppsCompat { public abstract boolean isPackageEnabledForProfile(String packageName, UserHandle user); public abstract boolean isActivityEnabledForProfile(ComponentName component, UserHandle user); - public abstract List getCustomShortcutActivityList(); + public abstract List getCustomShortcutActivityList( + @Nullable PackageUserKey packageUser); /** * request.accept() will initiate the following flow: diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java index 459017392..58683db75 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java @@ -29,9 +29,11 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.Process; import android.os.UserHandle; +import android.support.annotation.Nullable; import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL; import com.android.launcher3.shortcuts.ShortcutInfoCompat; +import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.HashMap; @@ -175,12 +177,19 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat { } @Override - public List getCustomShortcutActivityList() { - PackageManager pm = mContext.getPackageManager(); + public List getCustomShortcutActivityList( + @Nullable PackageUserKey packageUser) { List result = new ArrayList<>(); + if (packageUser != null && !packageUser.mUser.equals(Process.myUserHandle())) { + return result; + } + PackageManager pm = mContext.getPackageManager(); for (ResolveInfo info : pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) { - result.add(new ShortcutConfigActivityInfoVL(info.activityInfo, pm)); + if (packageUser == null || packageUser.mPackageName + .equals(info.activityInfo.packageName)) { + result.add(new ShortcutConfigActivityInfoVL(info.activityInfo, pm)); + } } return result; } diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java index d7e35a2e5..95f2e74f4 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatVO.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompatVO.java @@ -23,12 +23,15 @@ import android.content.pm.LauncherApps; import android.os.Build; import android.os.Process; import android.os.UserHandle; +import android.support.annotation.Nullable; import android.util.Log; +import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO; +import com.android.launcher3.util.PackageUserKey; + import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; -import com.android.launcher3.compat.ShortcutConfigActivityInfo.*; public class LauncherAppsCompatVO extends LauncherAppsCompatVL { @@ -44,17 +47,28 @@ public class LauncherAppsCompatVO extends LauncherAppsCompatVL { } @Override - public List getCustomShortcutActivityList() { + public List getCustomShortcutActivityList( + @Nullable PackageUserKey packageUser) { List result = new ArrayList<>(); UserHandle myUser = Process.myUserHandle(); try { Method m = LauncherApps.class.getDeclaredMethod("getShortcutConfigActivityList", String.class, UserHandle.class); - for (UserHandle user : UserManagerCompat.getInstance(mContext).getUserProfiles()) { + final List users; + final String packageName; + if (packageUser == null) { + users = UserManagerCompat.getInstance(mContext).getUserProfiles(); + packageName = null; + } else { + users = new ArrayList<>(1); + users.add(packageUser.mUser); + packageName = packageUser.mPackageName; + } + for (UserHandle user : users) { boolean ignoreTargetSdk = myUser.equals(user); List activities = - (List) m.invoke(mLauncherApps, null, user); + (List) m.invoke(mLauncherApps, packageName, user); for (LauncherActivityInfo activityInfo : activities) { if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) { diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index 95c54f767..e5215c70f 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -3,11 +3,10 @@ package com.android.launcher3.model; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.os.Process; import android.os.UserHandle; +import android.support.annotation.Nullable; import android.util.Log; import com.android.launcher3.AppFilter; @@ -19,13 +18,14 @@ import com.android.launcher3.Utilities; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.ShortcutConfigActivityInfo; -import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.ProviderConfig; import com.android.launcher3.util.MultiHashMap; +import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; /** * Widgets data model that is used by the adapters of the widget views and controllers. @@ -57,7 +57,11 @@ public class WidgetsModel { return mWidgetsList.isEmpty(); } - public ArrayList update(Context context) { + /** + * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise + * only widgets and shortcuts associated with the package/user are. + */ + public ArrayList update(Context context, @Nullable PackageUserKey packageUser) { Preconditions.assertWorkerThread(); final ArrayList widgetsAndShortcuts = new ArrayList<>(); @@ -66,18 +70,18 @@ public class WidgetsModel { InvariantDeviceProfile idp = LauncherAppState.getIDP(context); // Widgets - for (AppWidgetProviderInfo widgetInfo : - AppWidgetManagerCompat.getInstance(context).getAllProviders()) { + AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(context); + for (AppWidgetProviderInfo widgetInfo : widgetManager.getAllProviders(packageUser)) { widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo .fromProviderInfo(context, widgetInfo), pm, idp)); } // Shortcuts for (ShortcutConfigActivityInfo info : LauncherAppsCompat.getInstance(context) - .getCustomShortcutActivityList()) { + .getCustomShortcutActivityList(packageUser)) { widgetsAndShortcuts.add(new WidgetItem(info)); } - setWidgetsAndShortcuts(widgetsAndShortcuts, context); + setWidgetsAndShortcuts(widgetsAndShortcuts, context, packageUser); } catch (Exception e) { if (!ProviderConfig.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) { // the returned value may be incomplete and will not be refreshed until the next @@ -92,7 +96,7 @@ public class WidgetsModel { } private void setWidgetsAndShortcuts(ArrayList rawWidgetsShortcuts, - Context context) { + Context context, @Nullable PackageUserKey packageUser) { if (DEBUG) { Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size()); } @@ -102,13 +106,38 @@ public class WidgetsModel { HashMap tmpPackageItemInfos = new HashMap<>(); // clear the lists. - mWidgetsList.clear(); + if (packageUser == null) { + mWidgetsList.clear(); + } else { + // Only clear the widgets for the given package/user. + PackageItemInfo packageItem = null; + for (PackageItemInfo item : mWidgetsList.keySet()) { + if (item.packageName.equals(packageUser.mPackageName)) { + packageItem = item; + break; + } + } + if (packageItem != null) { + // We want to preserve the user that was on the packageItem previously, + // so add it to tmpPackageItemInfos here to avoid creating a new entry. + tmpPackageItemInfos.put(packageItem.packageName, packageItem); + + Iterator widgetItemIterator = mWidgetsList.get(packageItem).iterator(); + while (widgetItemIterator.hasNext()) { + WidgetItem nextWidget = widgetItemIterator.next(); + if (nextWidget.componentName.getPackageName().equals(packageUser.mPackageName) + && nextWidget.user.equals(packageUser.mUser)) { + widgetItemIterator.remove(); + } + } + } + } InvariantDeviceProfile idp = LauncherAppState.getIDP(context); UserHandle myUser = Process.myUserHandle(); // add and update. - for (WidgetItem item: rawWidgetsShortcuts) { + for (WidgetItem item : rawWidgetsShortcuts) { if (item.widgetInfo != null) { // Ensure that all widgets we show can be added on a workspace of this size int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java index 838b9b1db..d26d3062b 100644 --- a/src/com/android/launcher3/popup/PopupPopulator.java +++ b/src/com/android/launcher3/popup/PopupPopulator.java @@ -38,6 +38,7 @@ import com.android.launcher3.notification.NotificationKeyData; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutInfoCompat; +import com.android.launcher3.util.PackageUserKey; import java.util.ArrayList; import java.util.Collections; @@ -219,7 +220,8 @@ public class PopupPopulator { uiHandler.post(new Runnable() { @Override public void run() { - launcher.notifyWidgetProvidersChanged(true /* force */); + launcher.refreshAndBindWidgetsForPackageUser( + PackageUserKey.fromItemInfo(originalInfo)); } }); } -- cgit v1.2.3