Snoozing API changes

- No one can snooze for an undetermined amount of time
- Only the assistant can unsnooze
- Listeners can retrieve a list of snoozed notifications

Test: runtest systemui-notification, cts verifier
Change-Id: Idfaee6d8bc15a5d41630f86f7e852468b07dc7d0
diff --git a/api/current.txt b/api/current.txt
index 42242a7..ad28b94 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35814,6 +35814,7 @@
     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 final void unsnoozeNotification(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";
   }
@@ -35829,6 +35830,7 @@
     method public final int getCurrentInterruptionFilter();
     method public final int getCurrentListenerHints();
     method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+    method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onInterruptionFilterChanged(int);
     method public void onListenerConnected();
@@ -35847,8 +35849,6 @@
     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);
     field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index c159938..b9e89f6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -38797,6 +38797,7 @@
     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 final void unsnoozeNotification(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";
   }
@@ -38814,6 +38815,7 @@
     method public final int getCurrentInterruptionFilter();
     method public final int getCurrentListenerHints();
     method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+    method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onInterruptionFilterChanged(int);
     method public void onListenerConnected();
@@ -38834,9 +38836,7 @@
     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;
-    method public final void unsnoozeNotification(java.lang.String);
     field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
diff --git a/api/test-current.txt b/api/test-current.txt
index cc17d7f..0e6548e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35935,6 +35935,7 @@
     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 final void unsnoozeNotification(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";
   }
@@ -35950,6 +35951,7 @@
     method public final int getCurrentInterruptionFilter();
     method public final int getCurrentListenerHints();
     method public android.service.notification.NotificationListenerService.RankingMap getCurrentRanking();
+    method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onInterruptionFilterChanged(int);
     method public void onListenerConnected();
@@ -35968,8 +35970,6 @@
     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);
     field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
     field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index d674bfe..740af9c 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -75,8 +75,6 @@
 
     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);
 
     void requestBindListener(in ComponentName component);
     void requestUnbindListener(in INotificationListener token);
@@ -86,6 +84,7 @@
     void setNotificationsShownFromListener(in INotificationListener token, in String[] keys);
 
     ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
+    ParceledListSlice getSnoozedNotificationsFromListener(in INotificationListener token, int trim);
     void requestHintsFromListener(in INotificationListener token, int hints);
     int getHintsFromListener(in INotificationListener token);
     void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
@@ -100,6 +99,7 @@
     void updateNotificationChannelFromAssistant(in INotificationListener token, String pkg, in NotificationChannel channel);
     void deleteNotificationChannelFromAssistant(in INotificationListener token, String pkg, String channelId);
     ParceledListSlice getNotificationChannelsFromAssistant(in INotificationListener token, String pkg);
