Loading services/core/java/com/android/server/notification/SnoozeHelper.java +22 −1 Original line number Diff line number Diff line Loading @@ -141,13 +141,29 @@ public class SnoozeHelper { protected boolean canSnooze(int numberToSnooze) { synchronized (mLock) { if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) { if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT || (countPersistedNotificationsLocked() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) { return false; } } return true; } private int countPersistedNotificationsLocked() { int numNotifications = 0; for (ArrayMap<String, String> persistedWithContext : mPersistedSnoozedNotificationsWithContext.values()) { numNotifications += persistedWithContext.size(); } for (ArrayMap<String, Long> persistedWithDuration : mPersistedSnoozedNotifications.values()) { numNotifications += persistedWithDuration.size(); } return numNotifications; } @NonNull protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) { Long time = null; Loading Loading @@ -450,6 +466,11 @@ public class SnoozeHelper { mPackages.remove(groupSummaryKey); mUsers.remove(groupSummaryKey); final String trimmedKey = getTrimmedString(groupSummaryKey); removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotifications); removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotificationsWithContext); if (record != null && !record.isCanceled) { Runnable runnable = () -> { MetricsLogger.action(record.getLogMaker() Loading services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +102 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.notification; import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT; import static com.android.server.notification.SnoozeHelper.EXTRA_KEY; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; Loading Loading @@ -76,6 +78,16 @@ import java.util.Collections; public class SnoozeHelperTest extends UiServiceTestCase { private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String XML_TAG_NAME = "snoozed-notifications"; private static final String XML_SNOOZED_NOTIFICATION = "notification"; private static final String XML_SNOOZED_NOTIFICATION_CONTEXT = "context"; private static final String XML_SNOOZED_NOTIFICATION_KEY = "key"; private static final String XML_SNOOZED_NOTIFICATION_TIME = "time"; private static final String XML_SNOOZED_NOTIFICATION_CONTEXT_ID = "id"; private static final String XML_SNOOZED_NOTIFICATION_VERSION_LABEL = "version"; private static final String XML_SNOOZED_NOTIFICATION_PKG = "pkg"; private static final String XML_SNOOZED_NOTIFICATION_USER_ID = "user-id"; @Mock SnoozeHelper.Callback mCallback; @Mock AlarmManager mAm; @Mock ManagedServices.UserProfiles mUserProfiles; Loading Loading @@ -329,6 +341,56 @@ public class SnoozeHelperTest extends UiServiceTestCase { assertFalse(mSnoozeHelper.canSnooze(1)); } @Test public void testSnoozeLimit_maximumPersisted() throws XmlPullParserException, IOException { final long snoozeTimeout = 1234; final String snoozeContext = "ctx"; // Serialize & deserialize notifications so that only persisted lists are used TypedXmlSerializer serializer = Xml.newFastSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); serializer.startDocument(null, true); serializer.startTag(null, XML_TAG_NAME); // Serialize maximum number of timed + context snoozed notifications, half of each for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++) { final boolean timedNotification = i % 2 == 0; if (timedNotification) { serializer.startTag(null, XML_SNOOZED_NOTIFICATION); } else { serializer.startTag(null, XML_SNOOZED_NOTIFICATION_CONTEXT); } serializer.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, "pkg"); serializer.attributeInt(null, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_SYSTEM); serializer.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, 1); serializer.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, "key" + i); if (timedNotification) { serializer.attributeLong(null, XML_SNOOZED_NOTIFICATION_TIME, snoozeTimeout); serializer.endTag(null, XML_SNOOZED_NOTIFICATION); } else { serializer.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID, snoozeContext); serializer.endTag(null, XML_SNOOZED_NOTIFICATION_CONTEXT); } } serializer.endTag(null, XML_TAG_NAME); serializer.endDocument(); serializer.flush(); TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), "utf-8"); mSnoozeHelper.readXml(parser, 1); // Verify that we can't snooze any more notifications // and that the limit is caused by persisted notifications assertThat(mSnoozeHelper.canSnooze(1)).isFalse(); assertThat(mSnoozeHelper.isSnoozed(UserHandle.USER_SYSTEM, "pkg", "key0")).isFalse(); assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", "key0")).isEqualTo(snoozeTimeout); assertThat( mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", "key1")).isEqualTo(snoozeContext); } @Test public void testCancelByApp() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); Loading Loading @@ -602,6 +664,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { @Test public void repostGroupSummary_repostsSummary() throws Exception { final int snoozeDuration = 1000; IntArray profileIds = new IntArray(); profileIds.add(UserHandle.USER_SYSTEM); when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); Loading @@ -609,10 +672,44 @@ public class SnoozeHelperTest extends UiServiceTestCase { "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); NotificationRecord r2 = getNotificationRecord( "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); mSnoozeHelper.snooze(r, 1000); mSnoozeHelper.snooze(r2, 1000); final long snoozeTime = System.currentTimeMillis() + snoozeDuration; mSnoozeHelper.snooze(r, snoozeDuration); mSnoozeHelper.snooze(r2, snoozeDuration); assertEquals(2, mSnoozeHelper.getSnoozed().size()); assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was added to the persisted list assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isAtLeast(snoozeTime); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); 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()); // Verify that summary notification was removed from the persisted list assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isEqualTo(0); } @Test public void snoozeWithContext_repostGroupSummary_removesPersisted() throws Exception { final String snoozeContext = "zzzzz"; IntArray profileIds = new IntArray(); profileIds.add(UserHandle.USER_SYSTEM); when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); NotificationRecord r = getNotificationRecord( "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); NotificationRecord r2 = getNotificationRecord( "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); mSnoozeHelper.snooze(r, snoozeContext); mSnoozeHelper.snooze(r2, snoozeContext); assertEquals(2, mSnoozeHelper.getSnoozed().size()); assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was added to the persisted list assertThat(mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isEqualTo(snoozeContext); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); Loading @@ -621,6 +718,9 @@ public class SnoozeHelperTest extends UiServiceTestCase { assertEquals(1, mSnoozeHelper.getSnoozed().size()); assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was removed from the persisted list assertThat(mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isNull(); } @Test Loading Loading
services/core/java/com/android/server/notification/SnoozeHelper.java +22 −1 Original line number Diff line number Diff line Loading @@ -141,13 +141,29 @@ public class SnoozeHelper { protected boolean canSnooze(int numberToSnooze) { synchronized (mLock) { if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) { if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT || (countPersistedNotificationsLocked() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) { return false; } } return true; } private int countPersistedNotificationsLocked() { int numNotifications = 0; for (ArrayMap<String, String> persistedWithContext : mPersistedSnoozedNotificationsWithContext.values()) { numNotifications += persistedWithContext.size(); } for (ArrayMap<String, Long> persistedWithDuration : mPersistedSnoozedNotifications.values()) { numNotifications += persistedWithDuration.size(); } return numNotifications; } @NonNull protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) { Long time = null; Loading Loading @@ -450,6 +466,11 @@ public class SnoozeHelper { mPackages.remove(groupSummaryKey); mUsers.remove(groupSummaryKey); final String trimmedKey = getTrimmedString(groupSummaryKey); removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotifications); removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotificationsWithContext); if (record != null && !record.isCanceled) { Runnable runnable = () -> { MetricsLogger.action(record.getLogMaker() Loading
services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java +102 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.server.notification; import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT; import static com.android.server.notification.SnoozeHelper.EXTRA_KEY; import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; Loading Loading @@ -76,6 +78,16 @@ import java.util.Collections; public class SnoozeHelperTest extends UiServiceTestCase { private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String XML_TAG_NAME = "snoozed-notifications"; private static final String XML_SNOOZED_NOTIFICATION = "notification"; private static final String XML_SNOOZED_NOTIFICATION_CONTEXT = "context"; private static final String XML_SNOOZED_NOTIFICATION_KEY = "key"; private static final String XML_SNOOZED_NOTIFICATION_TIME = "time"; private static final String XML_SNOOZED_NOTIFICATION_CONTEXT_ID = "id"; private static final String XML_SNOOZED_NOTIFICATION_VERSION_LABEL = "version"; private static final String XML_SNOOZED_NOTIFICATION_PKG = "pkg"; private static final String XML_SNOOZED_NOTIFICATION_USER_ID = "user-id"; @Mock SnoozeHelper.Callback mCallback; @Mock AlarmManager mAm; @Mock ManagedServices.UserProfiles mUserProfiles; Loading Loading @@ -329,6 +341,56 @@ public class SnoozeHelperTest extends UiServiceTestCase { assertFalse(mSnoozeHelper.canSnooze(1)); } @Test public void testSnoozeLimit_maximumPersisted() throws XmlPullParserException, IOException { final long snoozeTimeout = 1234; final String snoozeContext = "ctx"; // Serialize & deserialize notifications so that only persisted lists are used TypedXmlSerializer serializer = Xml.newFastSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); serializer.startDocument(null, true); serializer.startTag(null, XML_TAG_NAME); // Serialize maximum number of timed + context snoozed notifications, half of each for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++) { final boolean timedNotification = i % 2 == 0; if (timedNotification) { serializer.startTag(null, XML_SNOOZED_NOTIFICATION); } else { serializer.startTag(null, XML_SNOOZED_NOTIFICATION_CONTEXT); } serializer.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, "pkg"); serializer.attributeInt(null, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_SYSTEM); serializer.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL, 1); serializer.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, "key" + i); if (timedNotification) { serializer.attributeLong(null, XML_SNOOZED_NOTIFICATION_TIME, snoozeTimeout); serializer.endTag(null, XML_SNOOZED_NOTIFICATION); } else { serializer.attribute(null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID, snoozeContext); serializer.endTag(null, XML_SNOOZED_NOTIFICATION_CONTEXT); } } serializer.endTag(null, XML_TAG_NAME); serializer.endDocument(); serializer.flush(); TypedXmlPullParser parser = Xml.newFastPullParser(); parser.setInput(new BufferedInputStream( new ByteArrayInputStream(baos.toByteArray())), "utf-8"); mSnoozeHelper.readXml(parser, 1); // Verify that we can't snooze any more notifications // and that the limit is caused by persisted notifications assertThat(mSnoozeHelper.canSnooze(1)).isFalse(); assertThat(mSnoozeHelper.isSnoozed(UserHandle.USER_SYSTEM, "pkg", "key0")).isFalse(); assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", "key0")).isEqualTo(snoozeTimeout); assertThat( mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", "key1")).isEqualTo(snoozeContext); } @Test public void testCancelByApp() throws Exception { NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM); Loading Loading @@ -602,6 +664,7 @@ public class SnoozeHelperTest extends UiServiceTestCase { @Test public void repostGroupSummary_repostsSummary() throws Exception { final int snoozeDuration = 1000; IntArray profileIds = new IntArray(); profileIds.add(UserHandle.USER_SYSTEM); when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); Loading @@ -609,10 +672,44 @@ public class SnoozeHelperTest extends UiServiceTestCase { "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); NotificationRecord r2 = getNotificationRecord( "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); mSnoozeHelper.snooze(r, 1000); mSnoozeHelper.snooze(r2, 1000); final long snoozeTime = System.currentTimeMillis() + snoozeDuration; mSnoozeHelper.snooze(r, snoozeDuration); mSnoozeHelper.snooze(r2, snoozeDuration); assertEquals(2, mSnoozeHelper.getSnoozed().size()); assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was added to the persisted list assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isAtLeast(snoozeTime); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); 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()); // Verify that summary notification was removed from the persisted list assertThat(mSnoozeHelper.getSnoozeTimeForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isEqualTo(0); } @Test public void snoozeWithContext_repostGroupSummary_removesPersisted() throws Exception { final String snoozeContext = "zzzzz"; IntArray profileIds = new IntArray(); profileIds.add(UserHandle.USER_SYSTEM); when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds); NotificationRecord r = getNotificationRecord( "pkg", 1, "one", UserHandle.SYSTEM, "group1", true); NotificationRecord r2 = getNotificationRecord( "pkg", 2, "two", UserHandle.SYSTEM, "group1", false); mSnoozeHelper.snooze(r, snoozeContext); mSnoozeHelper.snooze(r2, snoozeContext); assertEquals(2, mSnoozeHelper.getSnoozed().size()); assertEquals(2, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was added to the persisted list assertThat(mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isEqualTo(snoozeContext); mSnoozeHelper.repostGroupSummary("pkg", UserHandle.USER_SYSTEM, r.getGroupKey()); Loading @@ -621,6 +718,9 @@ public class SnoozeHelperTest extends UiServiceTestCase { assertEquals(1, mSnoozeHelper.getSnoozed().size()); assertEquals(1, mSnoozeHelper.getSnoozed(UserHandle.USER_SYSTEM, "pkg").size()); // Verify that summary notification was removed from the persisted list assertThat(mSnoozeHelper.getSnoozeContextForUnpostedNotification(UserHandle.USER_SYSTEM, "pkg", r.getKey())).isNull(); } @Test Loading