Merge "Some issues with persisted snoozed notifications"
This commit is contained in:
committed by
Android (Google) Code Review
commit
72b5e4a8aa
@@ -772,7 +772,7 @@ public class NotificationManagerService extends SystemService {
|
||||
parser, mAllowedManagedServicePackages, forRestore, userId);
|
||||
migratedManagedServices = true;
|
||||
} else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
|
||||
mSnoozeHelper.readXml(parser);
|
||||
mSnoozeHelper.readXml(parser, System.currentTimeMillis());
|
||||
}
|
||||
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
|
||||
if (forRestore && userId != UserHandle.USER_SYSTEM) {
|
||||
@@ -2322,6 +2322,8 @@ public class NotificationManagerService extends SystemService {
|
||||
mConditionProviders.onBootPhaseAppsCanStart();
|
||||
mHistoryManager.onBootPhaseAppsCanStart();
|
||||
registerDeviceConfigChange();
|
||||
} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
|
||||
mSnoozeHelper.scheduleRepostsForPersistedNotifications(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import android.util.Slog;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -43,9 +44,7 @@ import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -172,7 +171,7 @@ public class SnoozeHelper {
|
||||
for (int i = 0; i < allRecords.size(); i++) {
|
||||
NotificationRecord r = allRecords.valueAt(i);
|
||||
String currentGroupKey = r.getSbn().getGroup();
|
||||
if (currentGroupKey.equals(groupKey)) {
|
||||
if (Objects.equals(currentGroupKey, groupKey)) {
|
||||
records.add(r);
|
||||
}
|
||||
}
|
||||
@@ -217,7 +216,7 @@ public class SnoozeHelper {
|
||||
|
||||
snooze(record);
|
||||
scheduleRepost(pkg, key, userId, duration);
|
||||
Long activateAt = System.currentTimeMillis() + duration;
|
||||
Long activateAt = SystemClock.elapsedRealtime() + duration;
|
||||
synchronized (mPersistedSnoozedNotifications) {
|
||||
storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
|
||||
}
|
||||
@@ -244,8 +243,6 @@ public class SnoozeHelper {
|
||||
}
|
||||
storeRecord(record.getSbn().getPackageName(), record.getKey(),
|
||||
userId, mSnoozedNotifications, record);
|
||||
mPackages.put(record.getKey(), record.getSbn().getPackageName());
|
||||
mUsers.put(record.getKey(), userId);
|
||||
}
|
||||
|
||||
private <T> void storeRecord(String pkg, String key, Integer userId,
|
||||
@@ -258,6 +255,8 @@ public class SnoozeHelper {
|
||||
keyToValue.put(key, object);
|
||||
targets.put(getPkgKey(userId, pkg), keyToValue);
|
||||
|
||||
mPackages.put(key, pkg);
|
||||
mUsers.put(key, userId);
|
||||
}
|
||||
|
||||
private <T> T removeRecord(String pkg, String key, Integer userId,
|
||||
@@ -425,12 +424,34 @@ public class SnoozeHelper {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
public void scheduleRepostsForPersistedNotifications(long currentTime) {
|
||||
for (ArrayMap<String, Long> snoozed : mPersistedSnoozedNotifications.values()) {
|
||||
for (int i = 0; i < snoozed.size(); i++) {
|
||||
String key = snoozed.keyAt(i);
|
||||
Long time = snoozed.valueAt(i);
|
||||
String pkg = mPackages.get(key);
|
||||
Integer userId = mUsers.get(key);
|
||||
if (time == null || pkg == null || userId == null) {
|
||||
Slog.w(TAG, "data out of sync: " + time + "|" + pkg + "|" + userId);
|
||||
continue;
|
||||
}
|
||||
if (time != null && time > currentTime) {
|
||||
scheduleRepostAtTime(pkg, key, userId, time);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleRepost(String pkg, String key, int userId, long duration) {
|
||||
scheduleRepostAtTime(pkg, key, userId, SystemClock.elapsedRealtime() + duration);
|
||||
}
|
||||
|
||||
private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final PendingIntent pi = createPendingIntent(pkg, key, userId);
|
||||
mAm.cancel(pi);
|
||||
long time = SystemClock.elapsedRealtime() + duration;
|
||||
if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
|
||||
mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
|
||||
} finally {
|
||||
@@ -496,6 +517,7 @@ public class SnoozeHelper {
|
||||
private interface Inserter<T> {
|
||||
void insert(T t) throws IOException;
|
||||
}
|
||||
|
||||
private <T> void writeXml(XmlSerializer out,
|
||||
ArrayMap<String, ArrayMap<String, T>> targets, String tag,
|
||||
Inserter<T> attributeInserter)
|
||||
@@ -503,12 +525,13 @@ public class SnoozeHelper {
|
||||
synchronized (targets) {
|
||||
final int M = targets.size();
|
||||
for (int i = 0; i < M; i++) {
|
||||
String userIdPkgKey = targets.keyAt(i);
|
||||
// T is a String (snoozed until context) or Long (snoozed until time)
|
||||
ArrayMap<String, T> keyToValue = targets.valueAt(i);
|
||||
for (int j = 0; j < keyToValue.size(); j++) {
|
||||
String key = keyToValue.keyAt(j);
|
||||
T value = keyToValue.valueAt(j);
|
||||
String pkg = mPackages.get(key);
|
||||
Integer userId = mUsers.get(key);
|
||||
|
||||
out.startTag(null, tag);
|
||||
|
||||
@@ -518,8 +541,7 @@ public class SnoozeHelper {
|
||||
XML_SNOOZED_NOTIFICATION_VERSION);
|
||||
out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
|
||||
|
||||
String pkg = mPackages.get(key);
|
||||
int userId = mUsers.get(key);
|
||||
|
||||
out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
|
||||
out.attribute(null, XML_SNOOZED_NOTIFICATION_USER_ID,
|
||||
String.valueOf(userId));
|
||||
@@ -530,7 +552,7 @@ public class SnoozeHelper {
|
||||
}
|
||||
}
|
||||
|
||||
protected void readXml(XmlPullParser parser)
|
||||
protected void readXml(XmlPullParser parser, long currentTime)
|
||||
throws XmlPullParserException, IOException {
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
|
||||
@@ -547,16 +569,15 @@ public class SnoozeHelper {
|
||||
try {
|
||||
final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
|
||||
final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
|
||||
final int userId = Integer.parseInt(
|
||||
parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_USER_ID));
|
||||
final int userId = XmlUtils.readIntAttribute(
|
||||
parser, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
|
||||
if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
|
||||
final Long time = Long.parseLong(
|
||||
parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_TIME));
|
||||
if (time > System.currentTimeMillis()) { //only read new stuff
|
||||
final Long time = XmlUtils.readLongAttribute(
|
||||
parser, XML_SNOOZED_NOTIFICATION_TIME, 0);
|
||||
if (time > currentTime) { //only read new stuff
|
||||
synchronized (mPersistedSnoozedNotifications) {
|
||||
storeRecord(pkg, key, userId, mPersistedSnoozedNotifications, time);
|
||||
}
|
||||
scheduleRepost(pkg, key, userId, time - System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
if (tag.equals(XML_SNOOZED_NOTIFICATION_CONTEXT)) {
|
||||
|
||||
@@ -3246,7 +3246,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
|
||||
false,
|
||||
UserHandle.USER_ALL);
|
||||
verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class));
|
||||
verify(mSnoozeHelper, times(1)).readXml(any(XmlPullParser.class), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -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.eq;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
@@ -96,10 +97,33 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(xml_string.getBytes())), null);
|
||||
mSnoozeHelper.readXml(parser);
|
||||
assertTrue("Should read the notification time from xml and it should be more than zero",
|
||||
0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
|
||||
0, "pkg", "key").doubleValue());
|
||||
mSnoozeHelper.readXml(parser, 1);
|
||||
assertEquals((long) Long.MAX_VALUE, (long) mSnoozeHelper
|
||||
.getSnoozeTimeForUnpostedNotification(0, "pkg", "key"));
|
||||
verify(mAm, never()).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteXML_afterReading_noNPE()
|
||||
throws XmlPullParserException, IOException {
|
||||
final String max_time_str = Long.toString(Long.MAX_VALUE);
|
||||
final String xml_string = "<snoozed-notifications>"
|
||||
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
|
||||
+ "pkg=\"pkg\" key=\"key\" time=\"" + max_time_str + "\"/>"
|
||||
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
|
||||
+ "pkg=\"pkg\" key=\"key2\" time=\"" + max_time_str + "\"/>"
|
||||
+ "</snoozed-notifications>";
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(xml_string.getBytes())), null);
|
||||
mSnoozeHelper.readXml(parser, 1);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
XmlSerializer serializer = new FastXmlSerializer();
|
||||
serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
|
||||
serializer.startDocument(null, true);
|
||||
mSnoozeHelper.writeXml(serializer);
|
||||
serializer.endDocument();
|
||||
serializer.flush();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,7 +139,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(xml_string.getBytes())), null);
|
||||
mSnoozeHelper.readXml(parser);
|
||||
mSnoozeHelper.readXml(parser, 1);
|
||||
assertEquals("Should read the notification context from xml and it should be `uri",
|
||||
"uri", mSnoozeHelper.getSnoozeContextForUnpostedNotification(
|
||||
0, "pkg", "key"));
|
||||
@@ -137,7 +161,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
|
||||
mSnoozeHelper.readXml(parser);
|
||||
mSnoozeHelper.readXml(parser, 1);
|
||||
assertTrue("Should read the notification time from xml and it should be more than zero",
|
||||
0 < mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
|
||||
0, "pkg", r.getKey()).doubleValue());
|
||||
@@ -161,7 +185,7 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(baos.toByteArray())), "utf-8");
|
||||
mSnoozeHelper.readXml(parser);
|
||||
mSnoozeHelper.readXml(parser, 2);
|
||||
int systemUser = UserHandle.SYSTEM.getIdentifier();
|
||||
assertTrue("Should see a past time returned",
|
||||
System.currentTimeMillis() > mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
|
||||
@@ -194,6 +218,30 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
"not_my_package", r.getKey()).longValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScheduleRepostsForPersistedNotifications() throws Exception {
|
||||
final String xml_string = "<snoozed-notifications>"
|
||||
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
|
||||
+ "pkg=\"pkg\" key=\"key\" time=\"" + 10 + "\"/>"
|
||||
+ "<notification version=\"1\" user-id=\"0\" notification=\"notification\" "
|
||||
+ "pkg=\"pkg\" key=\"key2\" time=\"" + 15+ "\"/>"
|
||||
+ "</snoozed-notifications>";
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(new BufferedInputStream(
|
||||
new ByteArrayInputStream(xml_string.getBytes())), null);
|
||||
mSnoozeHelper.readXml(parser, 4);
|
||||
|
||||
mSnoozeHelper.scheduleRepostsForPersistedNotifications(5);
|
||||
|
||||
ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
|
||||
verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 10), captor.capture());
|
||||
assertEquals("key", captor.getValue().getIntent().getStringExtra(EXTRA_KEY));
|
||||
|
||||
ArgumentCaptor<PendingIntent> captor2 = ArgumentCaptor.forClass(PendingIntent.class);
|
||||
verify(mAm).setExactAndAllowWhileIdle(anyInt(), eq((long) 15), captor2.capture());
|
||||
assertEquals("key2", captor2.getValue().getIntent().getStringExtra(EXTRA_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSnoozeForTime() throws Exception {
|
||||
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
|
||||
@@ -413,6 +461,23 @@ public class SnoozeHelperTest extends UiServiceTestCase {
|
||||
mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnoozedGroupNotifications_nonGrouped() throws Exception {
|
||||
IntArray profileIds = new IntArray();
|
||||
profileIds.add(UserHandle.USER_CURRENT);
|
||||
when(mUserProfiles.getCurrentProfileIds()).thenReturn(profileIds);
|
||||
NotificationRecord r = getNotificationRecord("pkg", 1, "tag",
|
||||
UserHandle.CURRENT, "group", true);
|
||||
NotificationRecord r2 = getNotificationRecord("pkg", 2, "tag",
|
||||
UserHandle.CURRENT, null, true);
|
||||
mSnoozeHelper.snooze(r, 1000);
|
||||
mSnoozeHelper.snooze(r2, 1000);
|
||||
|
||||
assertEquals(1,
|
||||
mSnoozeHelper.getNotifications("pkg", "group", UserHandle.USER_CURRENT).size());
|
||||
// and no NPE
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSnoozedNotificationByKey() throws Exception {
|
||||
IntArray profileIds = new IntArray();
|
||||
|
||||
Reference in New Issue
Block a user