Send Snooze callback for Assistant

On selection of a snooze context SnoozeCriterion.

Test: runtest systemui-notification & make cts-verifier
Change-Id: Iaca567100c29295fbbf1d327195a114106909652
diff --git a/api/current.txt b/api/current.txt
index c7577e4..61e12c7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35451,6 +35451,7 @@
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
@@ -35482,6 +35483,7 @@
     method public static void requestRebind(android.content.ComponentName);
     method public final void requestUnbind();
     method public final void setNotificationsShown(java.lang.String[]);
+    method public final void snoozeNotification(java.lang.String, java.lang.String);
     method public final void snoozeNotification(java.lang.String, long);
     method public final void snoozeNotification(java.lang.String);
     method public final void unsnoozeNotification(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 28674ca..80c4fac5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -38320,6 +38320,7 @@
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
@@ -38355,6 +38356,7 @@
     method public final void requestUnbind();
     method public final void setNotificationsShown(java.lang.String[]);
     method public final void setOnNotificationPostedTrim(int);
+    method public final void snoozeNotification(java.lang.String, java.lang.String);
     method public final void snoozeNotification(java.lang.String, long);
     method public final void snoozeNotification(java.lang.String);
     method public void unregisterAsSystemService() throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index 71b8c1d..ab616f9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35569,6 +35569,7 @@
     method public java.util.List<android.app.NotificationChannel> getNotificationChannels(java.lang.String);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
     method public void updateNotificationChannel(java.lang.String, android.app.NotificationChannel);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
@@ -35600,6 +35601,7 @@
     method public static void requestRebind(android.content.ComponentName);
     method public final void requestUnbind();
     method public final void setNotificationsShown(java.lang.String[]);
+    method public final void snoozeNotification(java.lang.String, java.lang.String);
     method public final void snoozeNotification(java.lang.String, long);
     method public final void snoozeNotification(java.lang.String);
     method public final void unsnoozeNotification(java.lang.String);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 81aeaef..07c21a5 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -70,7 +70,7 @@
     void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
     void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
 
-
+    void snoozeNotificationUntilContextFromListener(in INotificationListener token, String key, String snoozeCriterionId);
     void snoozeNotificationUntilFromListener(in INotificationListener token, String key, long until);
     void snoozeNotificationFromListener(in INotificationListener token, String key);
     void unsnoozeNotificationFromListener(in INotificationListener token, String key);
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 7af93c2..9728fda 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -41,7 +41,10 @@
      */
     public static final String KEY_PEOPLE = "key_people";
     /**
-     * Parcelable {@code ArrayList} of {@link SnoozeCriterion}.
+     * Parcelable {@code ArrayList} of {@link SnoozeCriterion}. These criteria may be visible to
+     * users. If a user chooses to snooze a notification until one of these criterion, the
+     * assistant will be notified via
+     * {@link NotificationAssistantService#onNotificationSnoozedUntilContext}.
      */
     public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
 
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index f639c0d..01d3391 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -35,7 +35,5 @@
 
     // rankers only
     void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
-    void onNotificationVisibilityChanged(String key, long time, boolean visible);
-    void onNotificationClick(String key, long time);
-    void onNotificationActionClick(String key, long time, int actionIndex);
+    void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index cab390f..d7a02a8 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -63,6 +63,17 @@
     }
 
     /**
+     * A notification was snoozed until a context. For use with
+     * {@link Adjustment#KEY_SNOOZE_CRITERIA}. When the device reaches the given context, the
+     * assistant should restore the notification with {@link #unsnoozeNotification(String)}.
+     *
+     * @param sbn the notification to snooze
+     * @param snoozeCriterionId the {@link SnoozeCriterion#getId()} representing a device context.
+     */
+    abstract public void onNotificationSnoozedUntilContext(StatusBarNotification sbn,
+            String snoozeCriterionId);
+
+    /**
      * A notification was posted by an app. Called before alert.
      *
      * @param sbn the new notification
@@ -190,10 +201,30 @@
             mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
                     args).sendToTarget();
         }
+
+        @Override
+        public void onNotificationSnoozedUntilContext(
+                IStatusBarNotificationHolder sbnHolder, String snoozeCriterionId)
+                throws RemoteException {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationSnoozed: Error receiving StatusBarNotification", e);
+                return;
+            }
+
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = sbn;
+            args.arg2 = snoozeCriterionId;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_SNOOZED,
+                    args).sendToTarget();
+        }
     }
 
     private final class MyHandler extends Handler {
         public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
+        public static final int MSG_ON_NOTIFICATION_SNOOZED = 2;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -219,7 +250,16 @@
                             throw ex.rethrowFromSystemServer();
                         }
                     }
-                } break;
+                    break;
+                }
+                case MSG_ON_NOTIFICATION_SNOOZED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    String snoozeCriterionId = (String) args.arg2;
+                    args.recycle();
+                    onNotificationSnoozedUntilContext(sbn, snoozeCriterionId);
+                    break;
+                }
             }
         }
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1bc605f..694837e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -519,7 +519,31 @@
      * Inform the notification manager about snoozing a specific notification.
      * <p>
      * Use this if your listener has a user interface that allows the user to snooze a notification
-     * until a given time.  It should be called after the user snoozes a single notification using
+     * until a given {@link SnoozeCriterion}. It should be called after the user snoozes a single
+     * notification using your UI; upon being informed, the notification manager will actually
+     * remove the notification and you will get an
+     * {@link #onNotificationRemoved(StatusBarNotification)} callback. When the snoozing period
+     * expires, you will get a {@link #onNotificationPosted(StatusBarNotification, RankingMap)}
+     * callback for the notification.
+     * @param key The key of the notification to snooze
+     * @param snoozeCriterionId The{@link SnoozeCriterion#getId()} of a context to snooze the
+     *                          notification until.
+     */
+    public final void snoozeNotification(String key, String snoozeCriterionId) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().snoozeNotificationUntilContextFromListener(
+                    mWrapper, key, snoozeCriterionId);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
+     * Inform the notification manager about snoozing a specific notification.
+     * <p>
+     * Use this if your listener has a user interface that allows the user to snooze a notification
+     * until a given time. It should be called after the user snoozes a single notification using
      * your UI; upon being informed, the notification manager will actually remove the notification
      * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
      * snoozing period expires, you will get a
