Removing static reference of deep shortcut manager

Bug: 141376165
Change-Id: Ie60b82be63a8926825598c681d8b2a1b2ace6413
This commit is contained in:
Sunny Goyal 2019-12-11 10:00:47 -08:00
parent 98833d525c
commit fa39536570
20 changed files with 284 additions and 402 deletions

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 2018 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.shortcuts;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.notification.NotificationKeyData;
import java.util.ArrayList;
import java.util.List;
/**
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
*/
public class DeepShortcutManager {
private static final DeepShortcutManager sInstance = new DeepShortcutManager();
public static DeepShortcutManager getInstance(Context context) {
return sInstance;
}
private final QueryResult mFailure = new QueryResult();
private DeepShortcutManager() { }
/**
* Queries for the shortcuts with the package name and provided ids.
*
* This method is intended to get the full details for shortcuts when they are added or updated,
* because we only get "key" fields in onShortcutsChanged().
*/
public QueryResult queryForFullDetails(String packageName,
List<String> shortcutIds, UserHandle user) {
return mFailure;
}
/**
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
public QueryResult queryForShortcutsContainer(ComponentName activity,
UserHandle user) {
return mFailure;
}
/**
* Removes the given shortcut from the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void unpinShortcut(final ShortcutKey key) {
}
/**
* Adds the given shortcut to the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void pinShortcut(final ShortcutKey key) {
}
public void startShortcut(String packageName, String id, Rect sourceBounds,
Bundle startActivityOptions, UserHandle user) {
}
public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
return null;
}
/**
* Returns the id's of pinned shortcuts associated with the given package and user.
*
* If packageName is null, returns all pinned shortcuts regardless of package.
*/
public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
return mFailure;
}
public QueryResult queryForPinnedShortcuts(String packageName,
List<String> shortcutIds, UserHandle user) {
return mFailure;
}
public QueryResult queryForAllShortcuts(UserHandle user) {
return mFailure;
}
public boolean hasHostPermission() {
return false;
}
public static class QueryResult extends ArrayList<ShortcutInfo> {
public boolean wasSuccess() {
return true;
}
}
}

View File

