diff options
4 files changed, 532 insertions, 255 deletions
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 19c56f82d7bf..cea2656c4a19 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -19,18 +19,33 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.Person; +import android.app.appsearch.AppSearchManager; +import android.app.appsearch.AppSearchResult; import android.app.appsearch.AppSearchSession; +import android.app.appsearch.GenericDocument; +import android.app.appsearch.GetByUriRequest; import android.app.appsearch.PackageIdentifier; +import android.app.appsearch.PutDocumentsRequest; +import android.app.appsearch.RemoveByUriRequest; +import android.app.appsearch.ReportUsageRequest; +import android.app.appsearch.SearchResult; +import android.app.appsearch.SearchResults; +import android.app.appsearch.SearchSpec; +import android.app.appsearch.SetSchemaRequest; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; import android.content.LocusId; +import android.content.pm.AppSearchPerson; +import android.content.pm.AppSearchShortcutInfo; import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.content.res.Resources; import android.graphics.drawable.Icon; +import android.os.Binder; import android.os.PersistableBundle; +import android.os.StrictMode; import android.text.format.Formatter; import android.util.ArrayMap; import android.util.ArraySet; @@ -43,8 +58,10 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.infra.AndroidFuture; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; +import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.pm.ShortcutService.DumpFilter; @@ -64,13 +81,17 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; /** @@ -137,9 +158,9 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String KEY_BITMAP_BYTES = "bitmapBytes"; /** - * All the shortcuts from the package, keyed on IDs. + * An temp in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs. */ - private final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>(); + final ArraySet<ShortcutInfo> mShortcuts = new ArraySet<>(); /** * All the share targets from the package @@ -199,7 +220,9 @@ class ShortcutPackage extends ShortcutPackageItem { } public int getShortcutCount() { - return mShortcuts.size(); + final int[] count = new int[1]; + forEachShortcut(si -> count[0]++); + return count[0]; } @Override @@ -213,17 +236,20 @@ class ShortcutPackage extends ShortcutPackageItem { // - Unshadow all shortcuts. // - Set disabled reason. // - Disable if needed. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - ShortcutInfo si = mShortcuts.valueAt(i); - mutateShortcut(si.getId(), si, shortcut -> { - shortcut.clearFlags(ShortcutInfo.FLAG_SHADOW); - - shortcut.setDisabledReason(restoreBlockReason); - if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { - shortcut.addFlags(ShortcutInfo.FLAG_DISABLED); - } - }); - } + forEachShortcutMutateIf(si -> { + if (!si.hasFlags(ShortcutInfo.FLAG_SHADOW) + && si.getDisabledReason() == restoreBlockReason + && restoreBlockReason == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + return false; + } + si.clearFlags(ShortcutInfo.FLAG_SHADOW); + + si.setDisabledReason(restoreBlockReason); + if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + si.addFlags(ShortcutInfo.FLAG_DISABLED); + } + return true; + }); // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. refreshPinnedFlags(); @@ -234,7 +260,7 @@ class ShortcutPackage extends ShortcutPackageItem { */ @Nullable public ShortcutInfo findShortcutById(String id) { - return mShortcuts.get(id); + return getShortcutById(id); } public boolean isShortcutExistsAndInvisibleToPublisher(String id) { @@ -300,8 +326,9 @@ class ShortcutPackage extends ShortcutPackageItem { * Delete a shortcut by ID. This will *always* remove it even if it's immutable or invisible. */ private ShortcutInfo forceDeleteShortcutInner(@NonNull String id) { - final ShortcutInfo shortcut = mShortcuts.remove(id); + final ShortcutInfo shortcut = getShortcutById(id); if (shortcut != null) { + removeShortcut(id); mShortcutUser.mService.removeIconLocked(shortcut); shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL); @@ -318,10 +345,10 @@ class ShortcutPackage extends ShortcutPackageItem { forceDeleteShortcutInner(newShortcut.getId()); - // Extract Icon and update the icon res ID and the bitmap path. s.saveIconAndFixUpShortcutLocked(newShortcut); s.fixUpShortcutResourceNamesAndValues(newShortcut); - mShortcuts.put(newShortcut.getId(), newShortcut); + + saveShortcut(newShortcut); } /** @@ -410,6 +437,16 @@ class ShortcutPackage extends ShortcutPackageItem { } forceReplaceShortcutInner(newShortcut); + // TODO: Report usage can be filed async + runInAppSearch(session -> { + final AndroidFuture<Boolean> future = new AndroidFuture<>(); + session.reportUsage( + new ReportUsageRequest.Builder(getPackageName()) + .setUri(newShortcut.getId()).build(), + mShortcutUser.mExecutor, result -> future.complete(result.isSuccess())); + return future; + }); + return deleted; } @@ -419,19 +456,12 @@ class ShortcutPackage extends ShortcutPackageItem { * @return List of removed shortcuts. */ private List<ShortcutInfo> removeOrphans() { - List<ShortcutInfo> removeList = null; - - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); - - if (si.isAlive()) continue; - - if (removeList == null) { - removeList = new ArrayList<>(); - } + final List<ShortcutInfo> removeList = new ArrayList<>(1); + forEachShortcut(si -> { + if (si.isAlive()) return; removeList.add(si); - } - if (removeList != null) { + }); + if (!removeList.isEmpty()) { for (int i = removeList.size() - 1; i >= 0; i--) { forceDeleteShortcutInner(removeList.get(i).getId()); } @@ -448,20 +478,19 @@ class ShortcutPackage extends ShortcutPackageItem { public List<ShortcutInfo> deleteAllDynamicShortcuts(boolean ignoreInvisible) { final long now = mShortcutUser.mService.injectCurrentTimeMillis(); - boolean changed = false; - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + final boolean[] changed = new boolean[1]; + forEachShortcutMutateIf(si -> { if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) { - changed = true; + changed[0] = true; - mutateShortcut(si.getId(), si, shortcut -> { - shortcut.setTimestamp(now); - shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC); - shortcut.setRank(0); // It may still be pinned, so clear the rank. - }); + si.setTimestamp(now); + si.clearFlags(ShortcutInfo.FLAG_DYNAMIC); + si.setRank(0); // It may still be pinned, so clear the rank. + return true; } - } - if (changed) { + return false; + }); + if (changed[0]) { return removeOrphans(); } return null; @@ -606,11 +635,6 @@ class ShortcutPackage extends ShortcutPackageItem { * <p>Then remove all shortcuts that are not dynamic and no longer pinned either. */ public void refreshPinnedFlags() { - final List<ShortcutInfo> shortcuts = new ArrayList<>(mShortcuts.values()); - final Map<String, ShortcutInfo> shortcutMap = new ArrayMap<>(shortcuts.size()); - for (ShortcutInfo si : shortcuts) { - shortcutMap.put(si.getId(), si); - } final Set<String> pinnedShortcuts = new ArraySet<>(); // First, for the pinned set for each launcher, keep track of their id one by one. @@ -620,31 +644,20 @@ class ShortcutPackage extends ShortcutPackageItem { if (pinned == null || pinned.size() == 0) { return; } - for (int i = pinned.size() - 1; i >= 0; i--) { - final String id = pinned.valueAt(i); - final ShortcutInfo si = shortcutMap.get(id); - if (si == null) { - // This happens if a launcher pinned shortcuts from this package, then backup& - // restored, but this package doesn't allow backing up. - // In that case the launcher ends up having a dangling pinned shortcuts. - // That's fine, when the launcher is restored, we'll fix it. - continue; - } - pinnedShortcuts.add(si.getId()); - } + pinnedShortcuts.addAll(pinned); }); // Then, update the pinned state if necessary - for (int i = shortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = shortcuts.get(i); + forEachShortcutMutateIf(si -> { if (pinnedShortcuts.contains(si.getId()) && !si.isPinned()) { - mutateShortcut(si.getId(), si, - shortcut -> shortcut.addFlags(ShortcutInfo.FLAG_PINNED)); + si.addFlags(ShortcutInfo.FLAG_PINNED); + return true; } if (!pinnedShortcuts.contains(si.getId()) && si.isPinned()) { - mutateShortcut(si.getId(), si, shortcut -> - shortcut.clearFlags(ShortcutInfo.FLAG_PINNED)); + si.clearFlags(ShortcutInfo.FLAG_PINNED); + return true; } - } + return false; + }); // Lastly, remove the ones that are no longer pinned, cached nor dynamic. removeOrphans(); @@ -759,9 +772,7 @@ class ShortcutPackage extends ShortcutPackageItem { final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId) .getPinnedShortcutIds(getPackageName(), getPackageUserId()); - - for (int i = 0; i < mShortcuts.size(); i++) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcut(si -> { // Need to adjust PINNED flag depending on the caller. // Basically if the caller is a launcher (callingLauncher != null) and the launcher // isn't pinning it, then we need to clear PINNED for this caller. @@ -771,7 +782,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (!getPinnedByAnyLauncher) { if (si.isFloating() && !si.isCached()) { if (!isPinnedByCaller) { - continue; + return; } } } @@ -791,7 +802,7 @@ class ShortcutPackage extends ShortcutPackageItem { } result.add(clone); } - } + }); } public void resetThrottling() { @@ -861,7 +872,7 @@ class ShortcutPackage extends ShortcutPackageItem { * the app's Xml resource. */ int getSharingShortcutCount() { - if (mShortcuts.isEmpty() || mShareTargets.isEmpty()) { + if (getShortcutCount() == 0 || mShareTargets.isEmpty()) { return 0; } @@ -899,14 +910,12 @@ class ShortcutPackage extends ShortcutPackageItem { * Return the filenames (excluding path names) of icon bitmap files from this package. */ public ArraySet<String> getUsedBitmapFiles() { - final ArraySet<String> usedFiles = new ArraySet<>(mShortcuts.size()); - - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + final ArraySet<String> usedFiles = new ArraySet<>(1); + forEachShortcut(si -> { if (si.getBitmapPath() != null) { usedFiles.add(getFileName(si.getBitmapPath())); } - } + }); return usedFiles; } @@ -923,30 +932,29 @@ class ShortcutPackage extends ShortcutPackageItem { * @return false if any of the target activities are no longer enabled. */ private boolean areAllActivitiesStillEnabled() { - if (mShortcuts.size() == 0) { - return true; - } final ShortcutService s = mShortcutUser.mService; // Normally the number of target activities is 1 or so, so no need to use a complex // structure like a set. final ArrayList<ComponentName> checked = new ArrayList<>(4); + final boolean[] reject = new boolean[1]; - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcutStopWhen(si -> { final ComponentName activity = si.getActivity(); if (checked.contains(activity)) { - continue; // Already checked. + return false; // Already checked. } checked.add(activity); if ((activity != null) && !s.injectIsActivityEnabledAndExported(activity, getOwnerUserId())) { - return false; + reject[0] = true; + return true; // Found at least 1 activity is disabled, so skip the rest. } - } - return true; + return false; + }); + return !reject[0]; } /** @@ -1029,32 +1037,32 @@ class ShortcutPackage extends ShortcutPackageItem { // See if there are any shortcuts that were prevented restoring because the app was of a // lower version, and re-enable them. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcutMutateIf(si -> { if (si.getDisabledReason() != ShortcutInfo.DISABLED_REASON_VERSION_LOWER) { - continue; + return false; } if (getPackageInfo().getBackupSourceVersionCode() > newVersionCode) { if (ShortcutService.DEBUG) { Slog.d(TAG, String.format("Shortcut %s require version %s, still not restored.", si.getId(), getPackageInfo().getBackupSourceVersionCode())); } - continue; + return false; } Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId())); - mutateShortcut(si.getId(), si, shortcut -> { - shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED); - shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); - }); - } + if (si.hasFlags(ShortcutInfo.FLAG_DISABLED) + || si.getDisabledReason() != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) { + si.clearFlags(ShortcutInfo.FLAG_DISABLED); + si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED); + return true; + } + return false; + }); // For existing shortcuts, update timestamps if they have any resources. // Also check if shortcuts' activities are still main activities. Otherwise, disable them. if (!isNewApp) { - Resources publisherRes = null; - - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + final Resources publisherRes = getPackageResources(); + forEachShortcutMutateIf(si -> { // Disable dynamic shortcuts whose target activity is gone. if (si.isDynamic()) { if (si.getActivity() == null) { @@ -1067,33 +1075,26 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageName(), si.getId())); if (disableDynamicWithId(si.getId(), /*ignoreInvisible*/ false, ShortcutInfo.DISABLED_REASON_APP_CHANGED) != null) { - continue; // Actually removed. + return false; // Actually removed. } // Still pinned, so fall-through and possibly update the resources. } } - if (si.hasAnyResources()) { - if (publisherRes == null) { - publisherRes = getPackageResources(); - if (publisherRes == null) { - break; // Resources couldn't be loaded. - } - } - - final Resources res = publisherRes; - mutateShortcut(si.getId(), si, shortcut -> { - if (!shortcut.isOriginallyFromManifest()) { - shortcut.lookupAndFillInResourceIds(res); - } + if (!si.hasAnyResources() || publisherRes == null) { + return false; + } - // If this shortcut is not from a manifest, then update all resource IDs - // from resource names. (We don't allow resource strings for - // non-manifest at the moment, but icons can still be resources.) - shortcut.setTimestamp(s.injectCurrentTimeMillis()); - }); + if (!si.isOriginallyFromManifest()) { + si.lookupAndFillInResourceIds(publisherRes); } - } + + // If this shortcut is not from a manifest, then update all resource IDs + // from resource names. (We don't allow resource strings for + // non-manifest at the moment, but icons can still be resources.) + si.setTimestamp(s.injectCurrentTimeMillis()); + return true; + }); } // (Re-)publish manifest shortcut. @@ -1119,17 +1120,12 @@ class ShortcutPackage extends ShortcutPackageItem { boolean changed = false; // Keep the previous IDs. - ArraySet<String> toDisableList = null; - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); - + final ArraySet<String> toDisableList = new ArraySet<>(1); + forEachShortcut(si -> { if (si.isManifestShortcut()) { - if (toDisableList == null) { - toDisableList = new ArraySet<>(); - } toDisableList.add(si.getId()); } - } + }); // Publish new ones. if (newManifestShortcutList != null) { @@ -1169,7 +1165,7 @@ class ShortcutPackage extends ShortcutPackageItem { // regardless. forceReplaceShortcutInner(newShortcut); // This will clean up the old one too. - if (!newDisabled && toDisableList != null) { + if (!newDisabled && !toDisableList.isEmpty()) { // Still alive, don't remove. toDisableList.remove(id); } @@ -1177,7 +1173,7 @@ class ShortcutPackage extends ShortcutPackageItem { } // Disable the previous manifest shortcuts that are no longer in the manifest. - if (toDisableList != null) { + if (!toDisableList.isEmpty()) { if (ShortcutService.DEBUG) { Slog.d(TAG, String.format( "Package %s: disabling %d stale shortcuts", getPackageName(), @@ -1266,25 +1262,21 @@ class ShortcutPackage extends ShortcutPackageItem { private ArrayMap<ComponentName, ArrayList<ShortcutInfo>> sortShortcutsToActivities() { final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> activitiesToShortcuts = new ArrayMap<>(); - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcut(si -> { if (si.isFloating()) { - continue; // Ignore floating shortcuts, which are not tied to any activities. + return; // Ignore floating shortcuts, which are not tied to any activities. } final ComponentName activity = si.getActivity(); if (activity == null) { mShortcutUser.mService.wtf("null activity detected."); - continue; + return; } - ArrayList<ShortcutInfo> list = activitiesToShortcuts.get(activity); - if (list == null) { - list = new ArrayList<>(); - activitiesToShortcuts.put(activity, list); - } + ArrayList<ShortcutInfo> list = activitiesToShortcuts.computeIfAbsent(activity, + k -> new ArrayList<>()); list.add(si); - } + }); return activitiesToShortcuts; } @@ -1320,14 +1312,13 @@ class ShortcutPackage extends ShortcutPackageItem { // (If it's for update, then don't count dynamic shortcuts, since they'll be replaced // anyway.) final ArrayMap<ComponentName, Integer> counts = new ArrayMap<>(4); - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo shortcut = mShortcuts.valueAt(i); + forEachShortcut(shortcut -> { if (shortcut.isManifestShortcut()) { incrementCountForActivity(counts, shortcut.getActivity(), 1); } else if (shortcut.isDynamic() && (operation != ShortcutService.OPERATION_SET)) { incrementCountForActivity(counts, shortcut.getActivity(), 1); } - } + }); for (int i = newList.size() - 1; i >= 0; i--) { final ShortcutInfo newShortcut = newList.get(i); @@ -1340,7 +1331,7 @@ class ShortcutPackage extends ShortcutPackageItem { continue; // Activity can be null for update. } - final ShortcutInfo original = mShortcuts.get(newShortcut.getId()); + final ShortcutInfo original = findShortcutById(newShortcut.getId()); if (original == null) { if (operation == ShortcutService.OPERATION_UPDATE) { continue; // When updating, ignore if there's no target. @@ -1379,31 +1370,17 @@ class ShortcutPackage extends ShortcutPackageItem { public void resolveResourceStrings() { final ShortcutService s = mShortcutUser.mService; - List<ShortcutInfo> changedShortcuts = null; + final Resources publisherRes = getPackageResources(); + final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1); - Resources publisherRes = null; - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); - - if (si.hasStringResources()) { - if (publisherRes == null) { - publisherRes = getPackageResources(); - if (publisherRes == null) { - break; // Resources couldn't be loaded. - } - } - - final Resources res = publisherRes; - mutateShortcut(si.getId(), si, shortcut -> { - shortcut.resolveResourceStrings(res); - shortcut.setTimestamp(s.injectCurrentTimeMillis()); - }); - - if (changedShortcuts == null) { - changedShortcuts = new ArrayList<>(1); - } + if (publisherRes != null) { + forEachShortcutMutateIf(si -> { + if (!si.hasStringResources()) return false; + si.resolveResourceStrings(publisherRes); + si.setTimestamp(s.injectCurrentTimeMillis()); changedShortcuts.add(si); - } + return true; + }); } if (!CollectionUtils.isEmpty(changedShortcuts)) { s.packageShortcutsChanged(getPackageName(), getPackageUserId(), changedShortcuts, null); @@ -1412,10 +1389,7 @@ class ShortcutPackage extends ShortcutPackageItem { /** Clears the implicit ranks for all shortcuts. */ public void clearAllImplicitRanks() { - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); - mutateShortcut(si.getId(), si, ShortcutInfo::clearImplicitRankAndRankChangedFlag); - } + forEachShortcutMutate(ShortcutInfo::clearImplicitRankAndRankChangedFlag); } /** @@ -1455,17 +1429,16 @@ class ShortcutPackage extends ShortcutPackageItem { final long now = s.injectCurrentTimeMillis(); // First, clear ranks for floating shortcuts. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcutMutateIf(si -> { if (si.isFloating()) { if (si.getRank() != 0) { - mutateShortcut(si.getId(), si, shortcut -> { - shortcut.setTimestamp(now); - shortcut.setRank(0); - }); + si.setTimestamp(now); + si.setRank(0); + return true; } } - } + return false; + }); // Then adjust ranks. Ranks are unique for each activity, so we first need to sort // shortcuts to each activity. @@ -1507,13 +1480,14 @@ class ShortcutPackage extends ShortcutPackageItem { /** @return true if there's any shortcuts that are not manifest shortcuts. */ public boolean hasNonManifestShortcuts() { final boolean[] condition = new boolean[1]; - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcutStopWhen(si -> { if (!si.isDeclaredInManifest()) { + condition[0] = true; return true; } - } - return false; + return false; + }); + return condition[0]; } public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) { @@ -1553,11 +1527,8 @@ class ShortcutPackage extends ShortcutPackageItem { pw.print(prefix); pw.println(" Shortcuts:"); - long totalBitmapSize = 0; - final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts; - final int size = shortcuts.size(); - for (int i = 0; i < size; i++) { - final ShortcutInfo si = shortcuts.valueAt(i); + final long[] totalBitmapSize = new long[1]; + forEachShortcut(si -> { pw.println(si.toDumpString(prefix + " ")); if (si.getBitmapPath() != null) { final long len = new File(si.getBitmapPath()).length(); @@ -1566,15 +1537,15 @@ class ShortcutPackage extends ShortcutPackageItem { pw.print("bitmap size="); pw.println(len); - totalBitmapSize += len; + totalBitmapSize[0] += len; } - } + }); pw.print(prefix); pw.print(" "); pw.print("Total bitmap size: "); - pw.print(totalBitmapSize); + pw.print(totalBitmapSize[0]); pw.print(" ("); - pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize)); + pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize[0])); pw.println(")"); } @@ -1589,46 +1560,39 @@ class ShortcutPackage extends ShortcutPackageItem { | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); - final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts; - final int size = shortcuts.size(); - for (int i = 0; i < size; i++) { - final ShortcutInfo si = shortcuts.valueAt(i); + forEachShortcut(si -> { if ((si.getFlags() & shortcutFlags) != 0) { pw.println(si.toDumpString("")); } - } + }); } @Override public JSONObject dumpCheckin(boolean clear) throws JSONException { final JSONObject result = super.dumpCheckin(clear); - int numDynamic = 0; - int numPinned = 0; - int numManifest = 0; - int numBitmaps = 0; - long totalBitmapSize = 0; + final int[] numDynamic = new int[1]; + final int[] numPinned = new int[1]; + final int[] numManifest = new int[1]; + final int[] numBitmaps = new int[1]; + final long[] totalBitmapSize = new long[1]; - final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts; - final int size = shortcuts.size(); - for (int i = 0; i < size; i++) { - final ShortcutInfo si = shortcuts.valueAt(i); - - if (si.isDynamic()) numDynamic++; - if (si.isDeclaredInManifest()) numManifest++; - if (si.isPinned()) numPinned++; + forEachShortcut(si -> { + if (si.isDynamic()) numDynamic[0]++; + if (si.isDeclaredInManifest()) numManifest[0]++; + if (si.isPinned()) numPinned[0]++; if (si.getBitmapPath() != null) { - numBitmaps++; - totalBitmapSize += new File(si.getBitmapPath()).length(); + numBitmaps[0]++; + totalBitmapSize[0] += new File(si.getBitmapPath()).length(); } - } + }); - result.put(KEY_DYNAMIC, numDynamic); - result.put(KEY_MANIFEST, numManifest); - result.put(KEY_PINNED, numPinned); - result.put(KEY_BITMAPS, numBitmaps); - result.put(KEY_BITMAP_BYTES, totalBitmapSize); + result.put(KEY_DYNAMIC, numDynamic[0]); + result.put(KEY_MANIFEST, numManifest[0]); + result.put(KEY_PINNED, numPinned[0]); + result.put(KEY_BITMAPS, numBitmaps[0]); + result.put(KEY_BITMAP_BYTES, totalBitmapSize[0]); // TODO Log update frequency too. @@ -1652,9 +1616,15 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime); getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup); - for (int j = 0; j < size; j++) { - saveShortcut(out, mShortcuts.valueAt(j), forBackup, - getPackageInfo().isBackupAllowed()); + if (forBackup) { + // Shortcuts are persisted in AppSearch, xml is only needed for backup. + forEachShortcut(si -> { + try { + saveShortcut(out, si, forBackup, getPackageInfo().isBackupAllowed()); + } catch (IOException | XmlPullParserException e) { + throw new RuntimeException(e); + } + }); } if (!forBackup) { @@ -1771,12 +1741,14 @@ class ShortcutPackage extends ShortcutPackageItem { } final Intent[] intentsNoExtras = si.getIntentsNoExtras(); final PersistableBundle[] intentsExtras = si.getIntentPersistableExtrases(); - final int numIntents = intentsNoExtras.length; - for (int i = 0; i < numIntents; i++) { - out.startTag(null, TAG_INTENT); - ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); - ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); - out.endTag(null, TAG_INTENT); + if (intentsNoExtras != null && intentsExtras != null) { + final int numIntents = intentsNoExtras.length; + for (int i = 0; i < numIntents; i++) { + out.startTag(null, TAG_INTENT); + ShortcutService.writeAttr(out, ATTR_INTENT_NO_EXTRA, intentsNoExtras[i]); + ShortcutService.writeTagExtra(out, TAG_EXTRAS, intentsExtras[i]); + out.endTag(null, TAG_INTENT); + } } ShortcutService.writeTagExtra(out, TAG_EXTRAS, si.getExtras()); @@ -1864,7 +1836,7 @@ class ShortcutPackage extends ShortcutPackageItem { final ShortcutInfo si = parseShortcut(parser, packageName, shortcutUser.getUserId(), fromBackup); // Don't use addShortcut(), we don't need to save the icon. - ret.mShortcuts.put(si.getId(), si); + ret.mShortcuts.add(si); continue; case TAG_SHARE_TARGET: ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser)); @@ -2060,7 +2032,9 @@ class ShortcutPackage extends ShortcutPackageItem { @VisibleForTesting List<ShortcutInfo> getAllShortcutsForTest() { - return new ArrayList<>(mShortcuts.values()); + final List<ShortcutInfo> ret = new ArrayList<>(1); + forEachShortcut(ret::add); + return ret; } @VisibleForTesting @@ -2072,7 +2046,7 @@ class ShortcutPackage extends ShortcutPackageItem { public void verifyStates() { super.verifyStates(); - boolean failed = false; + final boolean[] failed = new boolean[1]; final ShortcutService s = mShortcutUser.mService; @@ -2083,7 +2057,7 @@ class ShortcutPackage extends ShortcutPackageItem { for (int outer = all.size() - 1; outer >= 0; outer--) { final ArrayList<ShortcutInfo> list = all.valueAt(outer); if (list.size() > mShortcutUser.mService.getMaxActivityShortcuts()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": activity " + all.keyAt(outer) + " has " + all.valueAt(outer).size() + " shortcuts."); } @@ -2103,61 +2077,60 @@ class ShortcutPackage extends ShortcutPackageItem { } // Verify each shortcut's status. - for (int i = mShortcuts.size() - 1; i >= 0; i--) { - final ShortcutInfo si = mShortcuts.valueAt(i); + forEachShortcut(si -> { if (!(si.isDeclaredInManifest() || si.isDynamic() || si.isPinned() || si.isCached())) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " is not manifest, dynamic or pinned."); } if (si.isDeclaredInManifest() && si.isDynamic()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " is both dynamic and manifest at the same time."); } if (si.getActivity() == null && !si.isFloating()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has null activity, but not floating."); } if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " is not floating, but is disabled."); } if (si.isFloating() && si.getRank() != 0) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " is floating, but has rank=" + si.getRank()); } if (si.getIcon() != null) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " still has an icon"); } if (si.hasAdaptiveBitmap() && !(si.hasIconFile() || si.hasIconUri())) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has adaptive bitmap but was not saved to a file nor has icon uri."); } if (si.hasIconFile() && si.hasIconResource()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both resource and bitmap icons"); } if (si.hasIconFile() && si.hasIconUri()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both url and bitmap icons"); } if (si.hasIconUri() && si.hasIconResource()) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both url and resource icons"); } if (si.isEnabled() != (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " isEnabled() and getDisabledReason() disagree: " + si.isEnabled() + " vs " + si.getDisabledReason()); @@ -2165,18 +2138,18 @@ class ShortcutPackage extends ShortcutPackageItem { if ((si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) && (getPackageInfo().getBackupSourceVersionCode() == ShortcutInfo.VERSION_CODE_UNKNOWN)) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " RESTORED_VERSION_LOWER with no backup source version code."); } if (s.isDummyMainActivity(si.getActivity())) { - failed = true; + failed[0] = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has a dummy target activity"); } - } + }); - if (failed) { + if (failed[0]) { throw new IllegalStateException("See logcat for errors"); } } @@ -2187,6 +2160,7 @@ class ShortcutPackage extends ShortcutPackageItem { } else { mPackageIdentifiers.remove(packageName); } + resetAppSearch(session -> AndroidFuture.completedFuture(true)); } void mutateShortcut(@NonNull final String id, @Nullable final ShortcutInfo shortcut, @@ -2196,23 +2170,302 @@ class ShortcutPackage extends ShortcutPackageItem { synchronized (mLock) { if (shortcut != null) { transform.accept(shortcut); - } else { - transform.accept(findShortcutById(id)); } - // TODO: Load ShortcutInfo from AppSearch, apply transformation logic and save + final ShortcutInfo si = getShortcutById(id); + if (si == null) { + return; + } + transform.accept(si); + saveShortcut(si); } } + private void saveShortcut(@NonNull final ShortcutInfo... shortcuts) { + Objects.requireNonNull(shortcuts); + saveShortcut(Arrays.asList(shortcuts)); + } + + private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) { + Objects.requireNonNull(shortcuts); + if (shortcuts.isEmpty()) { + // No need to invoke AppSearch when there's nothing to save. + return; + } + ConcurrentUtils.waitForFutureNoInterrupt( + runInAppSearch(session -> { + final AndroidFuture<Boolean> future = new AndroidFuture<>(); + session.put(new PutDocumentsRequest.Builder() + .addGenericDocuments( + AppSearchShortcutInfo.toGenericDocuments(shortcuts)) + .build(), + mShortcutUser.mExecutor, + result -> { + if (!result.isSuccess()) { + for (AppSearchResult<Void> k : result.getFailures().values()) { + Slog.e(TAG, k.getErrorMessage()); + } + future.completeExceptionally(new RuntimeException( + "failed to save shortcuts")); + return; + } + future.complete(true); + }); + return future; + }), + "saving shortcut"); + } + /** * Removes shortcuts from AppSearch. */ void removeShortcuts() { + awaitInAppSearch("removing shortcuts", session -> { + final AndroidFuture<Boolean> future = new AndroidFuture<>(); + session.remove("", + new SearchSpec.Builder() + .addFilterSchemas(AppSearchShortcutInfo.SCHEMA_TYPE) + .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY) + .build(), + mShortcutUser.mExecutor, result -> { + if (!result.isSuccess()) { + future.completeExceptionally(new RuntimeException( + "Failed to cleanup shortcuts " + result.getErrorMessage())); + return; + } + future.complete(true); + }); + return future; + }); + } + + private void removeShortcut(@NonNull final String id) { + Objects.requireNonNull(id); + awaitInAppSearch("removing shortcut with id=" + id, session -> { + final AndroidFuture<Boolean> future = new AndroidFuture<>(); + session.remove(new RemoveByUriRequest.Builder(getPackageName()).addUris(id).build(), + mShortcutUser.mExecutor, result -> { + if (!result.isSuccess()) { + final Map<String, AppSearchResult<Void>> failures = + result.getFailures(); + for (String key : failures.keySet()) { + Slog.e(TAG, "Failed deleting " + key + ", error message:" + + failures.get(key).getErrorMessage()); + } + future.completeExceptionally(new RuntimeException( + "Failed to delete shortcut: " + id)); + return; + } + future.complete(true); + }); + return future; + }); + } + + private ShortcutInfo getShortcutById(String id) { + return awaitInAppSearch("getting shortcut with id=" + id, session -> { + final AndroidFuture<ShortcutInfo> future = new AndroidFuture<>(); + session.getByUri( + new GetByUriRequest.Builder(getPackageName()).addUris(id).build(), + mShortcutUser.mExecutor, + results -> { + if (results.isSuccess()) { + Map<String, GenericDocument> documents = results.getSuccesses(); + for (GenericDocument doc : documents.values()) { + final ShortcutInfo info = new AppSearchShortcutInfo(doc) + .toShortcutInfo(mShortcutUser.getUserId()); + future.complete(info); + return; + } + } + future.complete(null); + }); + return future; + }); + } + + private void forEachShortcut( + @NonNull final Consumer<ShortcutInfo> cb) { + forEachShortcutStopWhen(si -> { + cb.accept(si); + return false; + }); + } + + private void forEachShortcutMutate(@NonNull final Consumer<ShortcutInfo> cb) { + forEachShortcutMutateIf(si -> { + cb.accept(si); + return true; + }); + } + + private void forEachShortcutMutateIf(@NonNull final Function<ShortcutInfo, Boolean> cb) { + final SearchResults res = awaitInAppSearch("mutating shortcuts", session -> + AndroidFuture.completedFuture(session.search("", new SearchSpec.Builder() + .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build()))); + if (res == null) return; + List<ShortcutInfo> shortcuts = getNextPage(res); + while (!shortcuts.isEmpty()) { + final List<ShortcutInfo> changed = new ArrayList<>(1); + for (ShortcutInfo si : shortcuts) { + if (cb.apply(si)) changed.add(si); + } + saveShortcut(changed); + shortcuts = getNextPage(res); + } + } + + private void forEachShortcutStopWhen( + @NonNull final Function<ShortcutInfo, Boolean> cb) { + forEachShortcutStopWhen("", cb); + } + + private void forEachShortcutStopWhen( + @NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) { + final SearchResults res = awaitInAppSearch("iterating shortcuts", session -> + AndroidFuture.completedFuture(session.search(query, new SearchSpec.Builder() + .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY).build()))); + if (res == null) return; + List<ShortcutInfo> shortcuts = getNextPage(res); + while (!shortcuts.isEmpty()) { + for (ShortcutInfo si : shortcuts) { + if (cb.apply(si)) return; + } + shortcuts = getNextPage(res); + } + } + + private List<ShortcutInfo> getNextPage(@NonNull final SearchResults res) { + final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>(); + final List<ShortcutInfo> ret = new ArrayList<>(); + final long callingIdentity = Binder.clearCallingIdentity(); + try { + res.getNextPage(mShortcutUser.mExecutor, nextPage -> { + if (!nextPage.isSuccess()) { + future.complete(ret); + return; + } + final List<SearchResult> results = nextPage.getResultValue(); + if (results.isEmpty()) { + future.complete(ret); + return; + } + final List<ShortcutInfo> page = new ArrayList<>(results.size()); + for (SearchResult result : results) { + final ShortcutInfo si = new AppSearchShortcutInfo(result.getGenericDocument()) + .toShortcutInfo(mShortcutUser.getUserId()); + page.add(si); + } + ret.addAll(page); + future.complete(ret); + }); + return ConcurrentUtils.waitForFutureNoInterrupt(future, + "getting next batch of shortcuts"); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + @Nullable + private <T> T awaitInAppSearch( + @NonNull final String description, + @NonNull final Function<AppSearchSession, CompletableFuture<T>> cb) { + return ConcurrentUtils.waitForFutureNoInterrupt(runInAppSearch(cb), description); + } + + @Nullable + private <T> CompletableFuture<T> runInAppSearch( + @NonNull final Function<AppSearchSession, CompletableFuture<T>> cb) { + synchronized (mLock) { + final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); + try { + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() // TODO: change this to penaltyDeath to fix the call-site + .build()); + if (mAppSearchSession != null) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + return AndroidFuture.supply(() -> mAppSearchSession).thenCompose(cb); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } else { + return resetAppSearch(cb); + } + } finally { + StrictMode.setThreadPolicy(oldPolicy); + } + } + } + + private <T> CompletableFuture<T> resetAppSearch( + @NonNull final Function<AppSearchSession, CompletableFuture<T>> cb) { + final long callingIdentity = Binder.clearCallingIdentity(); + final AppSearchManager.SearchContext searchContext = + new AppSearchManager.SearchContext.Builder(getPackageName()).build(); + final AppSearchSession session; + try { + session = ConcurrentUtils.waitForFutureNoInterrupt( + mShortcutUser.getAppSearch(searchContext), "resetting app search"); + ConcurrentUtils.waitForFutureNoInterrupt(setupSchema(session), "setting up schema"); + mAppSearchSession = session; + return cb.apply(mAppSearchSession); + } catch (Exception e) { + Slog.e(TAG, "Failed to initiate app search for shortcut package " + + getPackageName() + " user " + mShortcutUser.getUserId(), e); + return AndroidFuture.completedFuture(null); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + + void closeAppSearchSession() { + synchronized (mLock) { + if (mAppSearchSession != null) { + final long callingIdentity = Binder.clearCallingIdentity(); + try { + mAppSearchSession.close(); + } finally { + Binder.restoreCallingIdentity(callingIdentity); + } + } + mAppSearchSession = null; + } + } + + @NonNull + private AndroidFuture<AppSearchSession> setupSchema( + @NonNull final AppSearchSession session) { + SetSchemaRequest.Builder schemaBuilder = new SetSchemaRequest.Builder() + .addSchemas(AppSearchPerson.SCHEMA, AppSearchShortcutInfo.SCHEMA); + for (PackageIdentifier pi : mPackageIdentifiers.values()) { + schemaBuilder = schemaBuilder + .setSchemaTypeVisibilityForPackage( + AppSearchPerson.SCHEMA_TYPE, true, pi) + .setSchemaTypeVisibilityForPackage( + AppSearchShortcutInfo.SCHEMA_TYPE, true, pi); + } + final AndroidFuture<AppSearchSession> future = new AndroidFuture<>(); + session.setSchema( + schemaBuilder.build(), mShortcutUser.mExecutor, mShortcutUser.mExecutor, result -> { + if (!result.isSuccess()) { + future.completeExceptionally( + new IllegalArgumentException(result.getErrorMessage())); + return; + } + future.complete(session); + }); + return future; } /** * Merge/replace shortcuts parsed from xml file. */ void restoreParsedShortcuts(final boolean replace) { + if (replace) { + removeShortcuts(); + } + saveShortcut(mShortcuts); } private boolean verifyRanksSequential(List<ShortcutInfo> list) { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 8e999de80707..4cfa353b36f8 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1051,6 +1051,8 @@ public class ShortcutService extends IShortcutService.Stub { } final ShortcutUser user = getUserShortcutsLocked(userId); + // Close AppSearchSession to flush pending changes. + user.forAllPackages(ShortcutPackage::closeAppSearchSession); user.logSharingShortcutStats(mMetricsLogger); } @@ -5081,6 +5083,17 @@ public class ShortcutService extends IShortcutService.Stub { } @VisibleForTesting + void updatePackageShortcutForTest(String packageName, String shortcutId, int userId, + Consumer<ShortcutInfo> cb) { + synchronized (mLock) { + final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId); + if (pkg == null) return; + + pkg.mutateShortcut(shortcutId, null, cb); + } + } + + @VisibleForTesting ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) { synchronized (mLock) { final ShortcutUser user = mUsers.get(userId); diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 589b3b403e6c..88b06511cc74 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -2041,6 +2041,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return mService.getPackageShortcutForTest(packageName, shortcutId, userId); } + protected void updatePackageShortcut(String packageName, String shortcutId, int userId, + Consumer<ShortcutInfo> cb) { + mService.updatePackageShortcutForTest(packageName, shortcutId, userId, cb); + } + protected void assertShortcutExists(String packageName, String shortcutId, int userId) { assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null); } @@ -2236,6 +2241,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId()); } + protected void updateCallerShortcut(String shortcutId, Consumer<ShortcutInfo> cb) { + updatePackageShortcut(getCallingPackage(), shortcutId, getCallingUserId(), cb); + } + protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) { final List<ShortcutInfo>[] ret = new List[1]; runWithCaller(launcher, userId, () -> { @@ -2395,6 +2404,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); + mMockAppSearchManager.removeShortcuts(); + initService(); mService.applyRestore(payload, USER_0); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 4d0beef99cca..c16e49899dc2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -1702,8 +1702,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Because setDynamicShortcuts will update the timestamps when ranks are changing, // we explicitly set timestamps here. - getCallerShortcut("s1").setTimestamp(5000); - getCallerShortcut("s2").setTimestamp(1000); + updateCallerShortcut("s1", si -> si.setTimestamp(5000)); + updateCallerShortcut("s2", si -> si.setTimestamp(1000)); setCaller(CALLING_PACKAGE_2); final ShortcutInfo s2_2 = makeShortcut("s2"); @@ -1713,9 +1713,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeComponent(ShortcutActivity.class)); assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4))); - getCallerShortcut("s2").setTimestamp(1500); - getCallerShortcut("s3").setTimestamp(3000); - getCallerShortcut("s4").setTimestamp(500); + updateCallerShortcut("s2", si -> si.setTimestamp(1500)); + updateCallerShortcut("s3", si -> si.setTimestamp(3000)); + updateCallerShortcut("s4", si -> si.setTimestamp(500)); setCaller(CALLING_PACKAGE_3); final ShortcutInfo s3_2 = makeShortcutWithLocusId("s3", makeLocusId("l2")); @@ -1723,7 +1723,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list(s3_2))); - getCallerShortcut("s3").setTimestamp(START_TIME + 5000); + updateCallerShortcut("s3", si -> si.setTimestamp(START_TIME + 5000)); setCaller(LAUNCHER_1); @@ -7686,7 +7686,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals("http://www/", si.getIntent().getData().toString()); assertEquals("foo/bar", si.getIntent().getType()); assertEquals( - new ComponentName("abc", ".xyz"), si.getIntent().getComponent()); + new ComponentName("abc", "abc.xyz"), si.getIntent().getComponent()); assertEquals(set("cat1", "cat2"), si.getIntent().getCategories()); assertEquals("value1", si.getIntent().getStringExtra("key1")); |