Loading services/core/java/com/android/server/notification/NotificationManagerService.java +48 −4 Original line number Diff line number Diff line Loading @@ -6243,6 +6243,7 @@ public class NotificationManagerService extends SystemService { private final int mRank; private final int mCount; private final ManagedServiceInfo mListener; private final long mWhen; CancelNotificationRunnable(final int callingUid, final int callingPid, final String pkg, final String tag, final int id, Loading @@ -6262,6 +6263,7 @@ public class NotificationManagerService extends SystemService { this.mRank = rank; this.mCount = count; this.mListener = listener; this.mWhen = System.currentTimeMillis(); } @Override Loading @@ -6273,13 +6275,28 @@ public class NotificationManagerService extends SystemService { } synchronized (mNotificationLock) { // If the notification is currently enqueued, repost this runnable so it has a // chance to notify listeners if ((findNotificationByListLocked(mEnqueuedNotifications, mPkg, mTag, mId, mUserId)) != null) { // Check to see if there is a notification in the enqueued list that hasn't had a // chance to post yet. List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria( mPkg, mTag, mId, mUserId); boolean repost = false; if (enqueued.size() > 0) { // Found something, let's see what it was repost = true; // If all enqueues happened before this cancel then wait for them to happen, // otherwise we should let this cancel through so the next enqueue happens for (NotificationRecord r : enqueued) { if (r.mUpdateTimeMs > mWhen) { // At least one enqueue was posted after the cancel, so we're invalid return; } } } if (repost) { mHandler.post(this); return; } // Look for the notification in the posted list, since we already checked enqueued. NotificationRecord r = findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); Loading @@ -6298,6 +6315,10 @@ public class NotificationManagerService extends SystemService { if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { return; } if (r.getUpdateTimeMs() > mWhen) { // In this case, a post must have slipped by when this runnable reposted return; } // Bubbled children get to stick around if the summary was manually cancelled // (user removed) from systemui. Loading Loading @@ -8220,6 +8241,29 @@ public class NotificationManagerService extends SystemService { return null; } /** * There may be multiple records that match your criteria. For instance if there have been * multiple notifications posted which are enqueued for the same pkg, tag, id, userId. This * method will find all of them in the given list * @return */ @GuardedBy("mNotificationLock") private List<NotificationRecord> findEnqueuedNotificationsForCriteria( String pkg, String tag, int id, int userId) { final ArrayList<NotificationRecord> records = new ArrayList<>(); final int n = mEnqueuedNotifications.size(); for (int i = 0; i < n; i++) { NotificationRecord r = mEnqueuedNotifications.get(i); if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag) && r.getSbn().getPackageName().equals(pkg)) { records.add(r); } } return records; } @GuardedBy("mNotificationLock") int indexOfNotificationLocked(String key) { final int N = mNotificationList.size(); Loading services/core/java/com/android/server/notification/NotificationRecord.java +4 −0 Original line number Diff line number Diff line Loading @@ -906,6 +906,10 @@ public final class NotificationRecord { return (int) (now - mInterruptionTimeMs); } public long getUpdateTimeMs() { return mUpdateTimeMs; } /** * Set the visibility of the notification. */ Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -1283,6 +1283,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, mService.getNotificationRecordCount()); } @Test public void testPostCancelPostNotifiesListeners() throws Exception { // WHEN a notification is posted final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); // THEN it is canceled mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); // THEN it is posted again (before the cancel has a chance to finish) mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected waitForIdle(); // The final enqueue made it to the listener instead of being canceled StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); assertEquals(1, notifs.length); assertEquals(1, mService.getNotificationRecordCount()); } @Test public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, PKG, Loading Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +48 −4 Original line number Diff line number Diff line Loading @@ -6243,6 +6243,7 @@ public class NotificationManagerService extends SystemService { private final int mRank; private final int mCount; private final ManagedServiceInfo mListener; private final long mWhen; CancelNotificationRunnable(final int callingUid, final int callingPid, final String pkg, final String tag, final int id, Loading @@ -6262,6 +6263,7 @@ public class NotificationManagerService extends SystemService { this.mRank = rank; this.mCount = count; this.mListener = listener; this.mWhen = System.currentTimeMillis(); } @Override Loading @@ -6273,13 +6275,28 @@ public class NotificationManagerService extends SystemService { } synchronized (mNotificationLock) { // If the notification is currently enqueued, repost this runnable so it has a // chance to notify listeners if ((findNotificationByListLocked(mEnqueuedNotifications, mPkg, mTag, mId, mUserId)) != null) { // Check to see if there is a notification in the enqueued list that hasn't had a // chance to post yet. List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria( mPkg, mTag, mId, mUserId); boolean repost = false; if (enqueued.size() > 0) { // Found something, let's see what it was repost = true; // If all enqueues happened before this cancel then wait for them to happen, // otherwise we should let this cancel through so the next enqueue happens for (NotificationRecord r : enqueued) { if (r.mUpdateTimeMs > mWhen) { // At least one enqueue was posted after the cancel, so we're invalid return; } } } if (repost) { mHandler.post(this); return; } // Look for the notification in the posted list, since we already checked enqueued. NotificationRecord r = findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId); Loading @@ -6298,6 +6315,10 @@ public class NotificationManagerService extends SystemService { if ((r.getNotification().flags & mMustNotHaveFlags) != 0) { return; } if (r.getUpdateTimeMs() > mWhen) { // In this case, a post must have slipped by when this runnable reposted return; } // Bubbled children get to stick around if the summary was manually cancelled // (user removed) from systemui. Loading Loading @@ -8220,6 +8241,29 @@ public class NotificationManagerService extends SystemService { return null; } /** * There may be multiple records that match your criteria. For instance if there have been * multiple notifications posted which are enqueued for the same pkg, tag, id, userId. This * method will find all of them in the given list * @return */ @GuardedBy("mNotificationLock") private List<NotificationRecord> findEnqueuedNotificationsForCriteria( String pkg, String tag, int id, int userId) { final ArrayList<NotificationRecord> records = new ArrayList<>(); final int n = mEnqueuedNotifications.size(); for (int i = 0; i < n; i++) { NotificationRecord r = mEnqueuedNotifications.get(i); if (notificationMatchesUserId(r, userId) && r.getSbn().getId() == id && TextUtils.equals(r.getSbn().getTag(), tag) && r.getSbn().getPackageName().equals(pkg)) { records.add(r); } } return records; } @GuardedBy("mNotificationLock") int indexOfNotificationLocked(String key) { final int N = mNotificationList.size(); Loading
services/core/java/com/android/server/notification/NotificationRecord.java +4 −0 Original line number Diff line number Diff line Loading @@ -906,6 +906,10 @@ public final class NotificationRecord { return (int) (now - mInterruptionTimeMs); } public long getUpdateTimeMs() { return mUpdateTimeMs; } /** * Set the visibility of the notification. */ Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -1283,6 +1283,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, mService.getNotificationRecordCount()); } @Test public void testPostCancelPostNotifiesListeners() throws Exception { // WHEN a notification is posted final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); // THEN it is canceled mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId()); // THEN it is posted again (before the cancel has a chance to finish) mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getNotification(), sbn.getUserId()); // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected waitForIdle(); // The final enqueue made it to the listener instead of being canceled StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); assertEquals(1, notifs.length); assertEquals(1, mService.getNotificationRecordCount()); } @Test public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, PKG, Loading