diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ceb1cd41f5676..f4d65a82a104f 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2068,19 +2068,16 @@ public class NotificationManagerService extends SystemService { @Override public void onStart() { - SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() { - @Override - public void repost(int userId, NotificationRecord r) { - try { - if (DBG) { - Slog.d(TAG, "Reposting " + r.getKey()); - } - enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), - r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), - r.getSbn().getId(), r.getSbn().getNotification(), userId); - } catch (Exception e) { - Slog.e(TAG, "Cannot un-snooze notification", e); + SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> { + try { + if (DBG) { + Slog.d(TAG, "Reposting " + r.getKey()); } + enqueueNotificationInternal(r.getSbn().getPackageName(), r.getSbn().getOpPkg(), + r.getSbn().getUid(), r.getSbn().getInitialPid(), r.getSbn().getTag(), + r.getSbn().getId(), r.getSbn().getNotification(), userId, true); + } catch (Exception e) { + Slog.e(TAG, "Cannot un-snooze notification", e); } }, mUserProfiles); @@ -3983,7 +3980,7 @@ public class NotificationManagerService extends SystemService { synchronized (mNotificationLock) { final ManagedServiceInfo info = mAssistants.checkServiceTokenLocked(token); - unsnoozeNotificationInt(key, info); + unsnoozeNotificationInt(key, info, false); } } finally { Binder.restoreCallingIdentity(identity); @@ -4006,7 +4003,7 @@ public class NotificationManagerService extends SystemService { if (!info.isSystem) { throw new SecurityException("Not allowed to unsnooze before deadline"); } - unsnoozeNotificationInt(key, info); + unsnoozeNotificationInt(key, info, true); } } finally { Binder.restoreCallingIdentity(identity); @@ -5525,6 +5522,13 @@ public class NotificationManagerService extends SystemService { void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int incomingUserId) { + enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification, + incomingUserId, false); + } + + void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, + final int callingPid, final String tag, final int id, final Notification notification, + int incomingUserId, boolean postSilently) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); @@ -5605,6 +5609,7 @@ public class NotificationManagerService extends SystemService { user, null, System.currentTimeMillis()); final NotificationRecord r = new NotificationRecord(getContext(), n, channel); r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid)); + r.setPostSilently(postSilently); if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { final boolean fgServiceShown = channel.isFgServiceShown(); @@ -7040,6 +7045,11 @@ public class NotificationManagerService extends SystemService { return true; } + // Suppressed because a user manually unsnoozed something (or similar) + if (record.shouldPostSilently()) { + return true; + } + // muted by listener final String disableEffects = disableNotificationEffects(record); if (disableEffects != null) { @@ -8054,13 +8064,13 @@ public class NotificationManagerService extends SystemService { mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId)); } - void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) { + void unsnoozeNotificationInt(String key, ManagedServiceInfo listener, boolean muteOnReturn) { String listenerName = listener == null ? null : listener.component.toShortString(); if (DBG) { Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName)); } mSnoozeHelper.cleanupPersistedContext(key); - mSnoozeHelper.repost(key); + mSnoozeHelper.repost(key, muteOnReturn); handleSavePolicyFile(); } diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 9d243e4d75a97..70415af98ea4a 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -187,6 +187,7 @@ public final class NotificationRecord { private boolean mSuggestionsGeneratedByAssistant; private boolean mEditChoicesBeforeSending; private boolean mHasSeenSmartReplies; + private boolean mPostSilently; /** * Whether this notification (and its channels) should be considered user locked. Used in * conjunction with user sentiment calculation. @@ -856,6 +857,17 @@ public final class NotificationRecord { return mHidden; } + /** + * Override of all alerting information on the channel and notification. Used when notifications + * are reposted in response to direct user action and thus don't need to alert. + */ + public void setPostSilently(boolean postSilently) { + mPostSilently = postSilently; + } + + public boolean shouldPostSilently() { + return mPostSilently; + } public void setSuppressedVisualEffects(int effects) { mSuppressedVisualEffects = effects; diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java index d60c29119c182..26dbd22ce0287 100644 --- a/services/core/java/com/android/server/notification/SnoozeHelper.java +++ b/services/core/java/com/android/server/notification/SnoozeHelper.java @@ -332,14 +332,14 @@ public class SnoozeHelper { records.put(record.getKey(), record); } - protected void repost(String key) { + protected void repost(String key, boolean muteOnReturn) { Integer userId = mUsers.get(key); if (userId != null) { - repost(key, userId); + repost(key, userId, muteOnReturn); } } - protected void repost(String key, int userId) { + protected void repost(String key, int userId, boolean muteOnReturn) { final String pkg = mPackages.remove(key); ArrayMap records = mSnoozedNotifications.get(getPkgKey(userId, pkg)); @@ -356,7 +356,7 @@ public class SnoozeHelper { MetricsLogger.action(record.getLogMaker() .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); - mCallback.repost(userId, record); + mCallback.repost(userId, record, muteOnReturn); } } @@ -388,7 +388,7 @@ public class SnoozeHelper { MetricsLogger.action(record.getLogMaker() .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED) .setType(MetricsProto.MetricsEvent.TYPE_OPEN)); - mCallback.repost(userId, record); + mCallback.repost(userId, record, false); } } } @@ -601,7 +601,7 @@ public class SnoozeHelper { } protected interface Callback { - void repost(int userId, NotificationRecord r); + void repost(int userId, NotificationRecord r, boolean muteOnReturn); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -612,7 +612,7 @@ public class SnoozeHelper { } if (REPOST_ACTION.equals(intent.getAction())) { repost(intent.getStringExtra(EXTRA_KEY), intent.getIntExtra(EXTRA_USER_ID, - UserHandle.USER_SYSTEM)); + UserHandle.USER_SYSTEM), false); } } }; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index f029bc80480a6..afd10ddb8ec26 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -845,6 +845,18 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { assertNotEquals(-1, r.getLastAudiblyAlertedMs()); } + @Test + public void testPostSilently() throws Exception { + NotificationRecord r = getBuzzyNotification(); + r.setPostSilently(true); + + mService.buzzBeepBlinkLocked(r); + + verifyNeverBeep(); + assertFalse(r.isInterruptive()); + assertEquals(-1, r.getLastAudiblyAlertedMs()); + } + @Test public void testGroupAlertSummarySilenceChild() throws Exception { NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java index 816e8e57acc6f..863bbbb0d8dbf 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -363,8 +364,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), "one", 1); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r, false); } @Test @@ -374,8 +375,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); mSnoozeHelper.snooze(r2, 1000); reset(mAm); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); ArgumentCaptor captor = ArgumentCaptor.forClass(PendingIntent.class); verify(mAm).cancel(captor.capture()); assertEquals(r.getKey(), captor.getValue().getIntent().getStringExtra(EXTRA_KEY)); @@ -388,8 +389,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL); mSnoozeHelper.snooze(r2, 1000); reset(mAm); - mSnoozeHelper.repost(r.getKey()); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); verify(mAm).cancel(any(PendingIntent.class)); } @@ -400,10 +401,10 @@ public class SnoozeHelperTest extends UiServiceTestCase { r.getNotification().category = "NEW CATEGORY"; mSnoozeHelper.update(UserHandle.USER_SYSTEM, r); - verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class)); + verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class), anyBoolean()); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); } @Test @@ -420,12 +421,22 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.update(UserHandle.USER_SYSTEM, r); // verify callback is called when repost (snooze is expired) - verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class)); - mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); + verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class), anyBoolean()); + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, false); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); assertFalse(r.isCanceled); } + @Test + public void testReport_passesFlag() throws Exception { + // snooze a notification + NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); + mSnoozeHelper.snooze(r , 1000); + + mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM, true); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, true); + } + @Test public void testGetSnoozedBy() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); @@ -523,7 +534,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.snooze(r2, 1000); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, "group1"); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r); + verify(mCallback, never()).repost(eq(UserHandle.USER_SYSTEM), eq(r), anyBoolean()); } @Test @@ -542,8 +553,8 @@ public class SnoozeHelperTest extends UiServiceTestCase { mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); - verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r); - verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2); + verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r, false); + verify(mCallback, never()).repost(UserHandle.USER_SYSTEM, r2, false); assertEquals(1, mSnoozeHelper.getSnoozed().size()); assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size());