@@ -1094,21 +1118,12 @@
         }
 
         @Override
-        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+        public void onNotificationSnoozedUntilContext(
+                IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId)
                 throws RemoteException {
             // no-op in the listener
         }
 
-        @Override
-        public void onNotificationClick(String key, long time) throws RemoteException {
-            // no-op in the listener
-        }
-
-        @Override
-        public void onNotificationActionClick(String key, long time, int actionIndex)
-                throws RemoteException {
-            // no-op in the listener
-        }
     }
 
     /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a77a9cd..84b03d2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2993,7 +2993,7 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
-         android.service.notification.NotificationAssistantService to ensure that only the system
+         android.service.notification.NotificationAssistantService} to ensure that only the system
          can bind to it.
          <p>Protection level: signature
     -->
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ded8a1b..bff27ed 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1829,7 +1829,7 @@
          *
          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
          *
-         * @param token The binder for the listener, to check that the caller is allowed
+         * @param info The binder for the listener, to check that the caller is allowed
          */
         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
@@ -1840,7 +1840,24 @@
         }
 
         /**
-         * Allow an INotificationListener to snooze a single notification.
+         * Allow an INotificationListener to snooze a single notification until a context.
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public void snoozeNotificationUntilContextFromListener(INotificationListener token,
+                String key, String snoozeCriterionId) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                snoozeNotificationInt(key, snoozeCriterionId, info);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        /**
+         * Allow an INotificationListener to snooze a single notification until a time.
          *
          * @param token The binder for the listener, to check that the caller is allowed
          */
@@ -3845,12 +3862,31 @@
         }
     }
 
