OSDN Git Service

Add DND whitelist
authorJulia Reynolds <juliacr@google.com>
Tue, 16 Apr 2019 16:50:04 +0000 (12:50 -0400)
committerJulia Reynolds <juliacr@google.com>
Tue, 16 Apr 2019 17:47:11 +0000 (13:47 -0400)
That is, a whitelist of packages that can make sound on the ringer
stream in the background when DND is in priority only mode

Test: atest
Fixes: 130359054

Change-Id: I0e3a18bd6c3b1c096e7ce94b2c692eb7aa66ae76

core/res/res/values/config.xml
core/res/res/values/symbols.xml
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/notification/ZenModeHelper.java
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java

index 5268189..4d6fda9 100644 (file)
         <item>com.android.messaging</item>
     </string-array>
 
+    <!-- An array of packages that can make sound on the ringer stream in priority-only DND
+     mode -->
+    <string-array translatable="false" name="config_priorityOnlyDndExemptPackages">
+        <item>com.android.dialer</item>
+    </string-array>
+
     <!-- An array of packages which can listen for notifications on low ram devices. -->
     <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" />
 
index 94b5da6..924b036 100644 (file)
   <java-symbol type="array" name="config_convert_to_emergency_number_map" />
 
   <java-symbol type="array" name="config_nonBlockableNotificationPackages" />
+  <java-symbol type="array" name="config_priorityOnlyDndExemptPackages" />
 
   <java-symbol type="array" name="config_allowedManagedServicesOnLowRamDevices" />
 
index 7f1b25c..042ac8c 100644 (file)
@@ -1689,6 +1689,9 @@ public class NotificationManagerService extends SystemService {
 
         mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
                 com.android.internal.R.array.config_nonBlockableNotificationPackages));
+
+        mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
+                com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
     }
 
     @Override
index 7e74cc2..1f5b99c 100644 (file)
@@ -80,6 +80,7 @@ import org.xmlpull.v1.XmlSerializer;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -96,7 +97,7 @@ public class ZenModeHelper {
     private final Context mContext;
     private final H mHandler;
     private final SettingsObserver mSettingsObserver;
-    @VisibleForTesting protected final AppOpsManager mAppOps;
+    private final AppOpsManager mAppOps;
     @VisibleForTesting protected final NotificationManager mNotificationManager;
     @VisibleForTesting protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
@@ -123,11 +124,13 @@ public class ZenModeHelper {
 
     @VisibleForTesting protected boolean mIsBootComplete;
 
+    private String[] mPriorityOnlyDndExemptPackages;
+
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
         mContext = context;
         mHandler = new H(looper);
         addCallback(mMetrics);
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps = context.getSystemService(AppOpsManager.class);
         mNotificationManager =  context.getSystemService(NotificationManager.class);
 
         mDefaultConfig = readDefaultConfig(mContext.getResources());
@@ -214,6 +217,10 @@ public class ZenModeHelper {
         loadConfigForUser(user, "onUserUnlocked");
     }
 
+    void setPriorityOnlyDndExemptPackages(String[] packages) {
+        mPriorityOnlyDndExemptPackages = packages;
+    }
+
     private void loadConfigForUser(int user, String reason) {
         if (mUser == user || user < UserHandle.USER_SYSTEM) return;
         mUser = user;
@@ -994,53 +1001,47 @@ public class ZenModeHelper {
         for (int usage : AudioAttributes.SDK_USAGES) {
             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
             if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
-                applyRestrictions(false /*mute*/, usage);
+                applyRestrictions(zenPriorityOnly, false /*mute*/, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
-                applyRestrictions(muteNotifications || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
-                applyRestrictions(muteCalls || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
-                applyRestrictions(muteAlarms || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
-                applyRestrictions(muteMedia || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
                 if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
                     // normally DND will only restrict touch sounds, not haptic feedback/vibrations
-                    applyRestrictions(muteSystem || muteEverything, usage,
+                    applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage,
                             AppOpsManager.OP_PLAY_AUDIO);
-                    applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE);
+                    applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE);
                 } else {
-                    applyRestrictions(muteSystem || muteEverything, usage);
+                    applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage);
                 }
             } else {
-                applyRestrictions(muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteEverything, usage);
             }
         }
     }
 
 
     @VisibleForTesting
-    protected void applyRestrictions(boolean mute, int usage, int code) {
-        final String[] exceptionPackages = null; // none (for now)
-
-        // Only do this if we are executing within the system process...  otherwise
-        // we are running as test code, so don't have access to the protected call.
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                mAppOps.setRestriction(code, usage,
-                        mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
-                        exceptionPackages);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+    protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mAppOps.setRestriction(code, usage,
+                    mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+                    zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @VisibleForTesting
-    protected void applyRestrictions(boolean mute, int usage) {
-        applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE);
-        applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO);
+    protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) {
+        applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE);
+        applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO);
     }
 
 
index 355ff63..2d101dd 100644 (file)
@@ -349,6 +349,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
         when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
+        mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
 
         // write to a test file; the system file isn't readable from tests
         mFile = new File(mContext.getCacheDir(), "test.xml");
index 91d3e5e..7e3d4b4 100644 (file)
@@ -206,6 +206,7 @@ public class RoleObserverTest extends UiServiceTestCase {
 
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
+        mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
 
         mUsers = new ArrayList<>();
         mUsers.add(new UserInfo(0, "system", 0));
index 08d8333..8936450 100644 (file)
@@ -110,6 +110,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
     private ZenModeHelper mZenModeHelperSpy;
     private Context mContext;
     private ContentResolver mContentResolver;
+    @Mock AppOpsManager mAppOps;
 
     @Before
     public void setUp() {
@@ -127,6 +128,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
                     e.toString());
         }
 
+        when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
         when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
         mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
                 AppGlobals.getPackageManager());
