diff options
| author | 2023-03-05 07:20:07 +0000 | |
|---|---|---|
| committer | 2023-03-05 07:20:07 +0000 | |
| commit | 1d4b9580789462e3172cec6155718101d797483c (patch) | |
| tree | e740172c2bbbabd21255abaddce76ebc9990a7d8 | |
| parent | b4f4ac8e4540a4a5d254dda2873968bbbfe2b8be (diff) | |
| parent | 15ae228ddb1d099ce8315c7a3a447af6db3a64b1 (diff) | |
Merge "Limit the number of shortcuts per app that can be retained by system" into rvc-dev am: 15ae228ddb
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21564438
Change-Id: I9e61356ca633c6800098a5511b7330db7a4503ae
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
| -rw-r--r-- | services/core/java/com/android/server/pm/ShortcutPackage.java | 79 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/ShortcutService.java | 25 |
2 files changed, 100 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index f2bfb2aa1405..b2d78ec7d95d 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -68,6 +68,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Package information used by {@link ShortcutService}. @@ -350,6 +351,7 @@ class ShortcutPackage extends ShortcutPackageItem { @NonNull List<ShortcutInfo> changedShortcuts) { Preconditions.checkArgument(newShortcut.isEnabled(), "pushDynamicShortcuts() cannot publish disabled shortcuts"); + ensureShortcutCountBeforePush(); newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); @@ -357,7 +359,7 @@ class ShortcutPackage extends ShortcutPackageItem { final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId()); boolean deleted = false; - if (oldShortcut == null) { + if (oldShortcut == null || !oldShortcut.isDynamic()) { final ShortcutService service = mShortcutUser.mService; final int maxShortcuts = service.getMaxActivityShortcuts(); @@ -367,7 +369,6 @@ class ShortcutPackage extends ShortcutPackageItem { if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) { // Max has reached. Delete the shortcut with lowest rank. - // Sort by isManifestShortcut() and getRank(). Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator); @@ -382,7 +383,8 @@ class ShortcutPackage extends ShortcutPackageItem { changedShortcuts.add(shortcut); deleted = deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true) != null; } - } else { + } + if (oldShortcut != null) { // It's an update case. // Make sure the target is updatable. (i.e. should be mutable.) oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); @@ -396,6 +398,30 @@ class ShortcutPackage extends ShortcutPackageItem { return deleted; } + private void ensureShortcutCountBeforePush() { + final ShortcutService service = mShortcutUser.mService; + // Ensure the total number of shortcuts doesn't exceed the hard limit per app. + final int maxShortcutPerApp = service.getMaxAppShortcuts(); + final List<ShortcutInfo> appShortcuts = mShortcuts.values().stream().filter(si -> + !si.isPinned()).collect(Collectors.toList()); + if (appShortcuts.size() >= maxShortcutPerApp) { + // Max has reached. Removes shortcuts until they fall within the hard cap. + // Sort by isManifestShortcut(), isDynamic() and getLastChangedTimestamp(). + Collections.sort(appShortcuts, mShortcutTypeRankAndTimeComparator); + + while (appShortcuts.size() >= maxShortcutPerApp) { + final ShortcutInfo shortcut = appShortcuts.remove(appShortcuts.size() - 1); + if (shortcut.isDeclaredInManifest()) { + // All shortcuts are manifest shortcuts and cannot be removed. + throw new IllegalArgumentException(getPackageName() + " has published " + + appShortcuts.size() + " manifest shortcuts across different" + + " activities."); + } + forceDeleteShortcutInner(shortcut.getId()); + } + } + } + /** * Remove all shortcuts that aren't pinned, cached nor dynamic. * @@ -1223,6 +1249,53 @@ class ShortcutPackage extends ShortcutPackageItem { }; /** + * To sort by isManifestShortcut(), isDynamic(), getRank() and + * getLastChangedTimestamp(). i.e. manifest shortcuts come before non-manifest shortcuts, + * dynamic shortcuts come before floating shortcuts, then sort by last changed timestamp. + * + * This is used to decide which shortcuts to remove when the total number of shortcuts retained + * for the app exceeds the limit defined in {@link ShortcutService#getMaxAppShortcuts()}. + * + * (Note the number of manifest shortcuts is always <= the max number, because if there are + * more, ShortcutParser would ignore the rest.) + */ + final Comparator<ShortcutInfo> mShortcutTypeRankAndTimeComparator = (ShortcutInfo a, + ShortcutInfo b) -> { + if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) { + return -1; + } + if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) { + return 1; + } + if (a.isDynamic() && b.isDynamic()) { + return Integer.compare(a.getRank(), b.getRank()); + } + if (a.isDynamic()) { + return -1; + } + if (b.isDynamic()) { + return 1; + } + if (a.isCached() && b.isCached()) { + // if both shortcuts are cached, prioritize shortcuts cached by bubbles. + if (a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES) + && !b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) { + return -1; + } else if (!a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES) + && b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) { + return 1; + } + } + if (a.isCached()) { + return -1; + } + if (b.isCached()) { + return 1; + } + return Long.compare(b.getLastChangedTimestamp(), a.getLastChangedTimestamp()); + }; + + /** * Build a list of shortcuts for each target activity and return as a map. The result won't * contain "floating" shortcuts because they don't belong on any activities. */ diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 0c42ff6be520..c3375d9346e5 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -172,6 +172,9 @@ public class ShortcutService extends IShortcutService.Stub { static final int DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY = 15; @VisibleForTesting + static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 100; + + @VisibleForTesting static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96; @VisibleForTesting @@ -246,6 +249,11 @@ public class ShortcutService extends IShortcutService.Stub { String KEY_MAX_SHORTCUTS = "max_shortcuts"; /** + * Key name for the max shortcuts can be retained in system ram per app. (int) + */ + String KEY_MAX_SHORTCUTS_PER_APP = "max_shortcuts_per_app"; + + /** * Key name for icon compression quality, 0-100. */ String KEY_ICON_QUALITY = "icon_quality"; @@ -302,11 +310,16 @@ public class ShortcutService extends IShortcutService.Stub { new SparseArray<>(); /** - * Max number of dynamic + manifest shortcuts that each application can have at a time. + * Max number of dynamic + manifest shortcuts that each activity can have at a time. */ private int mMaxShortcuts; /** + * Max number of shortcuts that can exists in system ram for each application. + */ + private int mMaxShortcutsPerApp; + + /** * Max number of updating API calls that each application can make during the interval. */ int mMaxUpdatesPerInterval; @@ -732,6 +745,9 @@ public class ShortcutService extends IShortcutService.Stub { mMaxShortcuts = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY)); + mMaxShortcutsPerApp = Math.max(0, (int) parser.getLong( + ConfigConstants.KEY_MAX_SHORTCUTS_PER_APP, DEFAULT_MAX_SHORTCUTS_PER_APP)); + final int iconDimensionDp = Math.max(1, injectIsLowRamDevice() ? (int) parser.getLong( ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM, @@ -1662,6 +1678,13 @@ public class ShortcutService extends IShortcutService.Stub { } /** + * Return the max number of shortcuts can be retaiend in system ram for each application. + */ + int getMaxAppShortcuts() { + return mMaxShortcutsPerApp; + } + + /** * - Sends a notification to LauncherApps * - Write to file */ |