@ -44,8 +44,8 @@ import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList;
@ -167,11 +167,7 @@ public class DynamicItemCache {
@WorkerThread
private WorkspaceItemInfo loadShortcutWorker(ShortcutKey shortcutKey) {
DeepShortcutManager mgr = DeepShortcutManager.getInstance(mContext);
List<ShortcutInfo> details = mgr.queryForFullDetails(
shortcutKey.componentName.getPackageName(),
Collections.<String>singletonList(shortcutKey.getId()),
shortcutKey.user);
List<ShortcutInfo> details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL);
if (!details.isEmpty()) {
WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext);
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {

View File

@ -16,6 +16,7 @@
package com.android.launcher3;
import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@ -24,7 +25,12 @@ import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import android.view.ContextThemeWrapper;
import androidx.annotation.IntDef;
@ -47,6 +53,8 @@ import java.util.ArrayList;
public abstract class BaseActivity extends Activity
implements UserEventDelegate, LogStateProvider, ActivityContext {
private static final String TAG = "BaseActivity";
public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
public static final int INVISIBLE_BY_PENDING_FLAGS = 1 << 2;
@ -312,6 +320,22 @@ public abstract class BaseActivity extends Activity
writer.println(prefix + "mForceInvisible: " + mForceInvisible);
}
/**
* A wrapper around the platform method with Launcher specific checks
*/
public void startShortcut(String packageName, String id, Rect sourceBounds,
Bundle startActivityOptions, UserHandle user) {
if (GO_DISABLE_WIDGETS) {
return;
}
try {
getSystemService(LauncherApps.class).startShortcut(packageName, id, sourceBounds,
startActivityOptions, user);
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "Failed to start shortcut", e);
}
}
public static <T extends BaseActivity> T fromContext(Context context) {
if (context instanceof BaseActivity) {
return (T) context;

View File

@ -35,7 +35,6 @@ import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.PackageManagerHelper;
@ -198,8 +197,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
String packageName = intent.getPackage();
DeepShortcutManager.getInstance(this).startShortcut(
packageName, id, intent.getSourceBounds(), optsBundle, info.user);
startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
AppLaunchTracker.INSTANCE.get(this).onStartShortcut(packageName, id, info.user,
sourceContainer);
} else {

View File

@ -49,8 +49,8 @@ import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Thunk;
@ -538,12 +538,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
return new PendingInstallShortcutInfo(info, context);
}
} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
List<ShortcutInfo> si = sm.queryForFullDetails(
decoder.launcherIntent.getPackage(),
Arrays.asList(decoder.launcherIntent.getStringExtra(
ShortcutKey.EXTRA_SHORTCUT_ID)),
decoder.user);
List<ShortcutInfo> si = ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user)
.buildRequest(context)
.query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {

View File

@ -20,6 +20,7 @@ import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import android.content.Context;
import android.content.Intent;
@ -54,7 +55,7 @@ import com.android.launcher3.model.UserLockStateChangedTask;
import com.android.launcher3.pm.InstallSessionTracker;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@ -113,12 +114,9 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
private final Runnable mShortcutPermissionCheckRunnable = new Runnable() {
@Override
public void run() {
if (mModelLoaded) {
boolean hasShortcutHostPermission =
DeepShortcutManager.getInstance(mApp.getContext()).hasHostPermission();
if (hasShortcutHostPermission != sBgDataModel.hasShortcutHostPermission) {
forceReload();
}
if (mModelLoaded && hasShortcutsPermission(mApp.getContext())
!= sBgDataModel.hasShortcutHostPermission) {
forceReload();
}
}
};
@ -220,8 +218,8 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi
Context context = mApp.getContext();
onPackageChanged(packageName, user);
List<ShortcutInfo> pinnedShortcuts = DeepShortcutManager.getInstance(context)
.queryForPinnedShortcuts(packageName, user);
List<ShortcutInfo> pinnedShortcuts = new ShortcutRequest(context, user)
.forPackage(packageName).query(ShortcutRequest.PINNED);
if (!pinnedShortcuts.isEmpty()) {
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, pinnedShortcuts, user,
false));

View File

@ -65,9 +65,10 @@ import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.ShortcutCachingLogic;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.Transposable;
@ -540,15 +541,14 @@ public final class Utilities {
outObj[0] = activityInfo;
return activityInfo.getFullResIcon(appState.getIconCache());
}
ShortcutKey key = ShortcutKey.fromItemInfo(info);
DeepShortcutManager sm = DeepShortcutManager.getInstance(launcher);
List<ShortcutInfo> si = sm.queryForFullDetails(
key.componentName.getPackageName(), Arrays.asList(key.getId()), key.user);
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
.buildRequest(launcher)
.query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {
outObj[0] = si.get(0);
return sm.getShortcutIconDrawable(si.get(0),
return ShortcutCachingLogic.getIcon(launcher, si.get(0),
appState.getInvariantDeviceProfile().fillResIconDpi);
}
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {

View File

@ -15,13 +15,14 @@
*/
package com.android.launcher3.allapps;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import android.content.Context;
import android.content.pm.PackageManager;
import com.android.launcher3.AppInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LabelComparator;
@ -398,7 +399,7 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
private boolean shouldShowWorkFooter() {
return mIsWork && Utilities.ATLEAST_P &&
(DeepShortcutManager.getInstance(mLauncher).hasHostPermission()
(hasShortcutsPermission(mLauncher)
|| mLauncher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
== PackageManager.PERMISSION_GRANTED);
}

View File

@ -35,7 +35,6 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.Themes;
import java.util.function.Supplier;
@ -133,8 +132,8 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable {
public BitmapInfo createShortcutIconLegacy(ShortcutInfo shortcutInfo, boolean badged,
@Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
mContext, shortcutInfo, mFillResIconDpi);
IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
final Bitmap unbadgedBitmap;
if (unbadgedDrawable != null) {

View File

@ -16,19 +16,22 @@
package com.android.launcher3.icons;
import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Themes;
@ -37,6 +40,8 @@ import com.android.launcher3.util.Themes;
*/
public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
private static final String TAG = "ShortcutCachingLogic";
@Override
public ComponentName getComponent(ShortcutInfo info) {
return ShortcutKey.fromInfo(info).componentName;
@ -56,8 +61,8 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
@Override
public BitmapInfo loadIcon(Context context, ShortcutInfo info) {
try (LauncherIcons li = LauncherIcons.obtain(context)) {
Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
.getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi);
Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
context, info, LauncherAppState.getIDP(context).fillResIconDpi);
if (unbadgedDrawable == null) return BitmapInfo.LOW_RES_INFO;
return new BitmapInfo(li.createScaledBitmapWithoutShadow(
unbadgedDrawable, 0), Themes.getColorAccent(context));
@ -76,4 +81,21 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
public boolean addToMemCache() {
return false;
}
/**
* Similar to {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)} with additional
* Launcher specific checks
*/
public static Drawable getIcon(Context context, ShortcutInfo shortcutInfo, int density) {
if (GO_DISABLE_WIDGETS) {
return null;
}
try {
return context.getSystemService(LauncherApps.class)
.getShortcutIconDrawable(shortcutInfo, density);
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "Failed to get shortcut icon", e);
return null;
}
}
}

View File

@ -15,7 +15,11 @@
*/
package com.android.launcher3.model;
import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import android.text.TextUtils;
@ -29,15 +33,15 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PromiseAppInfo;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.DumpTargetWrapper;
import com.android.launcher3.model.nano.LauncherDumpProto;
import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType;
import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@ -59,6 +63,8 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
* All the data stored in-memory and managed by the LauncherModel
@ -287,7 +293,7 @@ public class BgDataModel {
if ((count == null || --count.value == 0)
&& !InstallShortcutReceiver.getPendingShortcuts(context)
.contains(pinnedShortcut)) {
DeepShortcutManager.getInstance(context).unpinShortcut(pinnedShortcut);
unpinShortcut(context, pinnedShortcut);
}
// Fall through.
}
@ -324,7 +330,7 @@ public class BgDataModel {
// Since this is a new item, pin the shortcut in the system server.
if (newItem && count.value == 1) {
DeepShortcutManager.getInstance(context).pinShortcut(pinnedShortcut);
updatePinnedShortcuts(context, pinnedShortcut, List::add);
}
// Fall through
}
@ -354,6 +360,36 @@ public class BgDataModel {
}
}
/**
* Removes the given shortcut from the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void unpinShortcut(Context context, ShortcutKey key) {
updatePinnedShortcuts(context, key, List::remove);
}
private void updatePinnedShortcuts(Context context, ShortcutKey key,
BiConsumer<List<String>, String> idOp) {
if (GO_DISABLE_WIDGETS) {
return;
}
String packageName = key.componentName.getPackageName();
String id = key.getId();
UserHandle user = key.user;
List<String> pinnedIds = new ShortcutRequest(context, user)
.forPackage(packageName)
.query(PINNED)
.stream()
.map(ShortcutInfo::getId)
.collect(Collectors.toCollection(ArrayList::new));
idOp.accept(pinnedIds, id);
try {
context.getSystemService(LauncherApps.class).pinShortcuts(packageName, pinnedIds, user);
} catch (SecurityException | IllegalStateException e) {
Log.w(TAG, "Failed to pin shortcut", e);
}
}
/**
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.

View File

@ -21,6 +21,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
import android.appwidget.AppWidgetProviderInfo;
@ -72,8 +73,9 @@ import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.LooperIdleLock;
@ -114,7 +116,6 @@ public class LoaderTask implements Runnable {
private final UserManager mUserManager;
private final UserCache mUserCache;
private final DeepShortcutManager mShortcutManager;
private final InstallSessionHelper mSessionHelper;
private final IconCache mIconCache;
@ -130,7 +131,6 @@ public class LoaderTask implements Runnable {
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
mUserCache = UserCache.INSTANCE.get(mApp.getContext());
mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
}
@ -349,8 +349,8 @@ public class LoaderTask implements Runnable {
// We can only query for shortcuts when the user is unlocked.
if (userUnlocked) {
DeepShortcutManager.QueryResult pinnedShortcuts =
mShortcutManager.queryForPinnedShortcuts(null, user);
QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
.query(ShortcutRequest.PINNED);
if (pinnedShortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : pinnedShortcuts) {
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
@ -786,7 +786,7 @@ public class LoaderTask implements Runnable {
if ((numTimesPinned == null || numTimesPinned.value == 0)
&& !pendingShortcuts.contains(key)) {
// Shortcut is pinned but doesn't exist on the workspace; unpin it.
mShortcutManager.unpinShortcut(key);
mBgDataModel.unpinShortcut(context, key);
}
}
@ -884,12 +884,12 @@ public class LoaderTask implements Runnable {
private List<ShortcutInfo> loadDeepShortcuts() {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
mBgDataModel.deepShortcutMap.clear();
mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission();
mBgDataModel.hasShortcutHostPermission = hasShortcutsPermission(mApp.getContext());
if (mBgDataModel.hasShortcutHostPermission) {
for (UserHandle user : mUserCache.getUserProfiles()) {
if (mUserManager.isUserUnlocked(user)) {
List<ShortcutInfo> shortcuts =
mShortcutManager.queryForAllShortcuts(user);
List<ShortcutInfo> shortcuts = new ShortcutRequest(mApp.getContext(), user)
.query(ShortcutRequest.ALL);
allShortcuts.addAll(shortcuts);
mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
}

View File

@ -41,7 +41,7 @@ import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntSparseArrayMap;
@ -208,10 +208,11 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
if (si.isPromise() && isNewApkAvailable) {
boolean isTargetValid = true;
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
List<ShortcutInfo> shortcut = DeepShortcutManager
.getInstance(context).queryForPinnedShortcuts(
cn.getPackageName(),
Arrays.asList(si.getDeepShortcutId()), mUser);
List<ShortcutInfo> shortcut =
new ShortcutRequest(context, mUser)
.forPackage(cn.getPackageName(),
si.getDeepShortcutId())
.query(ShortcutRequest.PINNED);
if (shortcut.isEmpty()) {
isTargetValid = false;
} else {

View File

@ -24,8 +24,8 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
@ -54,8 +54,6 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
final Context context = app.getContext();
DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
// Find WorkspaceItemInfo's that have changed on the workspace.
HashSet<ShortcutKey> removedKeys = new HashSet<>();
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
@ -74,8 +72,9 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
if (!keyToShortcutInfo.isEmpty()) {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
List<ShortcutInfo> shortcuts = deepShortcutManager.queryForFullDetails(
mPackageName, new ArrayList<>(allIds), mUser);
List<ShortcutInfo> shortcuts = new ShortcutRequest(context, mUser)
.forPackage(mPackageName, new ArrayList<>(allIds))
.query(ShortcutRequest.ALL);
for (ShortcutInfo fullDetails : shortcuts) {
ShortcutKey key = ShortcutKey.fromInfo(fullDetails);
List<WorkspaceItemInfo> workspaceItemInfos = keyToShortcutInfo.remove(key);

View File

@ -27,8 +27,9 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
@ -52,12 +53,11 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
Context context = app.getContext();
boolean isUserUnlocked = context.getSystemService(UserManager.class).isUserUnlocked(mUser);
DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
if (isUserUnlocked) {
DeepShortcutManager.QueryResult shortcuts =
deepShortcutManager.queryForPinnedShortcuts(null, mUser);
QueryResult shortcuts = new ShortcutRequest(context, mUser)
.query(ShortcutRequest.PINNED);
if (shortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : shortcuts) {
pinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut);
@ -115,7 +115,8 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
if (isUserUnlocked) {
dataModel.updateDeepShortcutCounts(
null, mUser, deepShortcutManager.queryForAllShortcuts(mUser));
null, mUser,
new ShortcutRequest(context, mUser).query(ShortcutRequest.ALL));
}
bindDeepShortcuts(dataModel);
}

View File

@ -31,8 +31,8 @@ import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@ -144,8 +144,9 @@ public class PopupPopulator {
uiHandler.post(() -> container.applyNotificationInfos(infos));
}
List<ShortcutInfo> shortcuts = DeepShortcutManager.getInstance(launcher)
.queryForShortcutsContainer(activity, user);
List<ShortcutInfo> shortcuts = new ShortcutRequest(launcher, user)
.withContainer(activity)
.query(ShortcutRequest.PUBLISHED);
String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null
: notificationKeys.get(0).shortcutId;
shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe);

View File

@ -1,6 +1,7 @@
package com.android.launcher3.shortcuts;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
@ -29,6 +30,14 @@ public class ShortcutKey extends ComponentKey {
return componentName.getClassName();
}
/**
* Creates a {@link ShortcutRequest} for this key
*/
public ShortcutRequest buildRequest(Context context) {
return new ShortcutRequest(context, user)
.forPackage(componentName.getPackageName(), getId());
}
public static ShortcutKey fromInfo(ShortcutInfo shortcutInfo) {
return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
shortcutInfo.getId());

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2020 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.shortcuts;
import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Utility class to streamline Shortcut query
*/
public class ShortcutRequest {
private static final String TAG = "ShortcutRequest";
public static final int ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
public static final int PUBLISHED = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_MANIFEST;
public static final int PINNED = ShortcutQuery.FLAG_MATCH_PINNED;
private final ShortcutQuery mQuery = GO_DISABLE_WIDGETS ? null : new ShortcutQuery();
private final Context mContext;
private final UserHandle mUserHandle;
boolean mFailed = false;
public ShortcutRequest(Context context, UserHandle userHandle) {
mContext = context;
mUserHandle = userHandle;
}
public ShortcutRequest forPackage(String packageName, String... shortcutIds) {
return forPackage(packageName, Arrays.asList(shortcutIds));
}
public ShortcutRequest forPackage(String packageName, @Nullable List<String> shortcutIds) {
if (!GO_DISABLE_WIDGETS && packageName != null) {
mQuery.setPackage(packageName);
mQuery.setShortcutIds(shortcutIds);
}
return this;
}
public ShortcutRequest withContainer(@Nullable ComponentName activity) {
if (!GO_DISABLE_WIDGETS) {
if (activity == null) {
mFailed = true;
} else {
mQuery.setActivity(activity);
}
}
return this;
}
public QueryResult query(int flags) {
if (GO_DISABLE_WIDGETS || mFailed) {
return QueryResult.DEFAULT;
}
mQuery.setQueryFlags(flags);
try {
return new QueryResult(mContext.getSystemService(LauncherApps.class)
.getShortcuts(mQuery, mUserHandle));
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "Failed to query for shortcuts", e);
return QueryResult.DEFAULT;
}
}
public static class QueryResult extends ArrayList<ShortcutInfo> {
static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_WIDGETS);
private final boolean mWasSuccess;
QueryResult(List<ShortcutInfo> result) {
super(result == null ? Collections.emptyList() : result);
mWasSuccess = true;
}
QueryResult(boolean wasSuccess) {
mWasSuccess = wasSuccess;
}
public boolean wasSuccess() {
return mWasSuccess;
}
}
}

View File

@ -332,4 +332,17 @@ public class PackageManagerHelper {
}
return false;
}
/**
* Returns true if Launcher has the permission to access shortcuts.
* @see LauncherApps#hasShortcutHostPermission()
*/
public static boolean hasShortcutsPermission(Context context) {
try {
return context.getSystemService(LauncherApps.class).hasShortcutHostPermission();
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "Failed to make shortcut manager call", e);
}
return false;
}
}

