summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mady Mellor <madym@google.com> 2024-07-09 20:36:30 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-07-09 20:36:30 +0000
commit6d980605554de666fb00a3e44b4e397de2b7a8ad (patch)
tree526d032a3e0f9639478636482ce80c5abe3cd46c
parent78deee1a013c06e3cd54c81a47b4a9709f02b3cf (diff)
parent34326c14dbb213c1e6ebf2ad12aa7bf5adf03a8d (diff)
Merge changes I610545fd,I3c0d2677 into main
* changes: Update NoMan's ShortcutHelper to use ShortcutChangeCallback Add way to remove shortcut changed callbacks to shortcut service
-rw-r--r--core/java/android/content/pm/ShortcutServiceInternal.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java6
-rw-r--r--services/core/java/com/android/server/notification/ShortcutHelper.java162
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java8
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java43
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java212
6 files changed, 240 insertions, 194 deletions
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 55d0bc1deedc..c811a47e5b05 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -91,6 +91,9 @@ public abstract class ShortcutServiceInternal {
public abstract void addShortcutChangeCallback(
@NonNull LauncherApps.ShortcutChangeCallback callback);
+ public abstract void removeShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback);
+
public abstract int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1c40f44b7b78..9e53cc357ea4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8658,8 +8658,7 @@ public class NotificationManagerService extends SystemService {
mAttentionHelper.updateLightsLocked();
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
- true /* isRemoved */,
- mHandler);
+ true /* isRemoved */);
}
} else {
if (notificationForceGrouping()) {
@@ -9116,8 +9115,7 @@ public class NotificationManagerService extends SystemService {
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
- false /* isRemoved */,
- mHandler);
+ false /* isRemoved */);
}
maybeRecordInterruptionLocked(r);
diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java
index 86dcecf9290a..857e3198d55b 100644
--- a/services/core/java/com/android/server/notification/ShortcutHelper.java
+++ b/services/core/java/com/android/server/notification/ShortcutHelper.java
@@ -27,7 +27,6 @@ import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.os.Binder;
-import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -65,85 +64,34 @@ public class ShortcutHelper {
void onShortcutRemoved(String key);
}
+ private final ShortcutListener mShortcutListener;
private LauncherApps mLauncherAppsService;
- private ShortcutListener mShortcutListener;
private ShortcutServiceInternal mShortcutServiceInternal;
private UserManager mUserManager;
- // Key: packageName Value: <shortcutId, notifId>
- private HashMap<String, HashMap<String, String>> mActiveShortcutBubbles = new HashMap<>();
- private boolean mLauncherAppsCallbackRegistered;
+ // Key: packageName|userId Value: <shortcutId, notifId>
+ private final HashMap<String, HashMap<String, String>> mActiveShortcutBubbles = new HashMap<>();
+ private boolean mShortcutChangedCallbackRegistered;
// Bubbles can be created based on a shortcut, we need to listen for changes to
// that shortcut so that we may update the bubble appropriately.
- private final LauncherApps.Callback mLauncherAppsCallback = new LauncherApps.Callback() {
- @Override
- public void onPackageRemoved(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackageAdded(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackageChanged(String packageName, UserHandle user) {
- }
-
- @Override
- public void onPackagesAvailable(String[] packageNames, UserHandle user,
- boolean replacing) {
- }
-
- @Override
- public void onPackagesUnavailable(String[] packageNames, UserHandle user,
- boolean replacing) {
- }
+ private final LauncherApps.ShortcutChangeCallback mShortcutChangeCallback =
+ new LauncherApps.ShortcutChangeCallback() {
- @Override
- public void onShortcutsChanged(@NonNull String packageName,
- @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
- HashMap<String, String> shortcutBubbles = mActiveShortcutBubbles.get(packageName);
- ArrayList<String> bubbleKeysToRemove = new ArrayList<>();
- if (shortcutBubbles != null) {
- // Copy to avoid a concurrent modification exception when we remove bubbles from
- // shortcutBubbles.
- final Set<String> shortcutIds = new HashSet<>(shortcutBubbles.keySet());
-
- // If we can't find one of our bubbles in the shortcut list, that bubble needs
- // to be removed.
- for (String shortcutId : shortcutIds) {
- boolean foundShortcut = false;
- for (int i = 0; i < shortcuts.size(); i++) {
- if (shortcuts.get(i).getId().equals(shortcutId)) {
- foundShortcut = true;
- break;
- }
- }
- if (!foundShortcut) {
- bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
- shortcutBubbles.remove(shortcutId);
- if (shortcutBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(packageName);
- if (mLauncherAppsCallbackRegistered
- && mActiveShortcutBubbles.isEmpty()) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
- }
- }
- }
+ @Override
+ public void onShortcutsAddedOrUpdated(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
}
- }
- // Let NoMan know about the updates
- for (int i = 0; i < bubbleKeysToRemove.size(); i++) {
- // update flag bubble
- String bubbleKey = bubbleKeysToRemove.get(i);
- if (mShortcutListener != null) {
- mShortcutListener.onShortcutRemoved(bubbleKey);
+ public void onShortcutsRemoved(@NonNull String packageName,
+ @NonNull List<ShortcutInfo> removedShortcuts, @NonNull UserHandle user) {
+ final String packageUserKey = getPackageUserKey(packageName, user);
+ if (mActiveShortcutBubbles.get(packageUserKey) == null) return;
+ for (ShortcutInfo info : removedShortcuts) {
+ onShortcutRemoved(packageUserKey, info.getId());
+ }
}
- }
- }
- };
+ };
ShortcutHelper(LauncherApps launcherApps, ShortcutListener listener,
ShortcutServiceInternal shortcutServiceInternal, UserManager userManager) {
@@ -172,14 +120,14 @@ public class ShortcutHelper {
* Returns whether the given shortcut info is a conversation shortcut.
*/
public static boolean isConversationShortcut(
- ShortcutInfo shortcutInfo, ShortcutServiceInternal mShortcutServiceInternal,
+ ShortcutInfo shortcutInfo, ShortcutServiceInternal shortcutServiceInternal,
int callingUserId) {
if (shortcutInfo == null || !shortcutInfo.isLongLived() || !shortcutInfo.isEnabled()) {
return false;
}
// TODO (b/155016294) uncomment when sharing shortcuts are required
/*
- mShortcutServiceInternal.isSharingShortcut(callingUserId, "android",
+ shortcutServiceInternal.isSharingShortcut(callingUserId, "android",
shortcutInfo.getPackage(), shortcutInfo.getId(), shortcutInfo.getUserId(),
SHARING_FILTER);
*/
@@ -233,34 +181,30 @@ public class ShortcutHelper {
*
* @param r the notification record to check
* @param removedNotification true if this notification is being removed
- * @param handler handler to register the callback with
*/
void maybeListenForShortcutChangesForBubbles(NotificationRecord r,
- boolean removedNotification,
- Handler handler) {
+ boolean removedNotification) {
final String shortcutId = r.getNotification().getBubbleMetadata() != null
? r.getNotification().getBubbleMetadata().getShortcutId()
: null;
+ final String packageUserKey = getPackageUserKey(r.getSbn().getPackageName(), r.getUser());
if (!removedNotification
&& !TextUtils.isEmpty(shortcutId)
&& r.getShortcutInfo() != null
&& r.getShortcutInfo().getId().equals(shortcutId)) {
// Must track shortcut based bubbles in case the shortcut is removed
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
- r.getSbn().getPackageName());
+ packageUserKey);
if (packageBubbles == null) {
packageBubbles = new HashMap<>();
}
packageBubbles.put(shortcutId, r.getKey());
- mActiveShortcutBubbles.put(r.getSbn().getPackageName(), packageBubbles);
- if (!mLauncherAppsCallbackRegistered) {
- mLauncherAppsService.registerCallback(mLauncherAppsCallback, handler);
- mLauncherAppsCallbackRegistered = true;
- }
+ mActiveShortcutBubbles.put(packageUserKey, packageBubbles);
+ registerCallbackIfNeeded();
} else {
// No longer track shortcut
HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get(
- r.getSbn().getPackageName());
+ packageUserKey);
if (packageBubbles != null) {
if (!TextUtils.isEmpty(shortcutId)) {
packageBubbles.remove(shortcutId);
@@ -278,20 +222,62 @@ public class ShortcutHelper {
}
}
if (packageBubbles.isEmpty()) {
- mActiveShortcutBubbles.remove(r.getSbn().getPackageName());
+ mActiveShortcutBubbles.remove(packageUserKey);
}
}
- if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
+ unregisterCallbackIfNeeded();
+ }
+ }
+
+ private String getPackageUserKey(String packageName, UserHandle user) {
+ return packageName + "|" + user.getIdentifier();
+ }
+
+ private void onShortcutRemoved(String packageUserKey, String shortcutId) {
+ HashMap<String, String> shortcutBubbles = mActiveShortcutBubbles.get(packageUserKey);
+ ArrayList<String> bubbleKeysToRemove = new ArrayList<>();
+ if (shortcutBubbles != null) {
+ if (shortcutBubbles.containsKey(shortcutId)) {
+ bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId));
+ shortcutBubbles.remove(shortcutId);
+ if (shortcutBubbles.isEmpty()) {
+ mActiveShortcutBubbles.remove(packageUserKey);
+ unregisterCallbackIfNeeded();
+ }
}
+ notifyNoMan(bubbleKeysToRemove);
+ }
+ }
+
+ private void registerCallbackIfNeeded() {
+ if (!mShortcutChangedCallbackRegistered) {
+ mShortcutChangedCallbackRegistered = true;
+ mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeCallback);
+ }
+ }
+
+ private void unregisterCallbackIfNeeded() {
+ if (mShortcutChangedCallbackRegistered && mActiveShortcutBubbles.isEmpty()) {
+ mShortcutServiceInternal.removeShortcutChangeCallback(mShortcutChangeCallback);
+ mShortcutChangedCallbackRegistered = false;
}
}
void destroy() {
- if (mLauncherAppsCallbackRegistered) {
- mLauncherAppsService.unregisterCallback(mLauncherAppsCallback);
- mLauncherAppsCallbackRegistered = false;
+ if (mShortcutChangedCallbackRegistered) {
+ mShortcutServiceInternal.removeShortcutChangeCallback(mShortcutChangeCallback);
+ mShortcutChangedCallbackRegistered = false;
+ }
+ }
+
+ private void notifyNoMan(List<String> bubbleKeysToRemove) {
+ // Let NoMan know about the updates
+ for (int i = 0; i < bubbleKeysToRemove.size(); i++) {
+ // update flag bubble
+ String bubbleKey = bubbleKeysToRemove.get(i);
+ if (mShortcutListener != null) {
+ mShortcutListener.onShortcutRemoved(bubbleKey);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1cd77ffcedaa..4a60e452919f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3443,6 +3443,14 @@ public class ShortcutService extends IShortcutService.Stub {
}
@Override
+ public void removeShortcutChangeCallback(
+ @NonNull LauncherApps.ShortcutChangeCallback callback) {
+ synchronized (mServiceLock) {
+ mShortcutChangeCallbacks.remove(Objects.requireNonNull(callback));
+ }
+ }
+
+ @Override
public int getShortcutIconResId(int launcherUserId, @NonNull String callingPackage,
@NonNull String packageName, @NonNull String shortcutId, int userId) {
Objects.requireNonNull(callingPackage, "callingPackage");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 5d306e152ad7..c1f5a01a8c47 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -89,7 +89,6 @@ import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
-import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
@@ -838,13 +837,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Pretend the shortcut exists
List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(mPkg);
- when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
+ shortcutInfos.add(createMockConvoShortcut());
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
anyString(), anyInt(), any())).thenReturn(true);
@@ -11109,8 +11102,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
BUBBLE_PREFERENCE_ALL /* app */,
true /* channel */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata =
@@ -11131,7 +11124,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure we register the callback for shortcut changes
- verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ shortcutChangeCallback.capture());
// yes allowed, yes messaging w/shortcut, yes bubble
Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
@@ -11144,14 +11138,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Test: Remove the shortcut
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
- launcherAppsCallback.getValue().onShortcutsChanged(mPkg, emptyList(),
+ ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(createMockConvoShortcut());
+ shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts,
UserHandle.getUserHandleForUid(mUid));
waitForIdle();
// Verify:
// Make sure callback is unregistered
- verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
+ shortcutChangeCallback.getValue());
// We're no longer a bubble
NotificationRecord notif2 = mService.getNotificationRecord(
@@ -11169,8 +11166,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
BUBBLE_PREFERENCE_ALL /* app */,
true /* channel */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
// Messaging notification with shortcut info
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
@@ -11204,7 +11201,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure we register the callback for shortcut changes
- verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ shortcutChangeCallback.capture());
// yes allowed, yes messaging w/shortcut, yes bubble
Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification();
@@ -11223,7 +11221,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// Verify:
// Make sure callback is unregistered
- verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(
+ shortcutChangeCallback.getValue());
}
@Test
@@ -16263,4 +16262,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID);
}
+
+ private ShortcutInfo createMockConvoShortcut() {
+ ShortcutInfo info = mock(ShortcutInfo.class);
+ when(info.getPackage()).thenReturn(mPkg);
+ when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
+ when(info.getUserId()).thenReturn(USER_SYSTEM);
+ when(info.isLongLived()).thenReturn(true);
+ when(info.isEnabled()).thenReturn(true);
+ return info;
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
index a4fb16dc1adc..f008cb671e78 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java
@@ -22,17 +22,22 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+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.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
import android.app.Person;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.ShortcutQuery;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutQueryWrapper;
import android.content.pm.ShortcutServiceInternal;
+import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
@@ -50,11 +55,9 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
@SmallTest
@@ -64,7 +67,6 @@ public class ShortcutHelperTest extends UiServiceTestCase {
private static final String SHORTCUT_ID = "shortcut";
private static final String PKG = "pkg";
- private static final String KEY = "key";
private static final Person PERSON = mock(Person.class);
@Mock
@@ -75,19 +77,11 @@ public class ShortcutHelperTest extends UiServiceTestCase {
UserManager mUserManager;
@Mock
ShortcutServiceInternal mShortcutServiceInternal;
- @Mock
- NotificationRecord mNr;
- @Mock
- Notification mNotif;
- @Mock
- StatusBarNotification mSbn;
- @Mock
- Notification.BubbleMetadata mBubbleMetadata;
- @Mock
- ShortcutInfo mShortcutInfo;
@Captor private ArgumentCaptor<ShortcutQuery> mShortcutQueryCaptor;
+ NotificationRecord mNr;
+
ShortcutHelper mShortcutHelper;
@Before
@@ -96,137 +90,186 @@ public class ShortcutHelperTest extends UiServiceTestCase {
mShortcutHelper = new ShortcutHelper(
mLauncherApps, mShortcutListener, mShortcutServiceInternal, mUserManager);
- when(mSbn.getPackageName()).thenReturn(PKG);
- when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID);
- when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata);
- when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID);
when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
- setUpMockNotificationRecord(mNr, KEY);
+ mNr = setUpNotificationRecord(SHORTCUT_ID, PKG, UserHandle.of(UserHandle.USER_SYSTEM));
}
- private void setUpMockNotificationRecord(NotificationRecord mockRecord, String key) {
- when(mockRecord.getKey()).thenReturn(key);
- when(mockRecord.getSbn()).thenReturn(mSbn);
- when(mockRecord.getNotification()).thenReturn(mNotif);
- when(mockRecord.getShortcutInfo()).thenReturn(mShortcutInfo);
+ private NotificationRecord setUpNotificationRecord(String shortcutId,
+ String pkg,
+ UserHandle user) {
+ ShortcutInfo shortcutInfo = mock(ShortcutInfo.class);
+ when(shortcutInfo.getId()).thenReturn(shortcutId);
+ when(shortcutInfo.getUserHandle()).thenReturn(user);
+ when(shortcutInfo.isLongLived()).thenReturn(true);
+
+ Notification notification = new Notification.Builder(getContext())
+ .setContentTitle("title")
+ .setShortcutId(shortcutId)
+ .setBubbleMetadata(new Notification.BubbleMetadata.Builder(shortcutId).build())
+ .build();
+
+ StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, 0, null,
+ 1000, 2000, notification, user, null, System.currentTimeMillis());
+ NotificationRecord record = new NotificationRecord(mContext, sbn,
+ mock(NotificationChannel.class));
+ record.setShortcutInfo(shortcutInfo);
+ return record;
}
- private LauncherApps.Callback addShortcutBubbleAndVerifyListener() {
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ private LauncherApps.ShortcutChangeCallback addShortcutBubbleAndVerifyListener(
+ NotificationRecord record) {
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record, false /* removed */);
- ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback =
- ArgumentCaptor.forClass(LauncherApps.Callback.class);
+ ArgumentCaptor<LauncherApps.ShortcutChangeCallback> launcherAppsCallback =
+ ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class);
- verify(mLauncherApps, times(1)).registerCallback(
- launcherAppsCallback.capture(), any());
+ verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback(
+ launcherAppsCallback.capture());
return launcherAppsCallback.getValue();
}
@Test
public void testBubbleAdded_listenedAdded() {
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
}
@Test
+ public void testListenerNotifiedOnShortcutRemoved() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
+ verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+ }
+
+ @Test
+ public void testListenerNotNotified_notMatchingPackage() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved("differentPackage", removedShortcuts, mNr.getUser());
+ verify(mShortcutListener, never()).onShortcutRemoved(anyString());
+ }
+
+ @Test
+ public void testListenerNotNotified_notMatchingUser() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, UserHandle.of(10));
+ verify(mShortcutListener, never()).onShortcutRemoved(anyString());
+ }
+
+ @Test
+ public void testListenerNotifiedDifferentUser() {
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
+ NotificationRecord diffUserRecord = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(10));
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(diffUserRecord,
+ false /* removed */);
+
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
+ verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+
+ reset(mShortcutListener);
+ removedShortcuts.clear();
+ removedShortcuts.add(diffUserRecord.getShortcutInfo());
+
+ callback.onShortcutsRemoved(PKG, removedShortcuts, diffUserRecord.getUser());
+ verify(mShortcutListener).onShortcutRemoved(diffUserRecord.getKey());
+ }
+
+
+ @Test
public void testBubbleRemoved_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Then remove the notif
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- true /* removed */,
- null /* handler */);
+ true /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testBubbleNoLongerHasBubbleMetadata_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Then make it not a bubble
- when(mNotif.getBubbleMetadata()).thenReturn(null);
+ mNr.getNotification().setBubbleMetadata(null);
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testBubbleNoLongerHasShortcutId_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
+ addShortcutBubbleAndVerifyListener(mNr);
// Clear out shortcutId
- when(mBubbleMetadata.getShortcutId()).thenReturn(null);
+ mNr.getNotification().setBubbleMetadata(new Notification.BubbleMetadata.Builder(
+ mock(PendingIntent.class), mock(Icon.class)).build());
mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr,
- false /* removed */,
- null /* handler */);
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testNotifNoLongerHasShortcut_listenerRemoved() {
// First set it up to listen
- addShortcutBubbleAndVerifyListener();
-
- NotificationRecord validMock1 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock1, "KEY1");
-
- NotificationRecord validMock2 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock2, "KEY2");
+ addShortcutBubbleAndVerifyListener(mNr);
- NotificationRecord validMock3 = Mockito.mock(NotificationRecord.class);
- setUpMockNotificationRecord(validMock3, "KEY3");
+ NotificationRecord record1 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
+ NotificationRecord record2 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
+ NotificationRecord record3 = setUpNotificationRecord(SHORTCUT_ID, PKG,
+ UserHandle.of(UserHandle.USER_SYSTEM));
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock1,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record1,
+ false /* removed */);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock2,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record2,
+ false /* removed */);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock3,
- false /* removed */,
- null /* handler */);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record3,
+ false /* removed */);
- // Clear out shortcutId of the bubble in the middle, to double check that we don't hit a
+ // Clear out shortcutId of the bubble in the middle, to double-check that we don't hit a
// concurrent modification exception (removing the last bubble would sidestep that check).
- when(validMock2.getShortcutInfo()).thenReturn(null);
- mShortcutHelper.maybeListenForShortcutChangesForBubbles(validMock2,
- false /* removed */,
- null /* handler */);
+ record2.setShortcutInfo(null);
+ mShortcutHelper.maybeListenForShortcutChangesForBubbles(record2,
+ false /* removed */);
- verify(mLauncherApps, times(1)).unregisterCallback(any());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
public void testOnShortcutsChanged_listenerRemoved() {
// First set it up to listen
- LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
+ LauncherApps.ShortcutChangeCallback callback = addShortcutBubbleAndVerifyListener(mNr);
// App shortcuts are removed:
- callback.onShortcutsChanged(PKG, Collections.emptyList(), mock(UserHandle.class));
+ List<ShortcutInfo> removedShortcuts = new ArrayList<>();
+ removedShortcuts.add(mNr.getShortcutInfo());
+ callback.onShortcutsRemoved(PKG, removedShortcuts, mNr.getUser());
- verify(mLauncherApps, times(1)).unregisterCallback(any());
- }
-
- @Test
- public void testListenerNotifiedOnShortcutRemoved() {
- LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener();
-
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
-
- callback.onShortcutsChanged(PKG, shortcutInfos, mock(UserHandle.class));
- verify(mShortcutListener).onShortcutRemoved(mNr.getKey());
+ verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback(any());
}
@Test
@@ -321,7 +364,6 @@ public class ShortcutHelperTest extends UiServiceTestCase {
.isSameInstanceAs(si);
}
-
@Test
public void testGetValidShortcutInfo_isValidButUserLocked() {
ShortcutInfo si = mock(ShortcutInfo.class);