Refactoring ShortcutManager + bug fixes.
- Don't pass the ShortcutService instance as an argument. This tiny optimization is no longer meaningful now that PackageShortcut and PackageLauncher have reference to ShortcutUser. - Rename mLauncherComponent to mDefaultLauncherComponent for clarity. - Don't instantiate ShortcutPackage instances when not needed. - Don't allow intents with a null action. - Also improve javadoc. Bug 28592642 Bug 28474517 Bug 28557169 Change-Id: I8790d3494bf3b92c143c02824b0ed0e514504baa
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
*
|
||||
* <h3>Backup and Restore</h3>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* <p>Note that:
|
||||
* <ul>
|
||||
* <li>Dynamic shortcuts will not be backed up or restored.
|
||||
* <li>Icons of pinned shortcuts will <b>not</b> be backed up for performance reasons, unless
|
||||
* they refer to resources. Instead, launcher applications are supposed to back up and restore
|
||||
* icons of pinned shortcuts by themselves, and thus from the user's point of view, pinned
|
||||
* shortcuts will look to have icons restored.
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <h3>APIs for launcher</h3>
|
||||
*
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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<String> shortcutIds) {
|
||||
try {
|
||||
|
||||
@@ -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<PackageWithUser> 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<String> 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();
|
||||
|
||||
@@ -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<String> 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 {
|
||||
*
|
||||
* <p>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<String> 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 {
|
||||
* <p>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 {
|
||||
* <p>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<ShortcutInfo> result,
|
||||
public void findAll(@NonNull List<ShortcutInfo> result,
|
||||
@Nullable Predicate<ShortcutInfo> 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<ShortcutInfo> result,
|
||||
public void findAll(@NonNull List<ShortcutInfo> result,
|
||||
@Nullable Predicate<ShortcutInfo> 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<String> 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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<String> 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<ShortcutInfo> 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<String> 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<ShortcutInfo> 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PackageWithUser, ShortcutLauncher> 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(")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user