Merge "ShortcutManager: Clean up for uninstalled packages." into nyc-dev
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user