@@ -219,10 +221,10 @@ public class ZenModeHelperTest extends UiServiceTestCase {
                 Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
-        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt());
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_MEDIA);
     }
 
@@ -233,9 +235,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
                 Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0);
 
         mZenModeHelperSpy.applyRestrictions();
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false,
                 AudioAttributes.USAGE_MEDIA);
     }
 
@@ -244,13 +246,13 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_ALARM);
 
         // Media is a catch-all that includes games
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_GAME);
     }
 
@@ -262,17 +264,17 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         mZenModeHelperSpy.applyRestrictions();
 
         // Total silence will silence alarms, media and system noises (but not vibrations)
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_GAME);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_UNKNOWN);
     }
 
@@ -283,19 +285,19 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         mZenModeHelperSpy.applyRestrictions();
 
         // Alarms only mode will not silence alarms
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
 
         // Alarms only mode will not silence media
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_GAME);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_UNKNOWN);
 
         // Alarms only will silence system noises (but not vibrations)
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO);
     }
 
@@ -306,9 +308,9 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         mZenModeHelperSpy.applyRestrictions();
 
         // Alarms only mode will silence calls despite priority-mode config
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST);
     }
 
@@ -319,7 +321,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
     }
 
@@ -334,19 +336,64 @@ public class ZenModeHelperTest extends UiServiceTestCase {
         for (int usage : AudioAttributes.SDK_USAGES) {
             if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
                 // only mute audio, not vibrations
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, usage,
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, usage,
                         AppOpsManager.OP_PLAY_AUDIO);
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, usage,
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, usage,
                         AppOpsManager.OP_VIBRATE);
             } else {
                 boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage)
                         != AudioAttributes.SUPPRESSIBLE_NEVER;
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, shouldMute, usage);
             }
         }
     }
 
     @Test
+    public void testApplyRestrictions_whitelist_priorityOnlyMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(new String[]{PKG_O}));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(new String[]{PKG_O}));
+        }
+    }
+
+    @Test
+    public void testApplyRestrictions_whitelist_alarmsOnlyMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_ALARMS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null));
+        }
+    }
+
+    @Test
+    public void testApplyRestrictions_whitelist_totalSilenceMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null));
+        }
+    }
+
+    @Test
     public void testZenUpgradeNotification() {
         // shows zen upgrade notification if stored settings says to shows,
         // zen has not been updated, boot is completed