Add a setting for hiding silent status icons

Test: atest, cts
Bug: 123419917
Change-Id: Iedfc1fb07e0e2c6639cb0b711cf81553cff29262
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 238eed4..7cffdb1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2361,6 +2361,28 @@
         }
 
         @Override
+        public boolean shouldHideSilentStatusIcons(String callingPkg) {
+            checkCallerIsSameApp(callingPkg);
+
+            if (isCallerSystemOrPhone()
+                    || mListeners.isListenerPackage(callingPkg)) {
+                return mPreferencesHelper.shouldHideSilentStatusIcons();
+            } else {
+                throw new SecurityException("Only available for notification listeners");
+            }
+        }
+
+        @Override
+        public void setHideSilentStatusIcons(boolean hide) {
+            checkCallerIsSystem();
+
+            mPreferencesHelper.setHideSilentStatusIcons(hide);
+            handleSavePolicyFile();
+
+            mListeners.onStatusBarIconsBehaviorChanged(hide);
+        }
+
+        @Override
         public int getPackageImportance(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
             return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -7319,6 +7341,20 @@
             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
         }
 
+        public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
+            for (final ManagedServiceInfo info : getServices()) {
+                mHandler.post(() -> {
+                    final INotificationListener listener = (INotificationListener) info.service;
+                     try {
+                        listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "unable to notify listener "
+                                + "(hideSilentStatusIcons): " + listener, ex);
+                    }
+                });
+            }
+        }
+
         /**
          * asynchronously notify all listeners about a new notification
          *
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3f0043c..6ed4f5c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -76,6 +76,7 @@
     private static final String TAG_CHANNEL = "channel";
     private static final String TAG_GROUP = "channelGroup";
     private static final String TAG_DELEGATE = "delegate";
+    private static final String TAG_STATUS_ICONS = "status_icons";
 
     private static final String ATT_VERSION = "version";
     private static final String ATT_NAME = "name";
@@ -89,10 +90,13 @@
     private static final String ATT_APP_USER_LOCKED_FIELDS = "app_user_locked_fields";
     private static final String ATT_ENABLED = "enabled";
     private static final String ATT_USER_ALLOWED = "allowed";
+    private static final String ATT_HIDE_SILENT = "hide_silent";
 
     private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
     private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
+    @VisibleForTesting
+    static final boolean DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS = false;
     private static final boolean DEFAULT_SHOW_BADGE = true;
     private static final boolean DEFAULT_ALLOW_BUBBLE = true;
     private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE  = false;
@@ -124,6 +128,7 @@
 
     private SparseBooleanArray mBadgingEnabled;
     private boolean mAreChannelsBypassingDnd;
+    private boolean mHideSilentStatusBarIcons;
 
     public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
             ZenModeHelper zenHelper) {
@@ -143,9 +148,8 @@
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
         synchronized (mPackagePreferences) {
-            // Clobber groups and channels with the xml, but don't delete other data that wasn't present
-
-            // at the time of serialization.
+            // Clobber groups and channels with the xml, but don't delete other data that wasn't
+            // present at the time of serialization.
             mRestoredWithoutUids.clear();
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 tag = parser.getName();
@@ -153,7 +157,10 @@
                     return;
                 }
                 if (type == XmlPullParser.START_TAG) {
-                    if (TAG_PACKAGE.equals(tag)) {
+                    if (TAG_STATUS_ICONS.equals(tag)) {
+                        mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
+                                parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+                    } else if (TAG_PACKAGE.equals(tag)) {
                         int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
                         String name = parser.getAttributeValue(null, ATT_NAME);
                         if (!TextUtils.isEmpty(name)) {
@@ -375,6 +382,11 @@
     public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
         out.startTag(null, TAG_RANKING);
         out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
+        if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS) {
+            out.startTag(null, TAG_STATUS_ICONS);
+            out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
+            out.endTag(null, TAG_STATUS_ICONS);
+        }
 
         synchronized (mPackagePreferences) {
             final int N = mPackagePreferences.size();
@@ -781,6 +793,14 @@
         }
     }
 
+    public boolean shouldHideSilentStatusIcons() {
+        return mHideSilentStatusBarIcons;
+    }
+
+    public void setHideSilentStatusIcons(boolean hide) {
+        mHideSilentStatusBarIcons = hide;
+    }
+
     public void lockChannelsForOEM(String[] appOrChannelList) {
         if (appOrChannelList == null) {
             return;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bde9dde..47ec390 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2006,6 +2006,28 @@
     }
 
     @Test
+    public void testXml_statusBarIcons_default() throws Exception {
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+        loadStreamXml(baos, false);
+
+        assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
+                mHelper.shouldHideSilentStatusIcons());
+    }
+
+    @Test
+    public void testXml_statusBarIcons() throws Exception {
+        mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+        loadStreamXml(baos, false);
+
+        assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
+                mHelper.shouldHideSilentStatusIcons());
+    }
+
+    @Test
     public void testSetNotificationDelegate() {
         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));