View File

@ -1,213 +0,0 @@
/*
* Copyright (C) 2016 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.shortcuts;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
*/
public class DeepShortcutManager {
private static final String TAG = "DeepShortcutManager";
private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
| ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
private static DeepShortcutManager sInstance;
public static DeepShortcutManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new DeepShortcutManager(context.getApplicationContext());
}
return sInstance;
}
private final LauncherApps mLauncherApps;
private DeepShortcutManager(Context context) {
mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
}
/**
* Queries for the shortcuts with the package name and provided ids.
*
* This method is intended to get the full details for shortcuts when they are added or updated,
* because we only get "key" fields in onShortcutsChanged().
*/
public QueryResult queryForFullDetails(String packageName,
List<String> shortcutIds, UserHandle user) {
return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
}
/**
* Gets all the manifest and dynamic shortcuts associated with the given package and user,
* to be displayed in the shortcuts container on long press.
*/
public QueryResult queryForShortcutsContainer(@Nullable ComponentName activity,
UserHandle user) {
if (activity == null) return QueryResult.FAILURE;
return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
activity.getPackageName(), activity, null, user);
}
/**
* Removes the given shortcut from the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void unpinShortcut(final ShortcutKey key) {
String packageName = key.componentName.getPackageName();
String id = key.getId();
UserHandle user = key.user;
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
pinnedIds.remove(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to unpin shortcut", e);
}
}
/**
* Adds the given shortcut to the current list of pinned shortcuts.
* (Runs on background thread)
*/
public void pinShortcut(final ShortcutKey key) {
String packageName = key.componentName.getPackageName();
String id = key.getId();
UserHandle user = key.user;
List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
pinnedIds.add(id);
try {
mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
} catch (SecurityException|IllegalStateException e) {
Log.w(TAG, "Failed to pin shortcut", e);
}
}
public void startShortcut(String packageName, String id, Rect sourceBounds,
Bundle startActivityOptions, UserHandle user) {
try {
mLauncherApps.startShortcut(packageName, id, sourceBounds,
startActivityOptions, user);
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to start shortcut", e);
}
}
public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
try {
return mLauncherApps.getShortcutIconDrawable(shortcutInfo, density);
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to get shortcut icon", e);
return null;
}
}
/**
* Returns the id's of pinned shortcuts associated with the given package and user.
*
* If packageName is null, returns all pinned shortcuts regardless of package.
*/
public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
return queryForPinnedShortcuts(packageName, null, user);
}
public QueryResult queryForPinnedShortcuts(String packageName, List<String> shortcutIds,
UserHandle user) {
return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, shortcutIds, user);
}
public QueryResult queryForAllShortcuts(UserHandle user) {
return query(FLAG_GET_ALL, null, null, null, user);
}
private static List<String> extractIds(List<ShortcutInfo> shortcuts) {
List<String> shortcutIds = new ArrayList<>(shortcuts.size());
for (ShortcutInfo shortcut : shortcuts) {
shortcutIds.add(shortcut.getId());
}
return shortcutIds;
}
/**
* Query the system server for all the shortcuts matching the given parameters.
* If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
*
* TODO: Use the cache to optimize this so we don't make an RPC every time.
*/
private QueryResult query(int flags, String packageName, ComponentName activity,
List<String> shortcutIds, UserHandle user) {
ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(flags);
if (packageName != null) {
q.setPackage(packageName);
q.setActivity(activity);
q.setShortcutIds(shortcutIds);
}
try {
return new QueryResult(mLauncherApps.getShortcuts(q, user));
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to query for shortcuts", e);
return QueryResult.FAILURE;
}
}
public boolean hasHostPermission() {
try {
return mLauncherApps.hasShortcutHostPermission();
} catch (SecurityException|IllegalStateException e) {
Log.e(TAG, "Failed to make shortcut manager call", e);
}
return false;
}
public static class QueryResult extends ArrayList<ShortcutInfo> {
static QueryResult FAILURE = new QueryResult();
private final boolean mWasSuccess;
QueryResult(List<ShortcutInfo> result) {
super(result == null ? Collections.emptyList() : result);
mWasSuccess = true;
}
QueryResult() {
mWasSuccess = false;
}
public boolean wasSuccess() {
return mWasSuccess;
}
}
}