diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 87dc0a17f41cc..bbcac56cf8afd 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -507,7 +507,8 @@ public class LauncherApps { /** * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to * register this callback, have been added or updated. - * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery) + * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, + * Executor) * *
Only the applications that are allowed to access the shortcut information, * as defined in {@link #hasShortcutHostPermission()}, will receive it. @@ -525,7 +526,8 @@ public class LauncherApps { /** * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to * register this callback, have been removed. - * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery) + * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, + * Executor) * *
Only the applications that are allowed to access the shortcut information,
* as defined in {@link #hasShortcutHostPermission()}, will receive it.
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 1d5c304388706..385ace8a511b4 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -746,9 +746,8 @@ public class LauncherAppsService extends SystemService {
}
UserHandle user = UserHandle.of(injectCallingUserId());
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- == PackageManager.PERMISSION_GRANTED) {
+ if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(),
+ injectBinderCallingUid())) {
user = null;
}
@@ -1053,29 +1052,6 @@ public class LauncherAppsService extends SystemService {
}
public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback {
-
- static class QueryInfo {
- final long mChangedSince;
- final String mPackage;
- final List shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2");
+ }
+
+ public void testShortcutChangeCallback_setDynamicShortcuts_replaceSameId() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s2", "s3")));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_setDynamicShortcuts_pinnedAndCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(
+ list(makeShortcut("s1"), makeLongLivedShortcut("s2"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s3", "s4")));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2", "s3", "s4");
+ }
+
+ public void testShortcutChangeCallback_pinShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_pinShortcuts_unpinOthers() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2", "s3")));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s1", "s2"));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_cacheShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s3");
+ }
+
+ public void testShortcutChangeCallback_uncacheShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2");
+ }
+
+ public void testShortcutChangeCallback_uncacheShortcuts_causeDeletion() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s2", "s3"));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0);
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s3");
+ }
+
+ public void testShortcutChangeCallback_updateShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"),
+ makeShortcutWithActivity("s2", new ComponentName(CALLING_PACKAGE_1, "test")))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ final ComponentName updatedCn = new ComponentName(CALLING_PACKAGE_1, "updated activity");
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.updateShortcuts(list(makeShortcutWithActivity("s2", updatedCn))));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2");
+ assertEquals(updatedCn, ((ShortcutInfo) shortcuts.getValue().get(0)).getActivity());
+ }
+
+ public void testShortcutChangeCallback_addDynamicShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.addDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2");
+ }
+
+ public void testShortcutChangeCallback_pushDynamicShortcut() {
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.pushDynamicShortcut(makeShortcut("s1"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_pushDynamicShortcut_existingId() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2", "s3", "s4", "s5",
+ "s6", "s7", "s8", "s9", "s10"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.pushDynamicShortcut(makeShortcut("s5"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s5");
+ }
+
+ public void testShortcutChangeCallback_pushDynamicShortcut_causeDeletion() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2", "s3", "s4", "s5",
+ "s6", "s7", "s8", "s9", "s10"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.pushDynamicShortcut(makeShortcut("s11"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s11");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s10");
+ }
+
+ public void testShortcutChangeCallback_pushDynamicShortcut_causeDeletionButCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts((makeShortcuts("s1", "s2", "s3", "s4", "s5",
+ "s6", "s7", "s8", "s9"))));
+ ShortcutInfo s10 = makeLongLivedShortcut("s10");
+ s10.setRank(10);
+ mManager.pushDynamicShortcut(s10); // Add a long lived shortcut to the end of the list.
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s10"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.pushDynamicShortcut(makeShortcut("s11"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s10", "s11");
+ }
+
+ public void testShortcutChangeCallback_disableShortcuts() {
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.disableShortcuts(list("s2"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ verify(callback, times(0)).onShortcutsAddedOrUpdated(any(), any(), any());
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2");
+ }
+
+ public void testShortcutChangeCallback_disableShortcuts_pinnedAndCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(
+ list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.disableShortcuts(list("s1", "s2", "s3"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_enableShortcuts() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(
+ list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.disableShortcuts(list("s1", "s2", "s3"));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.enableShortcuts(list("s1", "s2", "s3"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+ verify(callback, times(0)).onShortcutsRemoved(any(), any(), any());
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+ }
+
+ public void testShortcutChangeCallback_removeDynamicShortcuts() {
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s2"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ verify(callback, times(0)).onShortcutsAddedOrUpdated(any(), any(), any());
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2");
+ }
+
+ public void testShortcutChangeCallback_removeDynamicShortcuts_pinnedAndCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeDynamicShortcuts(list("s1", "s2", "s3"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_removeAllDynamicShortcuts() {
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(makeShortcuts("s1", "s2")));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeAllDynamicShortcuts();
+ });
+
+ mTestLooper.dispatchAll();
+
+ verify(callback, times(0)).onShortcutsAddedOrUpdated(any(), any(), any());
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2");
+ }
+
+ public void testShortcutChangeCallback_removeAllDynamicShortcuts_pinnedAndCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(
+ list(makeShortcut("s1"), makeLongLivedShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeAllDynamicShortcuts();
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s2", "s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1");
+ }
+
+ public void testShortcutChangeCallback_removeLongLivedShortcuts_notCached() {
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeLongLivedShortcuts(list("s1", "s2"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ verify(callback, times(0)).onShortcutsAddedOrUpdated(any(), any(), any());
+
+ ArgumentCaptor
shortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(shortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2");
+ }
+
+ public void testShortcutChangeCallback_removeLongLivedShortcuts_pinnedAndCached() {
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"),
+ makeLongLivedShortcut("s2"), makeShortcut("s3"), makeShortcut("s4"))));
+ });
+
+ ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+ mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL,
+ mTestLooper.getNewExecutor());
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.removeLongLivedShortcuts(list("s1", "s2", "s3"));
+ });
+
+ mTestLooper.dispatchAll();
+
+ ArgumentCaptor
changedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsAddedOrUpdated(
+ eq(CALLING_PACKAGE_1), changedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ ArgumentCaptor
removedShortcuts = ArgumentCaptor.forClass(List.class);
+ verify(callback, times(1)).onShortcutsRemoved(
+ eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0));
+
+ assertWith(changedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s3");
+
+ assertWith(removedShortcuts.getValue())
+ .areAllWithKeyFieldsOnly()
+ .haveIds("s1", "s2");
+ }
+
+ private static ShortcutQuery createShortcutQuery(int queryFlags) {
+ ShortcutQuery q = new ShortcutQuery();
+ return q.setQueryFlags(ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED);
+ }
+}