diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 526818949b3d5..4d6fda980755c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3483,6 +3483,12 @@ com.android.messaging + + + com.android.dialer + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 94b5da6baa071..924b036813a66 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3188,6 +3188,7 @@ + diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7f1b25ca3ca33..042ac8c5760e7 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -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 diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 7e74cc2368cdc..1f5b99cb3349d 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -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 mCallbacks = new ArrayList(); @@ -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); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 355ff63d18f7e..2d101dd87a0ff 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -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"); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index 91d3e5e4d7f62..7e3d4b47bbdff 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -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)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 08d83333e91b8..89364500fd80d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -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,18 +336,63 @@ 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,