+    void unsnoozeNotificationFromAssistant(in INotificationListener token, String key);
 
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index d7a02a8..cecdbee 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -119,6 +119,24 @@
     }
 
     /**
+     * Inform the notification manager about un-snoozing a specific notification.
+     * <p>
+     * This should only be used for notifications snoozed by this listener using
+     * {@link #snoozeNotification(String, String)}. Once un-snoozed, you will get a
+     * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
+     * notification.
+     * @param key The key of the notification to snooze
+     */
+    public final void unsnoozeNotification(String key) {
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().unsnoozeNotificationFromAssistant(mWrapper, key);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+    }
+
+    /**
      * Creates a notification channel that notifications can be posted to for a given package.
      *
      * @param pkg The package to create a channel for.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d930689..517b305 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -562,43 +562,6 @@
         }
     }
 
-    /**
-     * Inform the notification manager about snoozing a specific notification.
-     * <p>
-     * Use this to snooze a notification for an indeterminate time.  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. Use {@link #unsnoozeNotification(String)} to restore the notification.
-     * @param key The key of the notification to snooze
-     */
-    public final void snoozeNotification(String key) {
-        if (!isBound()) return;
-        try {
-            getNotificationInterface().snoozeNotificationFromListener(mWrapper, key);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-    }
-
-    /**
-     * Inform the notification manager about un-snoozing a specific notification.
-     * <p>
-     * This should only be used for notifications snoozed by this listener using
-     * {@link #snoozeNotification(String)}. Once un-snoozed, you will get a
-     * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
-     * notification.
-     * @param key The key of the notification to snooze
-     */
-    public final void unsnoozeNotification(String key) {
-        if (!isBound()) return;
-        try {
-            getNotificationInterface().unsnoozeNotificationFromListener(mWrapper, key);
-        } catch (android.os.RemoteException ex) {
-            Log.v(TAG, "Unable to contact notification manager", ex);
-        }
-    }
 
     /**
      * Inform the notification manager that these notifications have been viewed by the
@@ -663,6 +626,26 @@
     }
 
     /**
+     * Like {@link #getActiveNotifications()}, but returns the list of currently snoozed
+     * notifications, for all users this listener has access to.
+     *
+     * <p>The service should wait for the {@link #onListenerConnected()} event
+     * before performing this operation.
+     *
+     * @return An array of active notifications, sorted in natural order.
+     */
+    public final StatusBarNotification[] getSnoozedNotifications() {
+        try {
+            ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
+                    .getSnoozedNotificationsFromListener(mWrapper, TRIM_FULL);
+            return cleanUpNotificationList(parceledList);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
+        return null;
+    }
+
+    /**
      * Request the list of outstanding notifications (that is, those that are visible to the
      * current user). Useful when you don't know what's already been posted.
      *
@@ -711,36 +694,41 @@
         try {
             ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
                     .getActiveNotificationsFromListener(mWrapper, keys, trim);
-            List<StatusBarNotification> list = parceledList.getList();
-            ArrayList<StatusBarNotification> corruptNotifications = null;
-            int N = list.size();
-            for (int i = 0; i < N; i++) {
-                StatusBarNotification sbn = list.get(i);
-                Notification notification = sbn.getNotification();
-                try {
-                    // convert icon metadata to legacy format for older clients
-                    createLegacyIconExtras(notification);
-                    // populate remote views for older clients.
-                    maybePopulateRemoteViews(notification);
-                } catch (IllegalArgumentException e) {
-                    if (corruptNotifications == null) {
-                        corruptNotifications = new ArrayList<>(N);
-                    }
-                    corruptNotifications.add(sbn);
-                    Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
-                            sbn.getPackageName());
-                }
-            }
-            if (corruptNotifications != null) {
-                list.removeAll(corruptNotifications);
-            }
-            return list.toArray(new StatusBarNotification[list.size()]);
+            return cleanUpNotificationList(parceledList);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
         return null;
     }
 
+    private StatusBarNotification[] cleanUpNotificationList(
+            ParceledListSlice<StatusBarNotification> parceledList) {
+        List<StatusBarNotification> list = parceledList.getList();
+        ArrayList<StatusBarNotification> corruptNotifications = null;
+        int N = list.size();
+        for (int i = 0; i < N; i++) {
+            StatusBarNotification sbn = list.get(i);
+            Notification notification = sbn.getNotification();
+            try {
+                // convert icon metadata to legacy format for older clients
+                createLegacyIconExtras(notification);
+                // populate remote views for older clients.
+                maybePopulateRemoteViews(notification);
+            } catch (IllegalArgumentException e) {
+                if (corruptNotifications == null) {
+                    corruptNotifications = new ArrayList<>(N);
+                }
+                corruptNotifications.add(sbn);
+                Log.w(TAG, "get(Active/Snoozed)Notifications: can't rebuild notification from " +
+                        sbn.getPackageName());
+            }
+        }
+        if (corruptNotifications != null) {
+            list.removeAll(corruptNotifications);
+        }
+        return list.toArray(new StatusBarNotification[list.size()]);
+    }
+
     /**
      * Gets the set of hints representing current state.
      *
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 96459be..72faa81 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1944,31 +1944,16 @@
         }
 
         /**
-         * Allow an INotificationListener to snooze a single notification.
+         * Allows the notification assistant to un-snooze a single notification.
          *
-         * @param token The binder for the listener, to check that the caller is allowed
+         * @param token The binder for the assistant, to check that the caller is allowed
          */
         @Override
-        public void snoozeNotificationFromListener(INotificationListener token, String key) {
+        public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
             long identity = Binder.clearCallingIdentity();
             try {
-                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, null, info);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        /**
-         * Allow an INotificationListener to un-snooze a single notification.
-         *
-         * @param token The binder for the listener, to check that the caller is allowed
-         */
-        @Override
-        public void unsnoozeNotificationFromListener(INotificationListener token, String key) {
-            long identity = Binder.clearCallingIdentity();
-            try {
-                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                final ManagedServiceInfo info =
+                        mNotificationAssistants.checkServiceTokenLocked(token);
                 unsnoozeNotificationInt(key, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -2039,6 +2024,36 @@
             }
         }
 
+        /**
+         * Allow an INotificationListener to request the list of outstanding snoozed notifications
+         * seen by the current user. Useful when starting up, after which point the listener
+         * callbacks should be used.
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         * @returns The return value will contain the notifications specified in keys, in that
+         *      order, or if keys is null, all the notifications, in natural order.
+         */
+        @Override
+        public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
+                INotificationListener token, int trim) {
+            synchronized (mNotificationLock) {
+                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+                List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
+                final int N = snoozedRecords.size();
+                final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
+                for (int i=0; i < N; i++) {
+                    final NotificationRecord r = snoozedRecords.get(i);
+                    if (r == null) continue;
+                    StatusBarNotification sbn = r.sbn;
+                    if (!isVisibleToListener(sbn, info)) continue;
+                    StatusBarNotification sbnToSend =
+                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
+                    list.add(sbnToSend);
+                }
+                return new ParceledListSlice<>(list);
+            }
+        }
+
         @Override
         public void requestHintsFromListener(INotificationListener token, int hints) {
             final long identity = Binder.clearCallingIdentity();
@@ -3982,14 +3997,14 @@
     void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
+        if (until < System.currentTimeMillis() && snoozeCriterionId == null) {
+            return;
+        }
         // TODO: write to event log
         if (DBG) {
             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
                     listenerName));
         }
-        if (until != SNOOZE_UNTIL_UNSPECIFIED && until < System.currentTimeMillis()) {
-            return;
-        }
         // Needs to post so that it can cancel notifications not yet enqueued.
         mHandler.post(new Runnable() {
             @Override
@@ -4002,8 +4017,6 @@
                         if (snoozeCriterionId != null) {
                             mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
                                     snoozeCriterionId);
-                        }
-                        if (until == SNOOZE_UNTIL_UNSPECIFIED) {
                             mSnoozeHelper.snooze(r);
                         } else {
                             mSnoozeHelper.snooze(r, until);
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index e14700a..f2aff11 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -41,6 +41,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -98,6 +99,26 @@
         return Collections.EMPTY_LIST;
     }
 
+    protected List<NotificationRecord> getSnoozed() {
+        List<NotificationRecord> snoozedForUser = new ArrayList<>();
+        int[] userIds = mUserProfiles.getCurrentProfileIds();
+        final int N = userIds.length;
+        for (int i = 0; i < N; i++) {
+            final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+                    mSnoozedNotifications.get(userIds[i]);
+            if (snoozedPkgs != null) {
+                final int M = snoozedPkgs.size();
+                for (int j = 0; j < M; j++) {
+                    final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
+                    if (records != null) {
+                        snoozedForUser.addAll(records.values());
+                    }
+                }
+            }
+        }
+        return snoozedForUser;
+    }
+
     /**
      * Snoozes a notification and schedules an alarm to repost at that time.
      */
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 92d9810..250aab8 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -361,17 +361,4 @@
                 mBinderService.getActiveNotifications(sbn.getPackageName());
         assertEquals(1, notifs.length);
     }
-
-    @Test
-    @UiThreadTest
-    public void testSnoozeNotificationImmediatelyAfterEnqueue() throws Exception {
-        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
-        mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), "opPkg", "tag",
-                sbn.getId(), sbn.getNotification(), new int[1], sbn.getUserId());
-        mBinderService.snoozeNotificationFromListener(null, sbn.getKey());
-        waitForIdle();
-        StatusBarNotification[] notifs =
-                mBinderService.getActiveNotifications(sbn.getPackageName());
-        assertEquals(0, notifs.length);
-    }
 }
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 b7931d4..69724f4 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -33,6 +33,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 import static org.mockito.Matchers.any;
@@ -42,6 +43,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 
 @SmallTest
