Merge "Add support for getting widgets/shortucts for a particular package/user" into ub-launcher3-dorval

This commit is contained in:
Tony Wickham
2017-04-05 19:54:40 +00:00
committed by Android (Google) Code Review
11 changed files with 191 additions and 40 deletions

View File

@@ -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() {

View File

@@ -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<WidgetItem> allWidgets = mBgWidgetsModel.update(mApp.getContext());
ArrayList<WidgetItem> 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);
}
});
}

View File

@@ -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<? extends ComponentKey> list) {
public void removeObsoletePreviews(ArrayList<? extends ComponentKey> list,
@Nullable PackageUserKey packageUser) {
Preconditions.assertWorkerThread();
LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>();
@@ -187,6 +193,8 @@ public class WidgetPreviewLoader {
}
LongSparseArray<HashSet<String>> 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<String> packages = validPackages.get(userId);
if (packages != null && packages.contains(pkg)) {
long[] versions = getPackageVersion(pkg);

View File

@@ -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<AppWidgetProviderInfo> getAllProviders();
public abstract List<AppWidgetProviderInfo> getAllProviders(
@Nullable PackageUserKey packageUser);
public abstract boolean bindAppWidgetIdIfAllowed(
int appWidgetId, AppWidgetProviderInfo info, Bundle options);

View File

@@ -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<AppWidgetProviderInfo> getAllProviders() {
ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
for (UserHandle user : mUserManager.getUserProfiles()) {
providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
if (packageUser == null) {
ArrayList<AppWidgetProviderInfo> providers = new ArrayList<AppWidgetProviderInfo>();
for (UserHandle user : mUserManager.getUserProfiles()) {
providers.addAll(mAppWidgetManager.getInstalledProvidersForProfile(user));
}
return providers;
}
// Only get providers for the given package/user.
List<AppWidgetProviderInfo> providers = new ArrayList<>(mAppWidgetManager
.getInstalledProvidersForProfile(packageUser.mUser));
Iterator<AppWidgetProviderInfo> iterator = providers.iterator();
while (iterator.hasNext()) {
if (!iterator.next().provider.getPackageName().equals(packageUser.mPackageName)) {
iterator.remove();
}
}
return providers;
}

View File

@@ -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<AppWidgetProviderInfo> 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<AppWidgetProviderInfo>) 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);
}
}

View File

@@ -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<ShortcutConfigActivityInfo> getCustomShortcutActivityList();
public abstract List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
@Nullable PackageUserKey packageUser);
/**
* request.accept() will initiate the following flow:

View File

@@ -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<ShortcutConfigActivityInfo> getCustomShortcutActivityList() {
PackageManager pm = mContext.getPackageManager();
public List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
@Nullable PackageUserKey packageUser) {
List<ShortcutConfigActivityInfo> 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;
}

View File

@@ -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<ShortcutConfigActivityInfo> getCustomShortcutActivityList() {
public List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
@Nullable PackageUserKey packageUser) {
List<ShortcutConfigActivityInfo> 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<UserHandle> 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<LauncherActivityInfo> activities =
(List<LauncherActivityInfo>) m.invoke(mLauncherApps, null, user);
(List<LauncherActivityInfo>) m.invoke(mLauncherApps, packageName, user);
for (LauncherActivityInfo activityInfo : activities) {
if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.O) {

View File

@@ -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<WidgetItem> 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<WidgetItem> update(Context context, @Nullable PackageUserKey packageUser) {
Preconditions.assertWorkerThread();
final ArrayList<WidgetItem> 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<WidgetItem> 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<String, PackageItemInfo> 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<WidgetItem> 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);

View File

@@ -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));
}
});
}