diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index bd8cae20fc4bb..988ba4410133f 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -439,6 +439,7 @@ public final class ShortcutInfo implements Parcelable { @NonNull public Builder setIntent(@NonNull Intent intent) { mIntent = Preconditions.checkNotNull(intent, "intent"); + Preconditions.checkNotNull(mIntent.getAction(), "Intent action must be set."); return this; } diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index ab0367dc0df45..c12137ac07f23 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -18,7 +18,6 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.TestApi; import android.content.Context; -import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -80,8 +79,18 @@ import java.util.List; * *

Backup and Restore

* - * Shortcuts will be backed up and restored across devices. This means all information, including - * IDs, must be meaningful on a different device. + * Pinned shortcuts will be backed up and restored across devices. This means all information + * within shortcuts, including IDs, must be meaningful on different devices. + * + *

Note that: + *

+ * * *

APIs for launcher

* @@ -147,8 +156,8 @@ public class ShortcutManager { } /** - * Publish a single dynamic shortcut. If there's already dynamic or pinned shortcuts with - * the same ID, they will all be updated. + * Publish list of dynamic shortcuts. If there's already dynamic or pinned shortcuts with + * the same IDs, they will all be updated. * *

This API will be rate-limited. * @@ -167,7 +176,7 @@ public class ShortcutManager { } /** - * Delete a single dynamic shortcut by ID. + * Delete dynamic shortcuts by ID. */ public void removeDynamicShortcuts(@NonNull List shortcutIds) { try { diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java index 76d47a839f90c..db2b9f40239cd 100644 --- a/services/core/java/com/android/server/pm/ShortcutLauncher.java +++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java @@ -80,26 +80,31 @@ class ShortcutLauncher extends ShortcutPackageItem { * Called when the new package can't receive the backup, due to signature or version mismatch. */ @Override - protected void onRestoreBlocked(ShortcutService s) { + protected void onRestoreBlocked() { final ArrayList pinnedPackages = new ArrayList<>(mPinnedShortcuts.keySet()); mPinnedShortcuts.clear(); for (int i = pinnedPackages.size() - 1; i >= 0; i--) { final PackageWithUser pu = pinnedPackages.get(i); - s.getPackageShortcutsLocked(pu.packageName, pu.userId) - .refreshPinnedFlags(s); + final ShortcutPackage p = mShortcutUser.getPackageShortcutsIfExists(pu.packageName); + if (p != null) { + p.refreshPinnedFlags(); + } } } @Override - protected void onRestored(ShortcutService s) { + protected void onRestored() { // Nothing to do. } - public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId, + public void pinShortcuts(@UserIdInt int packageUserId, @NonNull String packageName, @NonNull List ids) { final ShortcutPackage packageShortcuts = - s.getPackageShortcutsLocked(packageName, packageUserId); + mShortcutUser.getPackageShortcutsIfExists(packageName); + if (packageShortcuts == null) { + return; // No need to instantiate. + } final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName); @@ -126,7 +131,7 @@ class ShortcutLauncher extends ShortcutPackageItem { } mPinnedShortcuts.put(pu, newSet); } - packageShortcuts.refreshPinnedFlags(s); + packageShortcuts.refreshPinnedFlags(); } /** @@ -240,7 +245,7 @@ class ShortcutLauncher extends ShortcutPackageItem { return ret; } - public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) { + public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { pw.println(); pw.print(prefix); @@ -252,7 +257,7 @@ class ShortcutLauncher extends ShortcutPackageItem { pw.print(getOwnerUserId()); pw.println(); - getPackageInfo().dump(s, pw, prefix + " "); + getPackageInfo().dump(pw, prefix + " "); pw.println(); final int size = mPinnedShortcuts.size(); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index f3ce79cf755fa..1b086639ddd32 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -98,17 +98,16 @@ class ShortcutPackage extends ShortcutPackageItem { private long mLastKnownForegroundElapsedTime; - private ShortcutPackage(ShortcutService s, ShortcutUser shortcutUser, + private ShortcutPackage(ShortcutUser shortcutUser, int packageUserId, String packageName, ShortcutPackageInfo spi) { super(shortcutUser, packageUserId, packageName, spi != null ? spi : ShortcutPackageInfo.newEmpty()); - mPackageUid = s.injectGetPackageUid(packageName, packageUserId); + mPackageUid = shortcutUser.mService.injectGetPackageUid(packageName, packageUserId); } - public ShortcutPackage(ShortcutService s, ShortcutUser shortcutUser, - int packageUserId, String packageName) { - this(s, shortcutUser, packageUserId, packageName, null); + public ShortcutPackage(ShortcutUser shortcutUser, int packageUserId, String packageName) { + this(shortcutUser, packageUserId, packageName, null); } @Override @@ -126,10 +125,12 @@ class ShortcutPackage extends ShortcutPackageItem { * exists (as opposed to Launcher trying to fetch shortcuts from a non-existent package), so * we do some initialization for the package. */ - private void onShortcutPublish(ShortcutService s) { + private void onShortcutPublish() { // Make sure we have the version code for the app. We need the version code in // handlePackageUpdated(). if (getPackageInfo().getVersionCode() < 0) { + final ShortcutService s = mShortcutUser.mService; + final int versionCode = s.getApplicationVersionCode(getPackageName(), getOwnerUserId()); if (ShortcutService.DEBUG) { Slog.d(TAG, String.format("Package %s version = %d", getPackageName(), @@ -143,16 +144,16 @@ class ShortcutPackage extends ShortcutPackageItem { } @Override - protected void onRestoreBlocked(ShortcutService s) { + protected void onRestoreBlocked() { // Can't restore due to version/signature mismatch. Remove all shortcuts. mShortcuts.clear(); } @Override - protected void onRestored(ShortcutService s) { + protected void onRestored() { // Because some launchers may not have been restored (e.g. allowBackup=false), // we need to re-calculate the pinned shortcuts. - refreshPinnedFlags(s); + refreshPinnedFlags(); } /** @@ -163,19 +164,18 @@ class ShortcutPackage extends ShortcutPackageItem { return mShortcuts.get(id); } - private ShortcutInfo deleteShortcut(@NonNull ShortcutService s, - @NonNull String id) { + private ShortcutInfo deleteShortcut(@NonNull String id) { final ShortcutInfo shortcut = mShortcuts.remove(id); if (shortcut != null) { - s.removeIcon(getPackageUserId(), shortcut); + mShortcutUser.mService.removeIcon(getPackageUserId(), shortcut); shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED); } return shortcut; } - void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) { - deleteShortcut(s, newShortcut.getId()); - s.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut); + void addShortcut(@NonNull ShortcutInfo newShortcut) { + deleteShortcut(newShortcut.getId()); + mShortcutUser.mService.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut); mShortcuts.put(newShortcut.getId(), newShortcut); } @@ -184,10 +184,9 @@ class ShortcutPackage extends ShortcutPackageItem { * * It checks the max number of dynamic shortcuts. */ - public void addDynamicShortcut(@NonNull ShortcutService s, - @NonNull ShortcutInfo newShortcut) { + public void addDynamicShortcut(@NonNull ShortcutInfo newShortcut) { - onShortcutPublish(s); + onShortcutPublish(); newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); @@ -209,21 +208,21 @@ class ShortcutPackage extends ShortcutPackageItem { } // Make sure there's still room. - s.enforceMaxDynamicShortcuts(newDynamicCount); + mShortcutUser.mService.enforceMaxDynamicShortcuts(newDynamicCount); // Okay, make it dynamic and add. if (wasPinned) { newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); } - addShortcut(s, newShortcut); + addShortcut(newShortcut); mDynamicShortcutCount = newDynamicCount; } /** * Remove all shortcuts that aren't pinned nor dynamic. */ - private void removeOrphans(@NonNull ShortcutService s) { + private void removeOrphans() { ArrayList removeList = null; // Lazily initialize. for (int i = mShortcuts.size() - 1; i >= 0; i--) { @@ -238,7 +237,7 @@ class ShortcutPackage extends ShortcutPackageItem { } if (removeList != null) { for (int i = removeList.size() - 1; i >= 0; i--) { - deleteShortcut(s, removeList.get(i)); + deleteShortcut(removeList.get(i)); } } } @@ -246,18 +245,18 @@ class ShortcutPackage extends ShortcutPackageItem { /** * Remove all dynamic shortcuts. */ - public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) { + public void deleteAllDynamicShortcuts() { for (int i = mShortcuts.size() - 1; i >= 0; i--) { mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC); } - removeOrphans(s); + removeOrphans(); mDynamicShortcutCount = 0; } /** * Remove a dynamic shortcut by ID. */ - public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) { + public void deleteDynamicWithId(@NonNull String shortcutId) { final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId); if (oldShortcut == null) { @@ -269,7 +268,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (oldShortcut.isPinned()) { oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC); } else { - deleteShortcut(s, shortcutId); + deleteShortcut(shortcutId); } } @@ -279,14 +278,15 @@ class ShortcutPackage extends ShortcutPackageItem { * *

Then remove all shortcuts that are not dynamic and no longer pinned either. */ - public void refreshPinnedFlags(@NonNull ShortcutService s) { + public void refreshPinnedFlags() { // First, un-pin all shortcuts for (int i = mShortcuts.size() - 1; i >= 0; i--) { mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED); } // Then, for the pinned set for each launcher, set the pin flag one by one. - s.getUserShortcutsLocked(getPackageUserId()).forAllLaunchers(launcherShortcuts -> { + mShortcutUser.mService.getUserShortcutsLocked(getPackageUserId()) + .forAllLaunchers(launcherShortcuts -> { final ArraySet pinned = launcherShortcuts.getPinnedShortcutIds( getPackageName(), getPackageUserId()); @@ -308,7 +308,7 @@ class ShortcutPackage extends ShortcutPackageItem { }); // Lastly, remove the ones that are no longer pinned nor dynamic. - removeOrphans(s); + removeOrphans(); } /** @@ -317,8 +317,10 @@ class ShortcutPackage extends ShortcutPackageItem { *

This takes care of the resetting the counter for foreground apps as well as after * locale changes. */ - public int getApiCallCount(@NonNull ShortcutService s) { - mShortcutUser.resetThrottlingIfNeeded(s); + public int getApiCallCount() { + mShortcutUser.resetThrottlingIfNeeded(); + + final ShortcutService s = mShortcutUser.mService; // Reset the counter if: // - the package is in foreground now. @@ -328,7 +330,7 @@ class ShortcutPackage extends ShortcutPackageItem { || mLastKnownForegroundElapsedTime < s.getUidLastForegroundElapsedTimeLocked(mPackageUid)) { mLastKnownForegroundElapsedTime = s.injectElapsedRealtime(); - resetRateLimiting(s); + resetRateLimiting(); } // Note resetThrottlingIfNeeded() and resetRateLimiting() will set 0 to mApiCallCount, @@ -349,8 +351,8 @@ class ShortcutPackage extends ShortcutPackageItem { // If not reset yet, then reset. if (mLastResetTime < last) { if (ShortcutService.DEBUG) { - Slog.d(TAG, String.format("My last reset=%d, now=%d, last=%d: resetting", - mLastResetTime, now, last)); + Slog.d(TAG, String.format("%s: last reset=%d, now=%d, last=%d: resetting", + getPackageName(), mLastResetTime, now, last)); } mApiCallCount = 0; mLastResetTime = last; @@ -365,8 +367,10 @@ class ShortcutPackage extends ShortcutPackageItem { *

This takes care of the resetting the counter for foreground apps as well as after * locale changes, which is done internally by {@link #getApiCallCount}. */ - public boolean tryApiCall(@NonNull ShortcutService s) { - if (getApiCallCount(s) >= s.mMaxUpdatesPerInterval) { + public boolean tryApiCall() { + final ShortcutService s = mShortcutUser.mService; + + if (getApiCallCount() >= s.mMaxUpdatesPerInterval) { return false; } mApiCallCount++; @@ -374,13 +378,13 @@ class ShortcutPackage extends ShortcutPackageItem { return true; } - public void resetRateLimiting(@NonNull ShortcutService s) { + public void resetRateLimiting() { if (ShortcutService.DEBUG) { Slog.d(TAG, "resetRateLimiting: " + getPackageName()); } if (mApiCallCount > 0) { mApiCallCount = 0; - s.scheduleSaveUser(getOwnerUserId()); + mShortcutUser.mService.scheduleSaveUser(getOwnerUserId()); } } @@ -392,9 +396,9 @@ class ShortcutPackage extends ShortcutPackageItem { /** * Find all shortcuts that match {@code query}. */ - public void findAll(@NonNull ShortcutService s, @NonNull List result, + public void findAll(@NonNull List result, @Nullable Predicate query, int cloneFlag) { - findAll(s, result, query, cloneFlag, null, 0); + findAll(result, query, cloneFlag, null, 0); } /** @@ -404,7 +408,7 @@ class ShortcutPackage extends ShortcutPackageItem { * by the calling launcher will not be included in the result, and also "isPinned" will be * adjusted for the caller too. */ - public void findAll(@NonNull ShortcutService s, @NonNull List result, + public void findAll(@NonNull List result, @Nullable Predicate query, int cloneFlag, @Nullable String callingLauncher, int launcherUserId) { if (getPackageInfo().isShadow()) { @@ -412,6 +416,8 @@ class ShortcutPackage extends ShortcutPackageItem { return; } + final ShortcutService s = mShortcutUser.mService; + // Set of pinned shortcuts by the calling launcher. final ArraySet pinnedByCallerSet = (callingLauncher == null) ? null : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId) @@ -479,7 +485,7 @@ class ShortcutPackage extends ShortcutPackageItem { * Called when the package is updated. If there are shortcuts with resource icons, update * their timestamps. */ - public void handlePackageUpdated(ShortcutService s, int newVersionCode) { + public void handlePackageUpdated(int newVersionCode) { if (getPackageInfo().getVersionCode() >= newVersionCode) { // Version hasn't changed; nothing to do. return; @@ -491,6 +497,8 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageInfo().setVersionCode(newVersionCode); + final ShortcutService s = mShortcutUser.mService; + boolean changed = false; for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); @@ -509,7 +517,7 @@ class ShortcutPackage extends ShortcutPackageItem { } } - public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) { + public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { pw.println(); pw.print(prefix); @@ -522,7 +530,7 @@ class ShortcutPackage extends ShortcutPackageItem { pw.print(prefix); pw.print(" "); pw.print("Calls: "); - pw.print(getApiCallCount(s)); + pw.print(getApiCallCount()); pw.println(); // getApiCallCount() may have updated mLastKnownForegroundElapsedTime. @@ -538,10 +546,10 @@ class ShortcutPackage extends ShortcutPackageItem { pw.print("Last reset: ["); pw.print(mLastResetTime); pw.print("] "); - pw.print(s.formatTime(mLastResetTime)); + pw.print(ShortcutService.formatTime(mLastResetTime)); pw.println(); - getPackageInfo().dump(s, pw, prefix + " "); + getPackageInfo().dump(pw, prefix + " "); pw.println(); pw.print(prefix); @@ -569,7 +577,7 @@ class ShortcutPackage extends ShortcutPackageItem { pw.print("Total bitmap size: "); pw.print(totalBitmapSize); pw.print(" ("); - pw.print(Formatter.formatFileSize(s.mContext, totalBitmapSize)); + pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize)); pw.println(")"); } @@ -651,7 +659,7 @@ class ShortcutPackage extends ShortcutPackageItem { final String packageName = ShortcutService.parseStringAttribute(parser, ATTR_NAME); - final ShortcutPackage ret = new ShortcutPackage(s, shortcutUser, + final ShortcutPackage ret = new ShortcutPackage(shortcutUser, shortcutUser.getUserId(), packageName); ret.mDynamicShortcutCount = diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java index 74969f02d7026..ae9709e4b6c83 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java @@ -189,7 +189,7 @@ class ShortcutPackageInfo { mSigHashes = hashes; } - public void dump(ShortcutService s, PrintWriter pw, String prefix) { + public void dump(PrintWriter pw, String prefix) { pw.println(); pw.print(prefix); diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java index 6fbdb8221ac56..0c2417cffae7c 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java @@ -69,18 +69,20 @@ abstract class ShortcutPackageItem { return mPackageInfo; } - public void refreshPackageInfoAndSave(ShortcutService s) { + public void refreshPackageInfoAndSave() { if (mPackageInfo.isShadow()) { return; // Don't refresh for shadow user. } + final ShortcutService s = mShortcutUser.mService; mPackageInfo.refresh(s, this); s.scheduleSaveUser(getOwnerUserId()); } - public void attemptToRestoreIfNeededAndSave(ShortcutService s) { + public void attemptToRestoreIfNeededAndSave() { if (!mPackageInfo.isShadow()) { return; // Already installed, nothing to do. } + final ShortcutService s = mShortcutUser.mService; if (!s.isPackageInstalled(mPackageName, mPackageUserId)) { if (ShortcutService.DEBUG) { Slog.d(TAG, String.format("Package still not installed: %s user=%d", @@ -91,14 +93,14 @@ abstract class ShortcutPackageItem { if (!mPackageInfo.hasSignatures()) { s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId + " but signatures not found in the restore data."); - onRestoreBlocked(s); + onRestoreBlocked(); return; } final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId); if (!mPackageInfo.canRestoreTo(s, pi)) { // Package is now installed, but can't restore. Let the subclass do the cleanup. - onRestoreBlocked(s); + onRestoreBlocked(); return; } if (ShortcutService.DEBUG) { @@ -106,7 +108,7 @@ abstract class ShortcutPackageItem { mPackageUserId, getOwnerUserId())); } - onRestored(s); + onRestored(); // Now the package is not shadow. mPackageInfo.setShadow(false); @@ -118,12 +120,12 @@ abstract class ShortcutPackageItem { * Called when the new package can't be restored because it has a lower version number * or different signatures. */ - protected abstract void onRestoreBlocked(ShortcutService s); + protected abstract void onRestoreBlocked(); /** * Called when the new package is successfully restored. */ - protected abstract void onRestored(ShortcutService s); + protected abstract void onRestored(); public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup) throws IOException, XmlPullParserException; diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 66833f462a8f7..5219201629a93 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -74,7 +74,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; @@ -104,6 +103,7 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Predicate; @@ -278,6 +278,8 @@ public class ShortcutService extends IShortcutService.Stub { */ private final AtomicLong mLocaleChangeSequenceNumber = new AtomicLong(); + private final AtomicBoolean mBootCompleted = new AtomicBoolean(); + private static final int PACKAGE_MATCH_FLAGS = PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE @@ -427,6 +429,9 @@ public class ShortcutService extends IShortcutService.Stub { case SystemService.PHASE_LOCK_SETTINGS_READY: initialize(); break; + case SystemService.PHASE_BOOT_COMPLETED: + mBootCompleted.set(true); + break; } } @@ -771,7 +776,7 @@ public class ShortcutService extends IShortcutService.Stub { out.setOutput(bos, StandardCharsets.UTF_8.name()); out.startDocument(null, true); - getUserShortcutsLocked(userId).saveToXml(this, out, forBackup); + getUserShortcutsLocked(userId).saveToXml(out, forBackup); out.endDocument(); @@ -949,7 +954,7 @@ public class ShortcutService extends IShortcutService.Stub { if (userPackages == null) { userPackages = loadUserLocked(userId); if (userPackages == null) { - userPackages = new ShortcutUser(userId); + userPackages = new ShortcutUser(this, userId); } mUsers.put(userId, userPackages); } @@ -967,7 +972,7 @@ public class ShortcutService extends IShortcutService.Stub { @NonNull ShortcutPackage getPackageShortcutsLocked( @NonNull String packageName, @UserIdInt int userId) { - return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName); + return getUserShortcutsLocked(userId).getPackageShortcuts(packageName); } @GuardedBy("mLock") @@ -976,7 +981,7 @@ public class ShortcutService extends IShortcutService.Stub { @NonNull String packageName, @UserIdInt int ownerUserId, @UserIdInt int launcherUserId) { return getUserShortcutsLocked(ownerUserId) - .getLauncherShortcuts(this, packageName, launcherUserId); + .getLauncherShortcuts(packageName, launcherUserId); } // === Caller validation === @@ -1039,7 +1044,7 @@ public class ShortcutService extends IShortcutService.Stub { private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user, @NonNull String packageName, @NonNull File path) { final ArraySet usedFiles = - user.getPackageShortcuts(this, packageName).getUsedBitmapFiles(); + user.getPackageShortcuts(packageName).getUsedBitmapFiles(); for (File child : path.listFiles()) { if (!child.isFile()) { @@ -1416,7 +1421,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); // Throttling. - if (!ps.tryApiCall(this)) { + if (!ps.tryApiCall()) { return false; } enforceMaxDynamicShortcuts(size); @@ -1427,12 +1432,12 @@ public class ShortcutService extends IShortcutService.Stub { } // First, remove all un-pinned; dynamic shortcuts - ps.deleteAllDynamicShortcuts(this); + ps.deleteAllDynamicShortcuts(); // Then, add/update all. We need to make sure to take over "pinned" flag. for (int i = 0; i < size; i++) { final ShortcutInfo newShortcut = newShortcuts.get(i); - ps.addDynamicShortcut(this, newShortcut); + ps.addDynamicShortcut(newShortcut); } } packageShortcutsChanged(packageName, userId); @@ -1451,7 +1456,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); // Throttling. - if (!ps.tryApiCall(this)) { + if (!ps.tryApiCall()) { return false; } @@ -1491,7 +1496,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId); // Throttling. - if (!ps.tryApiCall(this)) { + if (!ps.tryApiCall()) { return false; } for (int i = 0; i < size; i++) { @@ -1501,7 +1506,7 @@ public class ShortcutService extends IShortcutService.Stub { fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false); // Add it. - ps.addDynamicShortcut(this, newShortcut); + ps.addDynamicShortcut(newShortcut); } } packageShortcutsChanged(packageName, userId); @@ -1517,7 +1522,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { for (int i = shortcutIds.size() - 1; i >= 0; i--) { - getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this, + getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId( Preconditions.checkStringNotEmpty((String) shortcutIds.get(i))); } } @@ -1529,7 +1534,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyCaller(packageName, userId); synchronized (mLock) { - getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(this); + getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(); } packageShortcutsChanged(packageName, userId); } @@ -1561,7 +1566,7 @@ public class ShortcutService extends IShortcutService.Stub { final ArrayList ret = new ArrayList<>(); - getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags); + getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags); return new ParceledListSlice<>(ret); } @@ -1580,7 +1585,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { return mMaxUpdatesPerInterval - - getPackageShortcutsLocked(packageName, userId).getApiCallCount(this); + - getPackageShortcutsLocked(packageName, userId).getApiCallCount(); } } @@ -1674,7 +1679,7 @@ public class ShortcutService extends IShortcutService.Stub { Slog.v(TAG, "Default launcher from PM: " + detected); } } else { - detected = user.getLauncherComponent(); + detected = user.getDefaultLauncherComponent(); // TODO: Make sure it's still enabled. if (DEBUG) { @@ -1714,7 +1719,7 @@ public class ShortcutService extends IShortcutService.Stub { if (DEBUG) { Slog.v(TAG, "Detected launcher: " + detected); } - user.setLauncherComponent(this, detected); + user.setDefaultLauncherComponent(detected); return detected.getPackageName().equals(callingPackage); } else { // Default launcher not found. @@ -1748,7 +1753,7 @@ public class ShortcutService extends IShortcutService.Stub { // First, remove the package from the package list (if the package is a publisher). if (packageUserId == owningUserId) { - if (user.removePackage(this, packageName) != null) { + if (user.removePackage(packageName) != null) { doNotify = true; } } @@ -1761,7 +1766,7 @@ public class ShortcutService extends IShortcutService.Stub { // Now there may be orphan shortcuts because we removed pinned shortcuts at the previous // step. Remove them too. - user.forAllPackages(p -> p.refreshPinnedFlags(this)); + user.forAllPackages(p -> p.refreshPinnedFlags()); scheduleSaveUser(owningUserId); @@ -1797,7 +1802,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) - .attemptToRestoreIfNeededAndSave(ShortcutService.this); + .attemptToRestoreIfNeededAndSave(); if (packageName != null) { getShortcutsInnerLocked(launcherUserId, @@ -1822,7 +1827,13 @@ public class ShortcutService extends IShortcutService.Stub { final ArraySet ids = shortcutIds == null ? null : new ArraySet<>(shortcutIds); - getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret, + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return; // No need to instantiate ShortcutPackage. + } + + p.findAll(ret, (ShortcutInfo si) -> { if (si.getLastChangedTimestamp() < changedSince) { return false; @@ -1854,7 +1865,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) - .attemptToRestoreIfNeededAndSave(ShortcutService.this); + .attemptToRestoreIfNeededAndSave(); final ShortcutInfo si = getShortcutInfoLocked( launcherUserId, callingPackage, packageName, shortcutId, userId); @@ -1868,9 +1879,14 @@ public class ShortcutService extends IShortcutService.Stub { Preconditions.checkStringNotEmpty(packageName, "packageName"); Preconditions.checkStringNotEmpty(shortcutId, "shortcutId"); + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return null; + } + final ArrayList list = new ArrayList<>(1); - getPackageShortcutsLocked(packageName, userId).findAll( - ShortcutService.this, list, + p.findAll(list, (ShortcutInfo si) -> shortcutId.equals(si.getId()), /* clone flags=*/ 0, callingPackage, launcherUserId); return list.size() == 0 ? null : list.get(0); @@ -1887,10 +1903,9 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { final ShortcutLauncher launcher = getLauncherShortcutsLocked(callingPackage, userId, launcherUserId); - launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this); + launcher.attemptToRestoreIfNeededAndSave(); - launcher.pinShortcuts( - ShortcutService.this, userId, packageName, shortcutIds); + launcher.pinShortcuts(userId, packageName, shortcutIds); } packageShortcutsChanged(packageName, userId); } @@ -1905,7 +1920,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) - .attemptToRestoreIfNeededAndSave(ShortcutService.this); + .attemptToRestoreIfNeededAndSave(); // Make sure the shortcut is actually visible to the launcher. final ShortcutInfo si = getShortcutInfoLocked( @@ -1934,10 +1949,15 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) - .attemptToRestoreIfNeededAndSave(ShortcutService.this); + .attemptToRestoreIfNeededAndSave(); - final ShortcutInfo shortcutInfo = getPackageShortcutsLocked( - packageName, userId).findShortcutById(shortcutId); + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return 0; + } + + final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); return (shortcutInfo != null && shortcutInfo.hasIconResource()) ? shortcutInfo.getIconResourceId() : 0; } @@ -1953,10 +1973,15 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { getLauncherShortcutsLocked(callingPackage, userId, launcherUserId) - .attemptToRestoreIfNeededAndSave(ShortcutService.this); + .attemptToRestoreIfNeededAndSave(); - final ShortcutInfo shortcutInfo = getPackageShortcutsLocked( - packageName, userId).findShortcutById(shortcutId); + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return null; + } + + final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); if (shortcutInfo == null || !shortcutInfo.hasIconFile()) { return null; } @@ -2000,8 +2025,14 @@ public class ShortcutService extends IShortcutService.Stub { // This allows ShortcutUser's to detect the system locale change, so they can reset // counters. - mLocaleChangeSequenceNumber.incrementAndGet(); - postToHandler(() -> scheduleSaveBaseState()); + // Ignore all callback during system boot. + if (mBootCompleted.get()) { + mLocaleChangeSequenceNumber.incrementAndGet(); + if (DEBUG) { + Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get()); + } + postToHandler(() -> scheduleSaveBaseState()); + } } } @@ -2056,7 +2087,7 @@ public class ShortcutService extends IShortcutService.Stub { if (versionCode >= 0) { // Package still installed, see if it's updated. getUserShortcutsLocked(ownerUserId).handlePackageUpdated( - this, spi.getPackageName(), versionCode); + spi.getPackageName(), versionCode); } else { gonePackages.add(PackageWithUser.of(spi)); } @@ -2093,7 +2124,7 @@ public class ShortcutService extends IShortcutService.Stub { if (versionCode < 0) { return; // shouldn't happen } - getUserShortcutsLocked(userId).handlePackageUpdated(this, packageName, versionCode); + getUserShortcutsLocked(userId).handlePackageUpdated(packageName, versionCode); } } @@ -2215,7 +2246,7 @@ public class ShortcutService extends IShortcutService.Stub { return null; } - user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave(this)); + user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave()); // Then save. final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024); @@ -2336,7 +2367,7 @@ public class ShortcutService extends IShortcutService.Stub { for (int i = 0; i < mUsers.size(); i++) { pw.println(); - mUsers.valueAt(i).dump(this, pw, " "); + mUsers.valueAt(i).dump(pw, " "); } pw.println(); @@ -2548,8 +2579,7 @@ public class ShortcutService extends IShortcutService.Stub { private void clearLauncher() { synchronized (mLock) { - getUserShortcutsLocked(mUserId).setLauncherComponent( - ShortcutService.this, null); + getUserShortcutsLocked(mUserId).setDefaultLauncherComponent(null); } } @@ -2559,7 +2589,7 @@ public class ShortcutService extends IShortcutService.Stub { hasShortcutHostPermissionInner("-", mUserId); getOutPrintWriter().println("Launcher: " - + getUserShortcutsLocked(mUserId).getLauncherComponent()); + + getUserShortcutsLocked(mUserId).getDefaultLauncherComponent()); } } diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 2efae8675b084..d38cfba2b1c07 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -16,6 +16,7 @@ package com.android.server.pm; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; import android.text.format.Formatter; @@ -87,6 +88,8 @@ class ShortcutUser { } } + final ShortcutService mService; + @UserIdInt private final int mUserId; @@ -97,11 +100,12 @@ class ShortcutUser { private final ArrayMap mLaunchers = new ArrayMap<>(); /** Default launcher that can access the launcher apps APIs. */ - private ComponentName mLauncherComponent; + private ComponentName mDefaultLauncherComponent; private long mKnownLocaleChangeSequenceNumber; - public ShortcutUser(int userId) { + public ShortcutUser(ShortcutService service, int userId) { + mService = service; mUserId = userId; } @@ -120,10 +124,10 @@ class ShortcutUser { return mPackages.containsKey(packageName); } - public ShortcutPackage removePackage(@NonNull ShortcutService s, @NonNull String packageName) { + public ShortcutPackage removePackage(@NonNull String packageName) { final ShortcutPackage removed = mPackages.remove(packageName); - s.cleanupBitmapsForPackage(mUserId, packageName); + mService.cleanupBitmapsForPackage(mUserId, packageName); return removed; } @@ -140,23 +144,33 @@ class ShortcutUser { launcher.getPackageName()), launcher); } + @Nullable public ShortcutLauncher removeLauncher( @UserIdInt int packageUserId, @NonNull String packageName) { return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName)); } - public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) { - ShortcutPackage ret = mPackages.get(packageName); - if (ret == null) { - ret = new ShortcutPackage(s, this, mUserId, packageName); - mPackages.put(packageName, ret); - } else { - ret.attemptToRestoreIfNeededAndSave(s); + @Nullable + public ShortcutPackage getPackageShortcutsIfExists(@NonNull String packageName) { + final ShortcutPackage ret = mPackages.get(packageName); + if (ret != null) { + ret.attemptToRestoreIfNeededAndSave(); } return ret; } - public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName, + @NonNull + public ShortcutPackage getPackageShortcuts(@NonNull String packageName) { + ShortcutPackage ret = getPackageShortcutsIfExists(packageName); + if (ret == null) { + ret = new ShortcutPackage(this, mUserId, packageName); + mPackages.put(packageName, ret); + } + return ret; + } + + @NonNull + public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName, @UserIdInt int launcherUserId) { final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName); ShortcutLauncher ret = mLaunchers.get(key); @@ -164,7 +178,7 @@ class ShortcutUser { ret = new ShortcutLauncher(this, mUserId, packageName, launcherUserId); mLaunchers.put(key, ret); } else { - ret.attemptToRestoreIfNeededAndSave(s); + ret.attemptToRestoreIfNeededAndSave(); } return ret; } @@ -201,8 +215,8 @@ class ShortcutUser { /** * Reset all throttling counters for all packages, if there has been a system locale change. */ - public void resetThrottlingIfNeeded(ShortcutService s) { - final long currentNo = s.getLocaleChangeSequenceNumber(); + public void resetThrottlingIfNeeded() { + final long currentNo = mService.getLocaleChangeSequenceNumber(); if (mKnownLocaleChangeSequenceNumber < currentNo) { if (ShortcutService.DEBUG) { Slog.d(TAG, "LocaleChange detected for user " + mUserId); @@ -210,31 +224,35 @@ class ShortcutUser { mKnownLocaleChangeSequenceNumber = currentNo; - forAllPackages(p -> p.resetRateLimiting(s)); + forAllPackages(p -> p.resetRateLimiting()); - s.scheduleSaveUser(mUserId); + mService.scheduleSaveUser(mUserId); } } /** * Called when a package is updated. */ - public void handlePackageUpdated(ShortcutService s, @NonNull String packageName, + public void handlePackageUpdated(@NonNull String packageName, int newVersionCode) { if (!mPackages.containsKey(packageName)) { return; } - getPackageShortcuts(s, packageName).handlePackageUpdated(s, newVersionCode); + final ShortcutPackage p = getPackageShortcutsIfExists(packageName); + if (p == null) { + return; // No need to instantiate ShortcutPackage. + } + p.handlePackageUpdated(newVersionCode); } public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName, @UserIdInt int packageUserId) { forPackageItem(packageName, packageUserId, spi -> { - spi.attemptToRestoreIfNeededAndSave(s); + spi.attemptToRestoreIfNeededAndSave(); }); } - public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup) + public void saveToXml(XmlSerializer out, boolean forBackup) throws IOException, XmlPullParserException { out.startTag(null, TAG_ROOT); @@ -242,29 +260,29 @@ class ShortcutUser { mKnownLocaleChangeSequenceNumber); ShortcutService.writeTagValue(out, TAG_LAUNCHER, - mLauncherComponent); + mDefaultLauncherComponent); // Can't use forEachPackageItem due to the checked exceptions. { final int size = mLaunchers.size(); for (int i = 0; i < size; i++) { - saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup); + saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup); } } { final int size = mPackages.size(); for (int i = 0; i < size; i++) { - saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup); + saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup); } } out.endTag(null, TAG_ROOT); } - private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out, + private void saveShortcutPackageItem(XmlSerializer out, ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException { if (forBackup) { - if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) { + if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) { return; // Don't save. } if (spi.getPackageUserId() != spi.getOwnerUserId()) { @@ -276,7 +294,7 @@ class ShortcutUser { public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId, boolean fromBackup) throws IOException, XmlPullParserException { - final ShortcutUser ret = new ShortcutUser(userId); + final ShortcutUser ret = new ShortcutUser(s, userId); ret.mKnownLocaleChangeSequenceNumber = ShortcutService.parseLongAttribute(parser, ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER); @@ -294,7 +312,7 @@ class ShortcutUser { if (depth == outerDepth + 1) { switch (tag) { case TAG_LAUNCHER: { - ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute( + ret.mDefaultLauncherComponent = ShortcutService.parseComponentNameAttribute( parser, ATTR_VALUE); continue; } @@ -319,16 +337,16 @@ class ShortcutUser { return ret; } - public ComponentName getLauncherComponent() { - return mLauncherComponent; + public ComponentName getDefaultLauncherComponent() { + return mDefaultLauncherComponent; } - public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) { - if (Objects.equal(mLauncherComponent, launcherComponent)) { + public void setDefaultLauncherComponent(ComponentName launcherComponent) { + if (Objects.equal(mDefaultLauncherComponent, launcherComponent)) { return; } - mLauncherComponent = launcherComponent; - s.scheduleSaveUser(mUserId); + mDefaultLauncherComponent = launcherComponent; + mService.scheduleSaveUser(mUserId); } public void resetThrottling() { @@ -337,7 +355,7 @@ class ShortcutUser { } } - public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) { + public void dump(@NonNull PrintWriter pw, @NonNull String prefix) { pw.print(prefix); pw.print("User: "); pw.print(mUserId); @@ -349,24 +367,24 @@ class ShortcutUser { pw.print(prefix); pw.print("Default launcher: "); - pw.print(mLauncherComponent); + pw.print(mDefaultLauncherComponent); pw.println(); for (int i = 0; i < mLaunchers.size(); i++) { - mLaunchers.valueAt(i).dump(s, pw, prefix); + mLaunchers.valueAt(i).dump(pw, prefix); } for (int i = 0; i < mPackages.size(); i++) { - mPackages.valueAt(i).dump(s, pw, prefix); + mPackages.valueAt(i).dump(pw, prefix); } pw.println(); pw.print(prefix); pw.println("Bitmap directories: "); - dumpDirectorySize(s, pw, prefix + " ", s.getUserBitmapFilePath(mUserId)); + dumpDirectorySize(pw, prefix + " ", mService.getUserBitmapFilePath(mUserId)); } - private void dumpDirectorySize(@NonNull ShortcutService s, @NonNull PrintWriter pw, + private void dumpDirectorySize(@NonNull PrintWriter pw, @NonNull String prefix, File path) { int numFiles = 0; long size = 0; @@ -377,7 +395,7 @@ class ShortcutUser { numFiles++; size += child.length(); } else if (child.isDirectory()) { - dumpDirectorySize(s, pw, prefix + " ", child); + dumpDirectorySize(pw, prefix + " ", child); } } } @@ -389,7 +407,7 @@ class ShortcutUser { pw.print(" files, size="); pw.print(size); pw.print(" ("); - pw.print(Formatter.formatFileSize(s.mContext, size)); + pw.print(Formatter.formatFileSize(mService.mContext, size)); pw.println(")"); } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java index 7fa0c331ebc0e..918fdabb313dd 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java @@ -3698,8 +3698,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals(2, mManager.getRemainingCallCount()); }); - mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setLauncherComponent( - mService, new ComponentName("pkg1", "class")); + mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setDefaultLauncherComponent( + new ComponentName("pkg1", "class")); // Restore. mService.saveDirtyInfo(); @@ -3732,7 +3732,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { }); assertEquals("pkg1", mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM) - .getLauncherComponent().getPackageName()); + .getDefaultLauncherComponent().getPackageName()); // Start another user mService.handleUnlockUser(USER_10); @@ -3748,7 +3748,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertEquals("title10-1-1", getCallerShortcut("s1").getTitle()); assertEquals("title10-1-2", getCallerShortcut("s2").getTitle()); }); - assertNull(mService.getShortcutsForTest().get(USER_10).getLauncherComponent()); + assertNull(mService.getShortcutsForTest().get(USER_10).getDefaultLauncherComponent()); // Try stopping the user mService.handleCleanupUser(USER_10); @@ -5578,8 +5578,12 @@ public class ShortcutManagerTest extends InstrumentationTestCase { final long origSequenceNumber = mService.getLocaleChangeSequenceNumber(); + // onSystemLocaleChangedNoLock before boot completed will be ignored. mInternal.onSystemLocaleChangedNoLock(); + assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber()); + mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + mInternal.onSystemLocaleChangedNoLock(); assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber()); // Note at this point only user-0 is loaded, and the counters are reset for this user, @@ -5930,6 +5934,10 @@ public class ShortcutManagerTest extends InstrumentationTestCase { IllegalArgumentException.class, "ID must be provided", () -> new ShortcutInfo.Builder(getTestContext()).build()); + assertExpectException( + NullPointerException.class, + "Intent action must be set", + () -> new ShortcutInfo.Builder(getTestContext()).setIntent(new Intent())); assertExpectException( IllegalArgumentException.class, "title must be provided",