@@ -190,6 +192,39 @@
         verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
     }
 
+    @Test
+    public void testGetSnoozedByUser() throws Exception {
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+        NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
+        mSnoozeHelper.snooze(r4, 1000);
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+                new int[] {UserHandle.USER_SYSTEM});
+        assertEquals(3, mSnoozeHelper.getSnoozed().size());
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+                new int[] {UserHandle.USER_CURRENT});
+        assertEquals(1, mSnoozeHelper.getSnoozed().size());
+    }
+
+    @Test
+    public void testGetSnoozedByUser_managedProfiles() throws Exception {
+        when(mUserProfiles.getCurrentProfileIds()).thenReturn(
+                new int[] {UserHandle.USER_SYSTEM, UserHandle.USER_CURRENT});
+        NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+        NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+        NotificationRecord r4 = getNotificationRecord("pkg2", 3, "three", UserHandle.CURRENT);
+        mSnoozeHelper.snooze(r, 1000);
+        mSnoozeHelper.snooze(r2, 1000);
+        mSnoozeHelper.snooze(r3, 1000);
+        mSnoozeHelper.snooze(r4, 1000);
+        assertEquals(4, mSnoozeHelper.getSnoozed().size());
+    }
+
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
             UserHandle user) {
         Notification n = new Notification.Builder(getContext())