+    void snoozeNotificationInt(String key, String snoozeCriterionId, ManagedServiceInfo listener) {
+        String listenerName = listener == null ? null : listener.component.toShortString();
+        // TODO: write to event log
+        if (DBG) {
+            Slog.d(TAG, String.format("snooze event(%s, %s, %s)",
+                    key, snoozeCriterionId, listenerName));
+        }
+        synchronized (mNotificationList) {
+            final NotificationRecord r = mNotificationsByKey.get(key);
+            if (r != null) {
+                mNotificationList.remove(r);
+                cancelNotificationLocked(r, false, REASON_SNOOZED);
+                mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, snoozeCriterionId);
+                updateLightsLocked();
+                mSnoozeHelper.snooze(r);
+                savePolicyFile();
+            }
+        }
+    }
+
     void snoozeNotificationInt(String key, long until, ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         // TODO: write to event log
         if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %d, %s)", key, until,
-                    listenerName));
+            Slog.d(TAG, String.format("snooze event(%s, %d, %s)", key, until, listenerName));
         }
         if (until < System.currentTimeMillis()) {
             return;
@@ -3861,7 +3897,7 @@
                 mNotificationList.remove(r);
                 cancelNotificationLocked(r, false, REASON_SNOOZED);
                 updateLightsLocked();
-                mSnoozeHelper.snooze(r, r.getUser().getIdentifier(), until);
+                mSnoozeHelper.snooze(r, until);
                 savePolicyFile();
             }
         }
@@ -3879,7 +3915,7 @@
                 mNotificationList.remove(r);
                 cancelNotificationLocked(r, false, REASON_SNOOZED);
                 updateLightsLocked();
-                mSnoozeHelper.snooze(r, r.getUser().getIdentifier());
+                mSnoozeHelper.snooze(r);
                 savePolicyFile();
             }
         }
@@ -3891,8 +3927,8 @@
         if (DBG) {
             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
         }
-        mSnoozeHelper.repost(key, Binder.getCallingUid());
-                savePolicyFile();
+        mSnoozeHelper.repost(key);
+        savePolicyFile();
     }
 
     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
@@ -4273,6 +4309,33 @@
             }
         }
 
+        /**
+         * asynchronously notify the assistant that a notification has been snoozed until a
+         * context
+         */
+        public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
+                final String snoozeCriterionId) {
+            TrimCache trimCache = new TrimCache(sbn);
+            for (final ManagedServiceInfo info : mServices) {
+                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        final INotificationListener assistant =
+                                (INotificationListener) info.service;
+                        StatusBarNotificationHolder sbnHolder
+                                = new StatusBarNotificationHolder(sbnToPost);
+                        try {
+                            assistant.onNotificationSnoozedUntilContext(
+                                    sbnHolder, snoozeCriterionId);
+                        } catch (RemoteException ex) {
+                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+                        }
+                    }
+                });
+            }
+        }
+
         public boolean isEnabled() {
             return !mServices.isEmpty();
         }
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 733ff67..e14700a 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
@@ -68,6 +69,8 @@
             mSnoozedNotifications = new ArrayMap<>();
     // notification key : package.
     private ArrayMap<String, String> mPackages = new ArrayMap<>();
+    // key : userId
+    private ArrayMap<String, Integer> mUsers = new ArrayMap<>();
     private Callback mCallback;
 
     public SnoozeHelper(Context context, Callback callback,
@@ -98,15 +101,16 @@
     /**
      * Snoozes a notification and schedules an alarm to repost at that time.
      */
-    protected void snooze(NotificationRecord record, int userId, long until) {
-        snooze(record, userId);
-        scheduleRepost(record.sbn.getPackageName(), record.getKey(), userId, until);
+    protected void snooze(NotificationRecord record, long until) {
+        snooze(record);
+        scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), until);
     }
 
     /**
      * Records a snoozed notification.
      */
-    protected void snooze(NotificationRecord record, int userId) {
+    protected void snooze(NotificationRecord record) {
+        int userId = record.getUser().getIdentifier();
         if (DEBUG) {
             Slog.d(TAG, "Snoozing " + record.getKey());
         }
@@ -123,6 +127,7 @@
         records.put(record.sbn.getPackageName(), pkgRecords);
         mSnoozedNotifications.put(userId, records);
         mPackages.put(record.getKey(), record.sbn.getPackageName());
+        mUsers.put(record.getKey(), userId);
     }
 
     protected boolean cancel(int userId, String pkg, String tag, int id) {
@@ -142,6 +147,7 @@
                     recordsForPkg.remove(key);
                     cancelAlarm(userId, pkg, key);
                     mPackages.remove(key);
+                    mUsers.remove(key);
                     return true;
                 }
             }
