Notification banning updates.

- Dismiss notifications from banned topics
- Don't ban all topics when banning an app.
- Block notifications from banned topics.

Bug: 26154396
Change-Id: I1d94e6176a413386d89f8dc1c4899aee8a8a73b8
diff --git a/api/current.txt b/api/current.txt
index 6c49041..10c3b67 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -33569,6 +33569,7 @@
     field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
     field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
     field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     field public static final int REASON_USER_STOPPED = 6; // 0x6
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 3ede80a..0933443 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -35705,6 +35705,7 @@
     field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
     field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
     field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     field public static final int REASON_USER_STOPPED = 6; // 0x6
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 306cf73..b1bb37a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -33583,6 +33583,7 @@
     field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
     field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
     field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
+    field public static final int REASON_TOPIC_BANNED = 14; // 0xe
     field public static final int REASON_USER_STOPPED = 6; // 0x6
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index aba82fa..035462d 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -95,6 +95,9 @@
     /** Notification was canceled because it was an invisible member of a group. */
     public static final int REASON_GROUP_OPTIMIZATION = 13;
 
+    /** Notification was canceled by the user banning the topic. */
+    public static final int REASON_TOPIC_BANNED = 14;
+
     public class Adjustment {
         int mImportance;
         CharSequence mExplanation;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e787eda..018bf2d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -28,6 +28,7 @@
 import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL;
 import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
 import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationAssistantService.REASON_TOPIC_BANNED;
 import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
@@ -741,7 +742,7 @@
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
-                                    changeUserId, REASON_PACKAGE_CHANGED, null);
+                                    changeUserId, REASON_PACKAGE_CHANGED, null, null);
                         }
                     }
                 }
@@ -774,7 +775,7 @@
                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 if (userHandle >= 0) {
                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
-                            REASON_USER_STOPPED, null);
+                            REASON_USER_STOPPED, null, null);
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
@@ -1051,7 +1052,7 @@
         // Now, cancel any outstanding notifications that are part of a just-disabled app
         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
-                    REASON_PACKAGE_BANNED, null);
+                    REASON_PACKAGE_BANNED, null, null);
         }
     }
 
@@ -1209,7 +1210,7 @@
             // running foreground services.
             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
                     pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
-                    REASON_APP_CANCEL_ALL, null);
+                    REASON_APP_CANCEL_ALL, null, null);
         }
 
         @Override
@@ -1266,6 +1267,11 @@
         public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
                 int importance) {
             enforceSystemOrSystemUI("Caller not system or systemui");
+            if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
+                cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
+                        UserHandle.getUserId(uid),
+                        REASON_TOPIC_BANNED, topic, null);
+            }
             mRankingHelper.setTopicImportance(pkg, uid, topic, importance);
             savePolicyFile();
         }
@@ -2284,8 +2290,9 @@
                     mRankingHelper.extractSignals(r);
                     savePolicyFile();
 
-                    // blocked apps
-                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
+                    // blocked apps/topics
+                    if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
+                            || !noteNotificationOp(pkg, callingUid)) {
                         if (!isSystemNotification) {
                             Slog.e(TAG, "Suppressing notification from package " + pkg
                                     + " by user request.");
@@ -3067,11 +3074,11 @@
     }
 
     /**
-     * Cancels all notifications from a given package that have all of the
+     * Cancels all notifications from a given package or topic that have all of the
      * {@code mustHaveFlags}.
      */
     boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
-            int mustNotHaveFlags, boolean doit, int userId, int reason,
+            int mustNotHaveFlags, boolean doit, int userId, int reason, Notification.Topic topic,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
@@ -3099,6 +3106,10 @@
                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
                     continue;
                 }
+                if (topic != null
+                        && !topic.getId().equals(r.getNotification().getTopic().getId())) {
+                    continue;
+                }
                 if (canceledNotifications == null) {
                     canceledNotifications = new ArrayList<>();
                 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index f1fd42c..ce4ecd3 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -423,14 +423,16 @@
 
     /**
      * Sets the default importance for all new topics that appear in the future, and resets
-     * the importance of all current topics.
+     * the importance of all current topics (unless the app is being blocked).
      */
     @Override
     public void setAppImportance(String pkgName, int uid, int importance) {
         final Record r = getOrCreateRecord(pkgName, uid);
         r.importance = importance;
-        for (Topic t :  r.topics.values()) {
-            t.importance = importance;
+        if (Ranking.IMPORTANCE_NONE != importance) {
+            for (Topic t : r.topics.values()) {
+                t.importance = importance;
+            }
         }
         updateConfig();
     }
@@ -483,7 +485,9 @@
             pw.print(prefix);
             pw.println("per-package config:");
         }
+        pw.println("Records:");
         dumpRecords(pw, prefix, filter, mRecords);
+        pw.println("Restored without uid:");
         dumpRecords(pw, prefix, filter, mRestoredWithoutUids);
     }
 
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index fecfdf9..3a30230 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -175,7 +175,7 @@
                         .setTopic(new Notification.Topic("hello", "Hello"))
                         .build();
 
-                mNM.notify(999, n);
+                mNM.notify(70, n);
             }
         },
 
@@ -194,7 +194,7 @@
                         .setStyle(picture)
                         .build();
 
-                mNM.notify(9999, n);
+                mNM.notify(71, n);
             }
         },
         new Test("with topic Bananas") {
@@ -211,10 +211,28 @@
                         .setTopic(new Notification.Topic("bananas", "Bananas"))
                         .build();
 
-                mNM.notify(999, n);
+                mNM.notify(72, n);
             }
         },
 
+            new Test("with delete intent") {
+                public void run() {
+                    Notification.BigTextStyle bigText = new Notification.BigTextStyle();
+                    bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon1)
+                            .setStyle(bigText)
+                            .setWhen(mActivityCreateTime)
+                            .setContentTitle("bananananana")
+                            .setContentText("This is a banana!!!")
+                            .setTopic(new Notification.Topic("bananas", "Bananas"))
+                            .setDeleteIntent(makeIntent2())
+                            .build();
+
+                    mNM.notify(73, n);
+                }
+            },
+
         new Test("Whens") {
             public void run()
             {