Merge "ShortcutManager: Clean up for uninstalled packages." into nyc-dev

This commit is contained in:
Makoto Onuki
2016-03-22 00:12:04 +00:00
committed by Android (Google) Code Review
3 changed files with 453 additions and 22 deletions

View File

@@ -53,6 +53,7 @@ import android.os.ResultReceiver;
import android.os.SELinux;
import android.os.ShellCommand;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.format.Time;
@@ -67,6 +68,7 @@ import android.util.Xml;
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.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -99,6 +101,11 @@ import java.util.function.Predicate;
*
* - Default launcher check does take a few ms. Worth caching.
*
* - Allow non-default launcher to start pinned shortcuts. (but not dynamic.)
*
* - Extract the user/package/launcher classes to their own files. Maybe rename so they all have
* the same "Shortcut" prefix.
*
* - Listen to PACKAGE_*, remove orphan info, update timestamp for icon res
* -> Need to scan all packages when a user starts too.
* -> Clear data -> remove all dynamic? but not the pinned?
@@ -243,6 +250,7 @@ public class ShortcutService extends IShortcutService.Stub {
private int mSaveDelayMillis;
private final PackageManagerInternal mPackageManagerInternal;
private final UserManager mUserManager;
@GuardedBy("mLock")
private List<Integer> mDirtyUserIds = new ArrayList<>();
@@ -257,6 +265,9 @@ public class ShortcutService extends IShortcutService.Stub {
LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
mHandler = new Handler(looper);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mUserManager = context.getSystemService(UserManager.class);
mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
}
/**
@@ -282,16 +293,12 @@ public class ShortcutService extends IShortcutService.Stub {
@Override
public void onCleanupUser(int userHandle) {
synchronized (mService.mLock) {
mService.onCleanupUserLocked(userHandle);
}
mService.handleCleanupUser(userHandle);
}
@Override
public void onUnlockUser(int userId) {
synchronized (mService.mLock) {
mService.onStartUserLocked(userId);
}
mService.handleUnlockUser(userId);
}
}
@@ -308,13 +315,24 @@ public class ShortcutService extends IShortcutService.Stub {
}
/** lifecycle event */
void onStartUserLocked(int userId) {
// Preload
getUserShortcutsLocked(userId);
void handleUnlockUser(int userId) {
synchronized (mLock) {
// Preload
getUserShortcutsLocked(userId);
}
}
/** lifecycle event */
void onCleanupUserLocked(int userId) {
void handleCleanupUser(int userId) {
synchronized (mLock) {
unloadUserLocked(userId);
}
}
private void unloadUserLocked(int userId) {
if (DEBUG) {
Slog.d(TAG, "unloadUserLocked: user=" + userId);
}
// Save all dirty information.
saveDirtyInfo();
@@ -752,6 +770,12 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
@GuardedBy("mLock")
@NonNull
boolean isUserLoadedLocked(@UserIdInt int userId) {
return mUsers.get(userId) != null;
}
/** Return the per-user state. */
@GuardedBy("mLock")
@NonNull
@@ -1047,6 +1071,9 @@ public class ShortcutService extends IShortcutService.Stub {
}
private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
if (!mUserManager.isUserRunning(userId)) {
return;
}
postToHandler(() -> {
final ArrayList<ShortcutChangeListener> copy;
synchronized (mLock) {
@@ -1420,6 +1447,44 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
// === House keeping ===
@VisibleForTesting
void cleanUpPackageLocked(String packageName, int userId) {
final boolean wasUserLoaded = isUserLoadedLocked(userId);
final UserShortcuts mUser = getUserShortcutsLocked(userId);
boolean doNotify = false;
// First, remove the package from the package list (if the package is a publisher).
if (mUser.getPackages().remove(packageName) != null) {
doNotify = true;
}
// Also remove from the launcher list (if the package is a launcher).
mUser.getLaunchers().remove(packageName);
// Then remove pinned shortcuts from all launchers.
for (int i = mUser.getLaunchers().size() - 1; i >= 0; i--) {
mUser.getLaunchers().valueAt(i).cleanUpPackage(packageName);
}
// Now there may be orphan shortcuts because we removed pinned shortucts at the previous
// step. Remove them too.
for (int i = mUser.getPackages().size() - 1; i >= 0; i--) {
mUser.getPackages().valueAt(i).refreshPinnedFlags(this);
}
scheduleSaveUser(userId);
if (doNotify) {
notifyListeners(packageName, userId);
}
if (!wasUserLoaded) {
// Note this will execute the scheduled save.
unloadUserLocked(userId);
}
}
/**
* Entry point from {@link LauncherApps}.
*/
@@ -1575,6 +1640,50 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
private PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
handlePackageUpdateFinished(packageName, getChangingUserId());
}
@Override
public void onPackageRemoved(String packageName, int uid) {
handlePackageRemoved(packageName, getChangingUserId());
}
@Override
public void onPackageRemovedAllUsers(String packageName, int uid) {
handlePackageRemovedAllUsers(packageName, getChangingUserId());
}
};
void handlePackageUpdateFinished(String packageName, @UserIdInt int userId) {
if (DEBUG) {
Slog.d(TAG, "onPackageUpdateFinished() userId=" + userId);
}
// TODO Update the version.
}
void handlePackageRemoved(String packageName, @UserIdInt int userId) {
if (DEBUG) {
Slog.d(TAG, "onPackageRemoved() userId=" + userId);
}
synchronized (mLock) {
cleanUpPackageLocked(packageName, userId);
}
}
void handlePackageRemovedAllUsers(String packageName, @UserIdInt int userId) {
if (DEBUG) {
Slog.d(TAG, "onPackageRemovedAllUsers() userId=" + userId);
}
synchronized (mLock) {
cleanUpPackageLocked(packageName, userId);
}
// TODO Remove from all users, which we can't if the user is locked.
}
// === Dump ===
@Override
@@ -1913,7 +2022,13 @@ public class ShortcutService extends IShortcutService.Stub {
@VisibleForTesting
ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
synchronized (mLock) {
return getPackageShortcutsLocked(packageName, userId).findShortcutById(shortcutId);
final UserShortcuts user = mUsers.get(userId);
if (user == null) return null;
final PackageShortcuts pkg = user.getPackages().get(packageName);
if (pkg == null) return null;
return pkg.findShortcutById(shortcutId);
}
}
}
@@ -2131,15 +2246,23 @@ class LauncherShortcuts {
return mPinnedShortcuts.get(packageName);
}
boolean cleanUpPackage(String packageName) {
return mPinnedShortcuts.remove(packageName) != null;
}
/**
* Persist.
*/
public void saveToXml(XmlSerializer out) throws IOException {
final int size = mPinnedShortcuts.size();
if (size == 0) {
return; // Nothing to write.
}
out.startTag(null, TAG_ROOT);
ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
mPackageName);
final int size = mPinnedShortcuts.size();
for (int i = 0; i < size; i++) {
out.startTag(null, TAG_PACKAGE);
ShortcutService.writeAttr(out, ATTR_PACKAGE_NAME,
@@ -2357,7 +2480,7 @@ class PackageShortcuts {
removeList.add(si.getId());
}
if (removeList != null) {
for (int i = removeList.size() - 1 ; i >= 0; i--) {
for (int i = removeList.size() - 1; i >= 0; i--) {
deleteShortcut(s, removeList.get(i));
}
}
@@ -2569,6 +2692,12 @@ class PackageShortcuts {
}
public void saveToXml(@NonNull XmlSerializer out) throws IOException, XmlPullParserException {
final int size = mShortcuts.size();
if (size == 0 && mApiCallCount == 0) {
return; // nothing to write.
}
out.startTag(null, TAG_ROOT);
ShortcutService.writeAttr(out, ATTR_NAME, mPackageName);
@@ -2576,7 +2705,6 @@ class PackageShortcuts {
ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
final int size = mShortcuts.size();
for (int j = 0; j < size; j++) {
saveShortcut(out, mShortcuts.valueAt(j));
}

View File

@@ -78,7 +78,7 @@ class ShortcutManager {
public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
ShortcutInfo shortcut = null;
// If the Shift key is preesed, then search for the shift shortcuts.
// If the Shift key is pressed, then search for the shift shortcuts.
boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts;

View File

@@ -22,6 +22,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
@@ -56,6 +57,7 @@ import android.os.UserManager;
import android.test.InstrumentationTestCase;
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
@@ -123,6 +125,11 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
throw new UnsupportedOperationException();
}
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return getTestContext().getSystemServiceName(serviceClass);
}
@Override
public PackageManager getPackageManager() {
return mMockPackageManager;
@@ -231,7 +238,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
@Override
boolean injectIsLowRamDevice() {
return mInjectdIsLowRamDevice;
return mInjectedIsLowRamDevice;
}
@Override
@@ -343,7 +350,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
private long mInjectedCurrentTimeLillis;
private boolean mInjectdIsLowRamDevice;
private boolean mInjectedIsLowRamDevice;
private int mInjectedCallingUid;
private String mInjectedClientPackage;
@@ -657,6 +664,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
return new ComponentName(mClientContext, clazz);
}
private <T> Set<T> makeSet(T... values) {
final HashSet<T> ret = new HashSet<>();
for (T s : values) {
ret.add(s);
}
return ret;
}
@NonNull
private ShortcutInfo findById(List<ShortcutInfo> list, String id) {
for (ShortcutInfo s : list) {
@@ -841,6 +856,14 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
}
private void assertShortcutExists(String packageName, String shortcutId, int userId) {
assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
}
private void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
}
private ShortcutInfo getPackageShortcut(String packageName, String shortcutId) {
return getPackageShortcut(packageName, shortcutId, getCallingUserId());
}
@@ -849,6 +872,27 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
}
private List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
final List<ShortcutInfo>[] ret = new List[1];
runWithCaller(launcher, userId, () -> {
final ShortcutQuery q = new ShortcutQuery();
q.setQueryFlags(queryFlags);
ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
});
return ret[0];
}
private List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
}
/**
* Wrap a set in an ArraySet just to get a better toString.
*/
private <T> Set<T> set(Set<T> in) {
return new ArraySet<T>(in);
}
/**
* Test for the first launch path, no settings file available.
*/
@@ -857,7 +901,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
}
/**
* Test for {@link ShortcutService#updateTimes()}
* Test for {@link ShortcutService#getLastResetTimeLocked()} and
* {@link ShortcutService#getNextResetTimeLocked()}.
*/
public void testUpdateAndGetNextResetTimeLocked() {
assertResetTimes(START_TIME, START_TIME + INTERVAL);
@@ -928,7 +973,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
assertEquals(75, mService.getIconPersistQualityForTest());
mInjectdIsLowRamDevice = true;
mInjectedIsLowRamDevice = true;
mService.updateConfigurationLocked(
ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+ ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
@@ -2205,6 +2250,8 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// TODO Add "multi" version -- run the test with two launchers and make sure the callback
// argument only contains the ones that are actually visible to each launcher.
when(mMockUserManager.isUserRunning(eq(USER_0))).thenReturn(true);
LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
// Set listeners
@@ -2320,6 +2367,20 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
eq(UserHandle.of(USER_0))
);
assertEquals(0, shortcuts.getValue().size());
// Remove CALLING_PACKAGE_2
reset(c0);
mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0);
// Should get a callback with an empty list.
waitOnMainThread();
shortcuts = ArgumentCaptor.forClass(List.class);
verify(c0).onShortcutsChanged(
eq(CALLING_PACKAGE_2),
shortcuts.capture(),
eq(UserHandle.of(USER_0))
);
assertEquals(0, shortcuts.getValue().size());
}
// === Test for persisting ===
@@ -2436,7 +2497,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertEquals(0, mService.getShortcutsForTest().size());
// this will pre-load the per-user info.
mService.onStartUserLocked(UserHandle.USER_SYSTEM);
mService.handleUnlockUser(UserHandle.USER_SYSTEM);
// Now it's loaded.
assertEquals(1, mService.getShortcutsForTest().size());
@@ -2462,7 +2523,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
.getLauncherComponent().getPackageName());
// Start another user
mService.onStartUserLocked(USER_10);
mService.handleUnlockUser(USER_10);
// Now the size is 2.
assertEquals(2, mService.getShortcutsForTest().size());
@@ -2478,7 +2539,7 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
assertNull(mService.getShortcutsForTest().get(USER_10).getLauncherComponent());
// Try stopping the user
mService.onCleanupUserLocked(USER_10);
mService.handleCleanupUser(USER_10);
// Now it's unloaded.
assertEquals(1, mService.getShortcutsForTest().size());
@@ -2486,6 +2547,248 @@ public class ShortcutManagerTest extends InstrumentationTestCase {
// TODO Check all other fields
}
public void testCleanupPackage() {
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
makeShortcut("s0_1"))));
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
makeShortcut("s0_2"))));
});
runWithCaller(LAUNCHER_1, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s0_1"),
UserHandle.of(USER_0));
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s0_2"),
UserHandle.of(USER_0));
});
runWithCaller(LAUNCHER_2, USER_0, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s0_1"),
UserHandle.of(USER_0));
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s0_2"),
UserHandle.of(USER_0));
});
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
makeShortcut("s10_1"))));
});
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
makeShortcut("s10_2"))));
});
runWithCaller(LAUNCHER_1, USER_10, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s10_1"),
UserHandle.of(USER_10));
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s10_2"),
UserHandle.of(USER_10));
});
runWithCaller(LAUNCHER_2, USER_10, () -> {
mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s10_1"),
UserHandle.of(USER_10));
mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList("s10_2"),
UserHandle.of(USER_10));
});
// Remove all dynamic shortcuts; now all shortcuts are just pinned.
runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
mManager.deleteAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
mManager.deleteAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
mManager.deleteAllDynamicShortcuts();
});
runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
mManager.deleteAllDynamicShortcuts();
});
final SparseArray<UserShortcuts> users = mService.getShortcutsForTest();
assertEquals(2, users.size());
assertEquals(USER_0, users.keyAt(0));
assertEquals(USER_10, users.keyAt(1));
final UserShortcuts user0 = users.get(USER_0);
final UserShortcuts user10 = users.get(USER_10);
// Check the registered packages.
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
"s10_1", "s10_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
"s10_1", "s10_2");
assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// Nonexistent package.
mService.cleanUpPackageLocked("abc", USER_0);
// No changes.
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_1", "s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
"s10_1", "s10_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
"s10_1", "s10_2");
assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// Remove a package.
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
"s10_1", "s10_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
"s10_1", "s10_2");
assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// Remove a launcher.
mService.cleanUpPackageLocked(LAUNCHER_1, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(LAUNCHER_2),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
"s10_1", "s10_2");
assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// Remove a package.
mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(LAUNCHER_2),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
"s10_1");
assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// Remove the other launcher from user 10 too.
mService.cleanUpPackageLocked(LAUNCHER_2, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(CALLING_PACKAGE_1),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_2");
// Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
// More remove.
mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10);
assertEquals(makeSet(CALLING_PACKAGE_2),
set(user0.getPackages().keySet()));
assertEquals(makeSet(),
set(user10.getPackages().keySet()));
assertEquals(makeSet(LAUNCHER_1, LAUNCHER_2),
set(user0.getLaunchers().keySet()));
assertEquals(makeSet(),
set(user10.getLaunchers().keySet()));
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
"s0_2");
assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
"s0_2");
// Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
mService.saveDirtyInfo();
}
// TODO Detailed test for hasShortcutPermissionInner().
// TODO Add tests for the command line functions too.