@@ -165,8 +171,10 @@
                     if (records != null) {
                         int P = records.size();
                         for (int k = 0; k < P; k++) {
-                            cancelAlarm(userId, snoozedPkgs.keyAt(j), records.keyAt(k));
-                            mPackages.remove(records.keyAt(k));
+                            final String key = records.keyAt(k);
+                            cancelAlarm(userId, snoozedPkgs.keyAt(j), key);
+                            mPackages.remove(key);
+                            mUsers.remove(key);
                         }
                     }
                 }
@@ -183,8 +191,10 @@
                         mSnoozedNotifications.get(userId).remove(pkg);
                 int N = records.size();
                 for (int i = 0; i < N; i++) {
-                    cancelAlarm(userId, pkg, records.keyAt(i));
-                    mPackages.remove(records.keyAt(i));
+                    final String key = records.keyAt(i);
+                    cancelAlarm(userId, pkg, key);
+                    mPackages.remove(key);
+                    mUsers.remove(key);
                 }
                 return true;
             }
@@ -193,8 +203,13 @@
     }
 
     private void cancelAlarm(int userId, String pkg, String key) {
-        final PendingIntent pi = createPendingIntent(pkg, key, userId);
-        mAm.cancel(pi);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            final PendingIntent pi = createPendingIntent(pkg, key, userId);
+            mAm.cancel(pi);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     /**
@@ -213,6 +228,13 @@
         pkgRecords.put(record.getKey(), record);
     }
 
+    protected void repost(String key) {
+        Integer userId = mUsers.get(key);
+        if (userId != null) {
+            repost(key, userId);
+        }
+    }
+
     protected void repost(String key, int userId) {
         final String pkg = mPackages.remove(key);
         ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
@@ -243,10 +265,15 @@
     }
 
     private void scheduleRepost(String pkg, String key, int userId, long time) {
-        final PendingIntent pi = createPendingIntent(pkg, key, userId);
-        mAm.cancel(pi);
-        if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
-        mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            final PendingIntent pi = createPendingIntent(pkg, key, userId);
+            mAm.cancel(pi);
+            if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
+            mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index 4f6a35c..460fcdf 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -68,7 +68,7 @@
     @Test
     public void testSnoozeForTime() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+        mSnoozeHelper.snooze(r, 1000);
         verify(mAm, times(1)).setExactAndAllowWhileIdle(
                 anyInt(), eq((long) 1000), any(PendingIntent.class));
         assertTrue(mSnoozeHelper.isSnoozed(
@@ -78,7 +78,7 @@
     @Test
     public void testSnooze() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM);
+        mSnoozeHelper.snooze(r);
         verify(mAm, never()).setExactAndAllowWhileIdle(
                 anyInt(), anyLong(), any(PendingIntent.class));
         assertTrue(mSnoozeHelper.isSnoozed(
@@ -89,8 +89,8 @@
     public void testCancelByApp() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
-        mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2 , 1000);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
@@ -110,9 +110,9 @@
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
         NotificationRecord r3 = getNotificationRecord("pkg", 3, "three", UserHandle.ALL);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
-        mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
-        mSnoozeHelper.snooze(r3 , UserHandle.USER_ALL, 1000);
+        mSnoozeHelper.snooze(r,  1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
@@ -136,9 +136,9 @@
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
         NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
-        mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
-        mSnoozeHelper.snooze(r3 , UserHandle.USER_SYSTEM, 1000);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
@@ -160,17 +160,27 @@
     @Test
     public void testRepost() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+        mSnoozeHelper.snooze(r, 1000);
         NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
-        mSnoozeHelper.snooze(r2 , UserHandle.USER_ALL, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
         mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
         verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
     }
 
     @Test
+    public void testRepost_noUser() throws Exception {
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r, 1000);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.repost(r.getKey());
+        verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+    }
+
+    @Test
     public void testUpdate() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+        mSnoozeHelper.snooze(r , 1000);
         r.getNotification().category = "NEW CATEGORY";
 
         mSnoozeHelper.update(UserHandle.USER_SYSTEM, r);