diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java deleted file mode 100644 index 42b1194292..0000000000 --- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ /dev/null @@ -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 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 shortcutIds, UserHandle user) { - return mFailure; - } - - public QueryResult queryForAllShortcuts(UserHandle user) { - return mFailure; - } - - public boolean hasHostPermission() { - return false; - } - - - public static class QueryResult extends ArrayList { - - public boolean wasSuccess() { - return true; - } - } -} diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java index 38bb180ecb..76972aff41 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java @@ -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 details = mgr.queryForFullDetails( - shortcutKey.componentName.getPackageName(), - Collections.singletonList(shortcutKey.getId()), - shortcutKey.user); + List details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL); if (!details.isEmpty()) { WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext); try (LauncherIcons li = LauncherIcons.obtain(mContext)) { diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index f319ae1812..ea63fa7ada 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -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 fromContext(Context context) { if (context instanceof BaseActivity) { return (T) context; diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java index 893f64a1ba..066bcee3ad 100644 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ b/src/com/android/launcher3/BaseDraggingActivity.java @@ -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 { diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index df0302797d..3eb02b3dae 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -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 si = sm.queryForFullDetails( - decoder.launcherIntent.getPackage(), - Arrays.asList(decoder.launcherIntent.getStringExtra( - ShortcutKey.EXTRA_SHORTCUT_ID)), - decoder.user); + List si = ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user) + .buildRequest(context) + .query(ShortcutRequest.ALL); if (si.isEmpty()) { return null; } else { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 67fd7db6f1..0bdf8fdd90 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -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 pinnedShortcuts = DeepShortcutManager.getInstance(context) - .queryForPinnedShortcuts(packageName, user); + List pinnedShortcuts = new ShortcutRequest(context, user) + .forPackage(packageName).query(ShortcutRequest.PINNED); if (!pinnedShortcuts.isEmpty()) { enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, pinnedShortcuts, user, false)); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 2bec0ba3b7..af9a1b4e35 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -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 si = sm.queryForFullDetails( - key.componentName.getPackageName(), Arrays.asList(key.getId()), key.user); + List 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) { diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 0c4be62879..10e282156c 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -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); } diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index 4d3599e4d1..e67d2445b7 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -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 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) { diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java index 5c214704a3..b856dd1318 100644 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -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 { + 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 { @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 { 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; + } + } } diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 0e20270504..88f2a09a80 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -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, String> idOp) { + if (GO_DISABLE_WIDGETS) { + return; + } + String packageName = key.componentName.getPackageName(); + String id = key.getId(); + UserHandle user = key.user; + List 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. diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 605bb7598a..571d41a54b 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -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 loadDeepShortcuts() { List 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 shortcuts = - mShortcutManager.queryForAllShortcuts(user); + List shortcuts = new ShortcutRequest(mApp.getContext(), user) + .query(ShortcutRequest.ALL); allShortcuts.addAll(shortcuts); mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts); } diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 3361ff08e9..48c56e970e 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -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 shortcut = DeepShortcutManager - .getInstance(context).queryForPinnedShortcuts( - cn.getPackageName(), - Arrays.asList(si.getDeepShortcutId()), mUser); + List shortcut = + new ShortcutRequest(context, mUser) + .forPackage(cn.getPackageName(), + si.getDeepShortcutId()) + .query(ShortcutRequest.PINNED); if (shortcut.isEmpty()) { isTargetValid = false; } else { diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index 05225d4fa0..b0e7a69f81 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -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 removedKeys = new HashSet<>(); MultiHashMap keyToShortcutInfo = new MultiHashMap<>(); @@ -74,8 +72,9 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask { final ArrayList updatedWorkspaceItemInfos = new ArrayList<>(); if (!keyToShortcutInfo.isEmpty()) { // Update the workspace to reflect the changes to updated shortcuts residing on it. - List shortcuts = deepShortcutManager.queryForFullDetails( - mPackageName, new ArrayList<>(allIds), mUser); + List shortcuts = new ShortcutRequest(context, mUser) + .forPackage(mPackageName, new ArrayList<>(allIds)) + .query(ShortcutRequest.ALL); for (ShortcutInfo fullDetails : shortcuts) { ShortcutKey key = ShortcutKey.fromInfo(fullDetails); List workspaceItemInfos = keyToShortcutInfo.remove(key); diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index 694ae1abcf..d527423e42 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -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 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); } diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java index 80c6683d31..947f49d0c6 100644 --- a/src/com/android/launcher3/popup/PopupPopulator.java +++ b/src/com/android/launcher3/popup/PopupPopulator.java @@ -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 shortcuts = DeepShortcutManager.getInstance(launcher) - .queryForShortcutsContainer(activity, user); + List shortcuts = new ShortcutRequest(launcher, user) + .withContainer(activity) + .query(ShortcutRequest.PUBLISHED); String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null : notificationKeys.get(0).shortcutId; shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe); diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java index 70665ca28c..fa1a85f98c 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutKey.java +++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java @@ -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()); diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java new file mode 100644 index 0000000000..e6203b45a3 --- /dev/null +++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java @@ -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 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 { + + static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_WIDGETS); + + private final boolean mWasSuccess; + + QueryResult(List result) { + super(result == null ? Collections.emptyList() : result); + mWasSuccess = true; + } + + QueryResult(boolean wasSuccess) { + mWasSuccess = wasSuccess; + } + + + public boolean wasSuccess() { + return mWasSuccess; + } + } +} diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 2d56ce7b42..8b2ee36cb9 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -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; + } } diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java deleted file mode 100644 index 57f416495f..0000000000 --- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ /dev/null @@ -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 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 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 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 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 extractIds(List shortcuts) { - List 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 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 { - - static QueryResult FAILURE = new QueryResult(); - - private final boolean mWasSuccess; - - QueryResult(List result) { - super(result == null ? Collections.emptyList() : result); - mWasSuccess = true; - } - - QueryResult() { - mWasSuccess = false; - } - - - public boolean wasSuccess() { - return mWasSuccess; - } - } -}