When a profile is stopped, remove pending snoozes

To be consistent with the way that non-snoozed notifications
are canceled.

Also, simplify the data structures in SnoozeHelper.

Test: SnoozeHelperTest
Fixes: 211157091
Change-Id: I0cd8b0f406290a7886f4d60309ef3ba626af3726
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5787efb..9486a45 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1794,6 +1794,7 @@
                 if (userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
                             REASON_PROFILE_TURNED_OFF, null);
+                    mSnoozeHelper.clearData(userHandle);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 15d7c1e..61936df 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -16,7 +16,6 @@
 package com.android.server.notification;
 
 import android.annotation.NonNull;
-import android.annotation.UserIdInt;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -25,7 +24,6 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
@@ -38,18 +36,15 @@
 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 com.android.server.pm.PackageManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -59,7 +54,7 @@
 /**
  * NotificationManagerService helper for handling snoozed notifications.
  */
-public class SnoozeHelper {
+public final class SnoozeHelper {
     public static final int XML_SNOOZED_NOTIFICATION_VERSION = 1;
 
     static final int CONCURRENT_SNOOZE_LIMIT = 500;
@@ -68,8 +63,6 @@
 
     private static final String XML_SNOOZED_NOTIFICATION = "notification";
     private static final String XML_SNOOZED_NOTIFICATION_CONTEXT = "context";
-    private static final String XML_SNOOZED_NOTIFICATION_PKG = "pkg";
-    private static final String XML_SNOOZED_NOTIFICATION_USER_ID = "user-id";
     private static final String XML_SNOOZED_NOTIFICATION_KEY = "key";
     //the time the snoozed notification should be reposted
     private static final String XML_SNOOZED_NOTIFICATION_TIME = "time";
@@ -91,24 +84,19 @@
     private AlarmManager mAm;
     private final ManagedServices.UserProfiles mUserProfiles;
 
-    // User id | package name : notification key : record.
-    private ArrayMap<String, ArrayMap<String, NotificationRecord>>
-            mSnoozedNotifications = new ArrayMap<>();
-    // User id | package name : notification key : time-milliseconds .
+    // notification key : record.
+    private ArrayMap<String, NotificationRecord> mSnoozedNotifications = new ArrayMap<>();
+    // notification key : time-milliseconds .
     // This member stores persisted snoozed notification trigger times. it persists through reboots
     // It should have the notifications that haven't expired or re-posted yet
-    private final ArrayMap<String, ArrayMap<String, Long>>
-            mPersistedSnoozedNotifications = new ArrayMap<>();
-    // User id | package name : notification key : creation ID .
+    private final ArrayMap<String, Long> mPersistedSnoozedNotifications = new ArrayMap<>();
+    // notification key : creation ID.
     // This member stores persisted snoozed notification trigger context for the assistant
     // it persists through reboots.
     // It should have the notifications that haven't expired or re-posted yet
-    private final ArrayMap<String, ArrayMap<String, String>>
+    private final ArrayMap<String, String>
             mPersistedSnoozedNotificationsWithContext = new ArrayMap<>();
-    // notification key : package.
-    private ArrayMap<String, String> mPackages = new ArrayMap<>();
-    // key : userId
-    private ArrayMap<String, Integer> mUsers = new ArrayMap<>();
+
     private Callback mCallback;
 
     private final Object mLock = new Object();
@@ -125,21 +113,9 @@
         mUserProfiles = userProfiles;
     }
 
-    private String getPkgKey(@UserIdInt int userId, String pkg) {
-        return userId + "|" + pkg;
-    }
-
-    void cleanupPersistedContext(String key){
-        synchronized (mLock) {
-            int userId = mUsers.get(key);
-            String pkg = mPackages.get(key);
-            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
-        }
-    }
-
     protected boolean canSnooze(int numberToSnooze) {
         synchronized (mLock) {
-            if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) {
+            if ((mSnoozedNotifications.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) {
                 return false;
             }
         }
@@ -150,11 +126,7 @@
     protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
         Long time = null;
         synchronized (mLock) {
-           ArrayMap<String, Long> snoozed =
-                   mPersistedSnoozedNotifications.get(getPkgKey(userId, pkg));
-           if (snoozed != null) {
-               time = snoozed.get(key);
-           }
+            time = mPersistedSnoozedNotifications.get(key);
         }
         if (time == null) {
             time = 0L;
@@ -164,29 +136,26 @@
 
     protected String getSnoozeContextForUnpostedNotification(int userId, String pkg, String key) {
         synchronized (mLock) {
-            ArrayMap<String, String> snoozed =
-                    mPersistedSnoozedNotificationsWithContext.get(getPkgKey(userId, pkg));
-            if (snoozed != null) {
-                return snoozed.get(key);
-            }
+            return mPersistedSnoozedNotificationsWithContext.get(key);
         }
-        return null;
     }
 
     protected boolean isSnoozed(int userId, String pkg, String key) {
         synchronized (mLock) {
-            return mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))
-                    && mSnoozedNotifications.get(getPkgKey(userId, pkg)).containsKey(key);
+            return mSnoozedNotifications.containsKey(key);
         }
     }
 
     protected Collection<NotificationRecord> getSnoozed(int userId, String pkg) {
         synchronized (mLock) {
-            if (mSnoozedNotifications.containsKey(getPkgKey(userId, pkg))) {
-                return mSnoozedNotifications.get(getPkgKey(userId, pkg)).values();
+            ArrayList snoozed = new ArrayList();
+            for (NotificationRecord r : mSnoozedNotifications.values()) {
+                if (r.getUserId() == userId && r.getSbn().getPackageName().equals(pkg)) {
+                    snoozed.add(r);
+                }
             }
+            return snoozed;
         }
-        return Collections.EMPTY_LIST;
     }
 
     @NonNull
@@ -194,15 +163,11 @@
             String groupKey, Integer userId) {
         ArrayList<NotificationRecord> records =  new ArrayList<>();
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> allRecords =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (allRecords != null) {
-                for (int i = 0; i < allRecords.size(); i++) {
-                    NotificationRecord r = allRecords.valueAt(i);
-                    String currentGroupKey = r.getSbn().getGroup();
-                    if (Objects.equals(currentGroupKey, groupKey)) {
-                        records.add(r);
-                    }
+            for (int i = 0; i < mSnoozedNotifications.size(); i++) {
+                NotificationRecord r = mSnoozedNotifications.valueAt(i);
+                if (r.getSbn().getPackageName().equals(pkg) && r.getUserId() == userId
+                        && Objects.equals(r.getSbn().getGroup(), groupKey)) {
+                    records.add(r);
                 }
             }
         }
@@ -211,31 +176,16 @@
 
     protected NotificationRecord getNotification(String key) {
         synchronized (mLock) {
-            if (!mUsers.containsKey(key) || !mPackages.containsKey(key)) {
-                Slog.w(TAG, "Snoozed data sets no longer agree for " + key);
-                return null;
-            }
-            int userId = mUsers.get(key);
-            String pkg = mPackages.get(key);
-            ArrayMap<String, NotificationRecord> snoozed =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (snoozed == null) {
-                return null;
-            }
-            return snoozed.get(key);
+            return mSnoozedNotifications.get(key);
         }
     }
 
     protected @NonNull List<NotificationRecord> getSnoozed() {
         synchronized (mLock) {
-            // caller filters records based on the current user profiles and listener access, so just
-            // return everything
+            // caller filters records based on the current user profiles and listener access,
+            // so just return everything
             List<NotificationRecord> snoozed = new ArrayList<>();
-            for (String userPkgKey : mSnoozedNotifications.keySet()) {
-                ArrayMap<String, NotificationRecord> snoozedRecords =
-                        mSnoozedNotifications.get(userPkgKey);
-                snoozed.addAll(snoozedRecords.values());
-            }
+            snoozed.addAll(mSnoozedNotifications.values());
             return snoozed;
         }
     }
@@ -244,15 +194,13 @@
      * Snoozes a notification and schedules an alarm to repost at that time.
      */
     protected void snooze(NotificationRecord record, long duration) {
-        String pkg = record.getSbn().getPackageName();
         String key = record.getKey();
-        int userId = record.getUser().getIdentifier();
 
         snooze(record);
-        scheduleRepost(pkg, key, userId, duration);
+        scheduleRepost(key, duration);
         Long activateAt = System.currentTimeMillis() + duration;
         synchronized (mLock) {
-            storeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
+            mPersistedSnoozedNotifications.put(key, activateAt);
         }
     }
 
@@ -260,66 +208,33 @@
      * Records a snoozed notification.
      */
     protected void snooze(NotificationRecord record, String contextId) {
-        int userId = record.getUser().getIdentifier();
         if (contextId != null) {
             synchronized (mLock) {
-                storeRecordLocked(record.getSbn().getPackageName(), record.getKey(),
-                        userId, mPersistedSnoozedNotificationsWithContext, contextId);
+                mPersistedSnoozedNotificationsWithContext.put(record.getKey(), contextId);
             }
         }
         snooze(record);
     }
 
     private void snooze(NotificationRecord record) {
-        int userId = record.getUser().getIdentifier();
         if (DEBUG) {
             Slog.d(TAG, "Snoozing " + record.getKey());
         }
         synchronized (mLock) {
-            storeRecordLocked(record.getSbn().getPackageName(), record.getKey(),
-                    userId, mSnoozedNotifications, record);
+            mSnoozedNotifications.put(record.getKey(), record);
         }
     }
 
-    private <T> void storeRecordLocked(String pkg, String key, Integer userId,
-            ArrayMap<String, ArrayMap<String, T>> targets, T object) {
-
-        mPackages.put(key, pkg);
-        mUsers.put(key, userId);
-        ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
-        if (keyToValue == null) {
-            keyToValue = new ArrayMap<>();
-        }
-        keyToValue.put(key, object);
-        targets.put(getPkgKey(userId, pkg), keyToValue);
-    }
-
-    private <T> T removeRecordLocked(String pkg, String key, Integer userId,
-            ArrayMap<String, ArrayMap<String, T>> targets) {
-        T object = null;
-        ArrayMap<String, T> keyToValue = targets.get(getPkgKey(userId, pkg));
-        if (keyToValue == null) {
-            return null;
-        }
-        object = keyToValue.remove(key);
-        if (keyToValue.size() == 0) {
-            targets.remove(getPkgKey(userId, pkg));
-        }
-        return object;
-    }
-
     protected boolean cancel(int userId, String pkg, String tag, int id) {
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> recordsForPkg =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (recordsForPkg != null) {
-                final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
-                for (Map.Entry<String, NotificationRecord> record : records) {
-                    final StatusBarNotification sbn = record.getValue().getSbn();
-                    if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
-                        record.getValue().isCanceled = true;
-                        return true;
-                    }
+            final Set<Map.Entry<String, NotificationRecord>> records =
+                    mSnoozedNotifications.entrySet();
+            for (Map.Entry<String, NotificationRecord> record : records) {
+                final StatusBarNotification sbn = record.getValue().getSbn();
+                if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
+                        && Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
+                    record.getValue().isCanceled = true;
+                    return true;
                 }
             }
         }
@@ -336,11 +251,9 @@
             if (includeCurrentProfiles) {
                 userIds = mUserProfiles.getCurrentProfileIds();
             }
-            for (ArrayMap<String, NotificationRecord> snoozedRecords : mSnoozedNotifications.values()) {
-                for (NotificationRecord r : snoozedRecords.values()) {
-                    if (userIds.binarySearch(r.getUserId()) >= 0) {
-                        r.isCanceled = true;
-                    }
+            for (NotificationRecord r : mSnoozedNotifications.values()) {
+                if (userIds.binarySearch(r.getUserId()) >= 0) {
+                    r.isCanceled = true;
                 }
             }
         }
@@ -348,14 +261,12 @@
 
     protected boolean cancel(int userId, String pkg) {
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> records =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (records == null) {
-                return false;
-            }
-            int N = records.size();
-            for (int i = 0; i < N; i++) {
-                records.valueAt(i).isCanceled = true;
+            int n = mSnoozedNotifications.size();
+            for (int i = 0; i < n; i++) {
+                final NotificationRecord r = mSnoozedNotifications.valueAt(i);
+                if (r.getSbn().getPackageName().equals(pkg) && r.getUserId() == userId) {
+                    r.isCanceled = true;
+                }
             }
             return true;
         }
@@ -366,20 +277,17 @@
      */
     protected void update(int userId, NotificationRecord record) {
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> records =
-                    mSnoozedNotifications.get(getPkgKey(userId, record.getSbn().getPackageName()));
-            if (records == null) {
-                return;
+            if (mSnoozedNotifications.containsKey(record.getKey())) {
+                mSnoozedNotifications.put(record.getKey(), record);
             }
-            records.put(record.getKey(), record);
         }
     }
 
     protected void repost(String key, boolean muteOnReturn) {
         synchronized (mLock) {
-            Integer userId = mUsers.get(key);
-            if (userId != null) {
-                repost(key, userId, muteOnReturn);
+            final NotificationRecord r = mSnoozedNotifications.get(key);
+            if (r != null) {
+                repost(key, r.getUserId(), muteOnReturn);
             }
         }
     }
@@ -387,43 +295,30 @@
     protected void repost(String key, int userId, boolean muteOnReturn) {
         NotificationRecord record;
         synchronized (mLock) {
-            final String pkg = mPackages.remove(key);
-            mUsers.remove(key);
-            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications);
-            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
-            ArrayMap<String, NotificationRecord> records =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (records == null) {
-                return;
-            }
-            record = records.remove(key);
-
+            mPersistedSnoozedNotifications.remove(key);
+            mPersistedSnoozedNotificationsWithContext.remove(key);
+            record = mSnoozedNotifications.remove(key);
         }
 
         if (record != null && !record.isCanceled) {
-            final PendingIntent pi = createPendingIntent(
-                    record.getSbn().getPackageName(), record.getKey(), userId);
+            final PendingIntent pi = createPendingIntent(record.getKey());
             mAm.cancel(pi);
             MetricsLogger.action(record.getLogMaker()
                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                     .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
-            mCallback.repost(userId, record, muteOnReturn);
+            mCallback.repost(record.getUserId(), record, muteOnReturn);
         }
     }
 
     protected void repostGroupSummary(String pkg, int userId, String groupKey) {
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> recordsByKey
-                    = mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (recordsByKey == null) {
-                return;
-            }
-
             String groupSummaryKey = null;
-            int N = recordsByKey.size();
-            for (int i = 0; i < N; i++) {
-                final NotificationRecord potentialGroupSummary = recordsByKey.valueAt(i);
-                if (potentialGroupSummary.getSbn().isGroup()
+            int n = mSnoozedNotifications.size();
+            for (int i = 0; i < n; i++) {
+                final NotificationRecord potentialGroupSummary = mSnoozedNotifications.valueAt(i);
+                if (potentialGroupSummary.getSbn().getPackageName().equals(pkg)
+                        && potentialGroupSummary.getUserId() == userId
+                        && potentialGroupSummary.getSbn().isGroup()
                         && potentialGroupSummary.getNotification().isGroupSummary()
                         && groupKey.equals(potentialGroupSummary.getGroupKey())) {
                     groupSummaryKey = potentialGroupSummary.getKey();
@@ -432,16 +327,14 @@
             }
 
             if (groupSummaryKey != null) {
-                NotificationRecord record = recordsByKey.remove(groupSummaryKey);
-                mPackages.remove(groupSummaryKey);
-                mUsers.remove(groupSummaryKey);
+                NotificationRecord record = mSnoozedNotifications.remove(groupSummaryKey);
 
                 if (record != null && !record.isCanceled) {
                     Runnable runnable = () -> {
                         MetricsLogger.action(record.getLogMaker()
                                 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                                 .setType(MetricsProto.MetricsEvent.TYPE_OPEN));
-                        mCallback.repost(userId, record, false);
+                        mCallback.repost(record.getUserId(), record, false);
                     };
                     runnable.run();
                 }
@@ -451,20 +344,17 @@
 
     protected void clearData(int userId, String pkg) {
         synchronized (mLock) {
-            ArrayMap<String, NotificationRecord> records =
-                    mSnoozedNotifications.get(getPkgKey(userId, pkg));
-            if (records == null) {
-                return;
-            }
-            for (int i = records.size() - 1; i >= 0; i--) {
-                final NotificationRecord r = records.removeAt(i);
-                if (r != null) {
-                    mPackages.remove(r.getKey());
-                    mUsers.remove(r.getKey());
+            int n = mSnoozedNotifications.size();
+            for (int i = n - 1; i >= 0; i--) {
+                final NotificationRecord record = mSnoozedNotifications.valueAt(i);
+                if (record.getUserId() == userId && record.getSbn().getPackageName().equals(pkg)) {
+                    mSnoozedNotifications.removeAt(i);
+                    mPersistedSnoozedNotificationsWithContext.remove(record.getKey());
+                    mPersistedSnoozedNotifications.remove(record.getKey());
                     Runnable runnable = () -> {
-                        final PendingIntent pi = createPendingIntent(pkg, r.getKey(), userId);
+                        final PendingIntent pi = createPendingIntent(record.getKey());
                         mAm.cancel(pi);
-                        MetricsLogger.action(r.getLogMaker()
+                        MetricsLogger.action(record.getLogMaker()
                                 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
                                 .setType(MetricsProto.MetricsEvent.TYPE_DISMISS));
                     };
@@ -474,47 +364,61 @@
         }
     }
 
-    private PendingIntent createPendingIntent(String pkg, String key, int userId) {
+    protected void clearData(int userId) {
+        synchronized (mLock) {
+            int n = mSnoozedNotifications.size();
+            for (int i = n - 1; i >= 0; i--) {
+                final NotificationRecord record = mSnoozedNotifications.valueAt(i);
+                if (record.getUserId() == userId) {
+                    mSnoozedNotifications.removeAt(i);
+                    mPersistedSnoozedNotificationsWithContext.remove(record.getKey());
+                    mPersistedSnoozedNotifications.remove(record.getKey());
+
+                    Runnable runnable = () -> {
+                        final PendingIntent pi = createPendingIntent(record.getKey());
+                        mAm.cancel(pi);
+                        MetricsLogger.action(record.getLogMaker()
+                                .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED)
+                                .setType(MetricsProto.MetricsEvent.TYPE_DISMISS));
+                    };
+                    runnable.run();
+                }
+            }
+        }
+    }
+
+    private PendingIntent createPendingIntent(String key) {
         return PendingIntent.getBroadcast(mContext,
                 REQUEST_CODE_REPOST,
                 new Intent(REPOST_ACTION)
                         .setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
                         .setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build())
                         .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(EXTRA_KEY, key)
-                        .putExtra(EXTRA_USER_ID, userId),
+                        .putExtra(EXTRA_KEY, key),
                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
     }
 
     public void scheduleRepostsForPersistedNotifications(long currentTime) {
         synchronized (mLock) {
-            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);
-                    }
+            for (int i = 0; i < mPersistedSnoozedNotifications.size(); i++) {
+                String key = mPersistedSnoozedNotifications.keyAt(i);
+                Long time = mPersistedSnoozedNotifications.valueAt(i);
+                if (time != null && time > currentTime) {
+                    scheduleRepostAtTime(key, time);
                 }
             }
         }
     }
 
-    private void scheduleRepost(String pkg, String key, int userId, long duration) {
-        scheduleRepostAtTime(pkg, key, userId, System.currentTimeMillis() + duration);
+    private void scheduleRepost(String key, long duration) {
+        scheduleRepostAtTime(key, System.currentTimeMillis() + duration);
     }
 
-    private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
+    private void scheduleRepostAtTime(String key, long time) {
         Runnable runnable = () -> {
             final long identity = Binder.clearCallingIdentity();
             try {
-                final PendingIntent pi = createPendingIntent(pkg, key, userId);
+                final PendingIntent pi = createPendingIntent(key);
                 mAm.cancel(pi);
                 if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
                 mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
@@ -528,37 +432,14 @@
     public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
         synchronized (mLock) {
             pw.println("\n  Snoozed notifications:");
-            for (String userPkgKey : mSnoozedNotifications.keySet()) {
+            for (String key : mSnoozedNotifications.keySet()) {
                 pw.print(INDENT);
-                pw.println("key: " + userPkgKey);
-                ArrayMap<String, NotificationRecord> snoozedRecords =
-                        mSnoozedNotifications.get(userPkgKey);
-                Set<String> snoozedKeys = snoozedRecords.keySet();
-                for (String key : snoozedKeys) {
-                    pw.print(INDENT);
-                    pw.print(INDENT);
-                    pw.print(INDENT);
-                    pw.println(key);
-                }
+                pw.println("key: " + key);
             }
             pw.println("\n Pending snoozed notifications");
-            for (String userPkgKey : mPersistedSnoozedNotifications.keySet()) {
+            for (String key : mPersistedSnoozedNotifications.keySet()) {
                 pw.print(INDENT);
-                pw.println("key: " + userPkgKey);
-                ArrayMap<String, Long> snoozedRecords =
-                        mPersistedSnoozedNotifications.get(userPkgKey);
-                if (snoozedRecords == null) {
-                    continue;
-                }
-                Set<String> snoozedKeys = snoozedRecords.keySet();
-                for (String key : snoozedKeys) {
-                    pw.print(INDENT);
-                    pw.print(INDENT);
-                    pw.print(INDENT);
-                    pw.print(key);
-                    pw.print(INDENT);
-                    pw.println(snoozedRecords.get(key));
-                }
+                pw.println("key: " + key + " until: " + mPersistedSnoozedNotifications.get(key));
             }
         }
     }
@@ -589,37 +470,22 @@
         void insert(T t) throws IOException;
     }
 
-    private <T> void writeXml(TypedXmlSerializer out,
-            ArrayMap<String, ArrayMap<String, T>> targets, String tag,
-            Inserter<T> attributeInserter)
-            throws IOException {
-        final int M = targets.size();
-        for (int i = 0; i < M; i++) {
+    private <T> void writeXml(TypedXmlSerializer out, ArrayMap<String, T> targets, String tag,
+            Inserter<T> attributeInserter) throws IOException {
+        for (int j = 0; j < targets.size(); j++) {
+            String key = targets.keyAt(j);
             // 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);
+            T value = targets.valueAt(j);
 
-                if (pkg == null || userId == null) {
-                    Slog.w(TAG, "pkg " + pkg + " or user " + userId + " missing for " + key);
-                    continue;
-                }
+            out.startTag(null, tag);
 
-                out.startTag(null, tag);
+            attributeInserter.insert(value);
 
-                attributeInserter.insert(value);
+            out.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
+                    XML_SNOOZED_NOTIFICATION_VERSION);
+            out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
 
-                out.attributeInt(null, XML_SNOOZED_NOTIFICATION_VERSION_LABEL,
-                        XML_SNOOZED_NOTIFICATION_VERSION);
-                out.attribute(null, XML_SNOOZED_NOTIFICATION_KEY, key);
-                out.attribute(null, XML_SNOOZED_NOTIFICATION_PKG, pkg);
-                out.attributeInt(null, XML_SNOOZED_NOTIFICATION_USER_ID, userId);
-
-                out.endTag(null, tag);
-            }
+            out.endTag(null, tag);
         }
     }
 
@@ -639,16 +505,12 @@
                         == XML_SNOOZED_NOTIFICATION_VERSION) {
                 try {
                     final String key = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_KEY);
-                    final String pkg = parser.getAttributeValue(null, XML_SNOOZED_NOTIFICATION_PKG);
-                    final int userId = parser.getAttributeInt(
-                            null, XML_SNOOZED_NOTIFICATION_USER_ID, UserHandle.USER_ALL);
                     if (tag.equals(XML_SNOOZED_NOTIFICATION)) {
                         final Long time = parser.getAttributeLong(
                                 null, XML_SNOOZED_NOTIFICATION_TIME, 0);
                         if (time > currentTime) { //only read new stuff
                             synchronized (mLock) {
-                                storeRecordLocked(
-                                        pkg, key, userId, mPersistedSnoozedNotifications, time);
+                                mPersistedSnoozedNotifications.put(key, time);
                             }
                         }
                     }
@@ -656,9 +518,7 @@
                         final String creationId = parser.getAttributeValue(
                                 null, XML_SNOOZED_NOTIFICATION_CONTEXT_ID);
                         synchronized (mLock) {
-                            storeRecordLocked(
-                                    pkg, key, userId, mPersistedSnoozedNotificationsWithContext,
-                                    creationId);
+                            mPersistedSnoozedNotificationsWithContext.put(key, creationId);
                         }
                     }
                 } catch (Exception e) {
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 8bead57..7817e81 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -20,6 +20,7 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
@@ -39,7 +40,6 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -50,7 +50,6 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
 import com.android.server.pm.PackageManagerService;
 
@@ -60,9 +59,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -198,18 +195,6 @@
     }
 
     @Test
-    public void testCleanupContextShouldRemovePersistedRecord() {
-        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r, "context");
-        mSnoozeHelper.cleanupPersistedContext(r.getSbn().getKey());
-        assertNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification(
-                r.getUser().getIdentifier(),
-                r.getSbn().getPackageName(),
-                r.getSbn().getKey()
-        ));
-    }
-
-    @Test
     public void testReadNoneSnoozedNotification() throws XmlPullParserException,
             IOException, InterruptedException {
         NotificationRecord r = getNotificationRecord(
@@ -219,8 +204,9 @@
         assertEquals("should see a zero value for unsnoozed notification",
                 0L,
                 mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
-                        UserHandle.SYSTEM.getIdentifier(),
-                        "not_my_package", r.getKey()).longValue());
+                        UserHandle.SYSTEM.getIdentifier(), "not_my_package",
+                        getNotificationRecord("not_my_package", 1, "one",
+                                UserHandle.SYSTEM).getKey()).longValue());
     }
 
     @Test
@@ -592,7 +578,7 @@
     }
 
     @Test
-    public void testClearData() {
+    public void testClearData_userPackage() {
         // snooze 2 from same package
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
@@ -616,17 +602,72 @@
     }
 
     @Test
+    public void testClearData_user() {
+        // snooze 2 from same package
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg2", 2, "two", UserHandle.SYSTEM);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+        NotificationRecord r4 = getNotificationRecord("pkg", 2, "two", UserHandle.ALL);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, "until");
+        mSnoozeHelper.snooze(r4, "until");
+
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r2.getSbn().getPackageName(), r2.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r3.getSbn().getPackageName(), r3.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_ALL, r4.getSbn().getPackageName(), r4.getKey()));
+
+        // clear data
+        mSnoozeHelper.clearData(UserHandle.USER_SYSTEM);
+
+        // nothing in USER_SYSTEM snoozed; alarms canceled
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r2.getSbn().getPackageName(), r2.getKey()));
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r3.getSbn().getPackageName(), r3.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, r4.getSbn().getPackageName(), r4.getKey()));
+
+        assertNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+                r3.getUser().getIdentifier(), r3.getSbn().getPackageName(),
+                r3.getSbn().getKey()));
+        assertNotNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+                r4.getUser().getIdentifier(), r4.getSbn().getPackageName(),
+                r4.getSbn().getKey()));
+        assertEquals(0L, mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+                r.getUser().getIdentifier(), r.getSbn().getPackageName(),
+                r.getSbn().getKey()).longValue());
+        assertEquals(0L, mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+                r2.getUser().getIdentifier(), r2.getSbn().getPackageName(),
+                r2.getSbn().getKey()).longValue());
+
+        // 2 for initial timed-snoozes, once each for canceling the USER_SYSTEM snoozes
+        verify(mAm, times(5)).cancel(any(PendingIntent.class));
+    }
+
+    @Test
     public void testClearData_otherRecordsUntouched() {
         // 2 packages, 2 users
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord rb = getNotificationRecord("pkg", 1, "oneb", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.ALL);
         NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(rb, "until");
         mSnoozeHelper.snooze(r2, 1000);
         mSnoozeHelper.snooze(r3, 1000);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, rb.getSbn().getPackageName(), rb.getKey()));
+        assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_ALL, r2.getSbn().getPackageName(), r2.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r3.getSbn().getPackageName(), r3.getKey()));
@@ -636,12 +677,22 @@
 
         assertFalse(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
+        assertFalse(mSnoozeHelper.isSnoozed(
+                UserHandle.USER_SYSTEM, rb.getSbn().getPackageName(), rb.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_ALL, r2.getSbn().getPackageName(), r2.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r3.getSbn().getPackageName(), r3.getKey()));
+
+        assertNull(mSnoozeHelper.getSnoozeContextForUnpostedNotification(
+                rb.getUser().getIdentifier(), rb.getSbn().getPackageName(),
+                rb.getSbn().getKey()));
+        assertEquals(0L, mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+                r.getUser().getIdentifier(), r.getSbn().getPackageName(),
+                r.getSbn().getKey()).longValue());
+
         // once for each initial snooze, once for canceling one snooze
-        verify(mAm, times(4)).cancel(any(PendingIntent.class));
+        verify(mAm, times(5)).cancel(any(PendingIntent.class));
     }
 
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,