Loading services/core/java/com/android/server/notification/NotificationManagerService.java +24 −7 Original line number Diff line number Diff line Loading @@ -5387,7 +5387,7 @@ public class NotificationManagerService extends SystemService { @Override public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg, boolean fromUser) { validateAutomaticZenRule(automaticZenRule); validateAutomaticZenRule(/* updateId= */ null, automaticZenRule); checkCallerIsSameApp(pkg); if (automaticZenRule.getZenPolicy() != null && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { Loading @@ -5413,7 +5413,7 @@ public class NotificationManagerService extends SystemService { @Override public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule, boolean fromUser) throws RemoteException { validateAutomaticZenRule(automaticZenRule); validateAutomaticZenRule(id, automaticZenRule); enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule"); Loading @@ -5421,14 +5421,31 @@ public class NotificationManagerService extends SystemService { computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid()); } private void validateAutomaticZenRule(AutomaticZenRule rule) { private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) { Objects.requireNonNull(rule, "automaticZenRule is null"); Objects.requireNonNull(rule.getName(), "Name is null"); rule.validate(); if (rule.getOwner() == null // Implicit rules have no ConditionProvider or Activity. We allow the user to customize // them (via Settings), but not the owner app. Should the app want to start using it as // a "normal" rule, it must provide a CP/ConfigActivity too. if (android.app.Flags.modesApi()) { boolean isImplicitRuleUpdateFromSystem = updateId != null && ZenModeHelper.isImplicitRuleId(updateId) && isCallerSystemOrSystemUi(); if (!isImplicitRuleUpdateFromSystem && rule.getOwner() == null && rule.getConfigurationActivity() == null) { throw new NullPointerException( "Rule must have a conditionproviderservice and/or configuration activity"); "Rule must have a ConditionProviderService and/or configuration " + "activity"); } } else { if (rule.getOwner() == null && rule.getConfigurationActivity() == null) { throw new NullPointerException( "Rule must have a ConditionProviderService and/or configuration " + "activity"); } } Objects.requireNonNull(rule.getConditionId(), "ConditionId is null"); Loading services/core/java/com/android/server/notification/ZenModeHelper.java +7 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,8 @@ public class ZenModeHelper { private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72; static final int RULE_LIMIT_PER_PACKAGE = 100; private static final String IMPLICIT_RULE_ID_PREFIX = "implicit_"; // + pkg_name /** * Send new activation AutomaticZenRule statuses to apps with a min target SDK version */ Loading Loading @@ -653,7 +655,11 @@ public class ZenModeHelper { } private static String implicitRuleId(String forPackage) { return "implicit_" + forPackage; return IMPLICIT_RULE_ID_PREFIX + forPackage; } static boolean isImplicitRuleId(@NonNull String ruleId) { return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX); } boolean removeAutomaticZenRule(String id, @ConfigChangeOrigin int origin, String reason, Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +72 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ import static com.android.server.notification.NotificationRecordLogger.Notificat import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; Loading Loading @@ -9370,6 +9371,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyInt()); } /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ private ZenModeHelper setUpMockZenTest() { ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); mService.setZenHelper(zenModeHelper); Loading Loading @@ -13974,6 +13976,76 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { setUpRealZenTest(); mService.setCallerIsNormalPackage(); assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); // Create an implicit zen rule by calling setNotificationPolicy from an app. mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(rule.getValue().getOwner()).isNull(); assertThat(rule.getValue().getConfigurationActivity()).isNull(); // Now try to update said rule (e.g. disable it). Should fail. // We also validate the exception message because NPE could be thrown by all sorts of test // issues (e.g. misconfigured mocks). rule.getValue().setEnabled(false); NullPointerException e = assertThrows(NullPointerException.class, () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false)); assertThat(e.getMessage()).isEqualTo( "Rule must have a ConditionProviderService and/or configuration activity"); } @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { setUpRealZenTest(); mService.setCallerIsNormalPackage(); assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); // Create an implicit zen rule by calling setNotificationPolicy from an app. mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(rule.getValue().getOwner()).isNull(); assertThat(rule.getValue().getConfigurationActivity()).isNull(); // Now update said rule from Settings (e.g. disable it). Should work! mService.isSystemUid = true; rule.getValue().setEnabled(false); mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false); Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(updatedRule.getValue().isEnabled()).isFalse(); } /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ private void setUpRealZenTest() throws Exception { when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) .thenReturn(true); int iconResId = 79; String iconResName = "icon_79"; String pkg = mContext.getPackageName(); ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); appInfoSpy.icon = iconResId; when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); } @Test public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR); Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +24 −7 Original line number Diff line number Diff line Loading @@ -5387,7 +5387,7 @@ public class NotificationManagerService extends SystemService { @Override public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg, boolean fromUser) { validateAutomaticZenRule(automaticZenRule); validateAutomaticZenRule(/* updateId= */ null, automaticZenRule); checkCallerIsSameApp(pkg); if (automaticZenRule.getZenPolicy() != null && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { Loading @@ -5413,7 +5413,7 @@ public class NotificationManagerService extends SystemService { @Override public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule, boolean fromUser) throws RemoteException { validateAutomaticZenRule(automaticZenRule); validateAutomaticZenRule(id, automaticZenRule); enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule"); enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule"); Loading @@ -5421,14 +5421,31 @@ public class NotificationManagerService extends SystemService { computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid()); } private void validateAutomaticZenRule(AutomaticZenRule rule) { private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) { Objects.requireNonNull(rule, "automaticZenRule is null"); Objects.requireNonNull(rule.getName(), "Name is null"); rule.validate(); if (rule.getOwner() == null // Implicit rules have no ConditionProvider or Activity. We allow the user to customize // them (via Settings), but not the owner app. Should the app want to start using it as // a "normal" rule, it must provide a CP/ConfigActivity too. if (android.app.Flags.modesApi()) { boolean isImplicitRuleUpdateFromSystem = updateId != null && ZenModeHelper.isImplicitRuleId(updateId) && isCallerSystemOrSystemUi(); if (!isImplicitRuleUpdateFromSystem && rule.getOwner() == null && rule.getConfigurationActivity() == null) { throw new NullPointerException( "Rule must have a conditionproviderservice and/or configuration activity"); "Rule must have a ConditionProviderService and/or configuration " + "activity"); } } else { if (rule.getOwner() == null && rule.getConfigurationActivity() == null) { throw new NullPointerException( "Rule must have a ConditionProviderService and/or configuration " + "activity"); } } Objects.requireNonNull(rule.getConditionId(), "ConditionId is null"); Loading
services/core/java/com/android/server/notification/ZenModeHelper.java +7 −1 Original line number Diff line number Diff line Loading @@ -134,6 +134,8 @@ public class ZenModeHelper { private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72; static final int RULE_LIMIT_PER_PACKAGE = 100; private static final String IMPLICIT_RULE_ID_PREFIX = "implicit_"; // + pkg_name /** * Send new activation AutomaticZenRule statuses to apps with a min target SDK version */ Loading Loading @@ -653,7 +655,11 @@ public class ZenModeHelper { } private static String implicitRuleId(String forPackage) { return "implicit_" + forPackage; return IMPLICIT_RULE_ID_PREFIX + forPackage; } static boolean isImplicitRuleId(@NonNull String ruleId) { return ruleId.startsWith(IMPLICIT_RULE_ID_PREFIX); } boolean removeAutomaticZenRule(String id, @ConfigChangeOrigin int origin, String reason, Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +72 −0 Original line number Diff line number Diff line Loading @@ -111,6 +111,7 @@ import static com.android.server.notification.NotificationRecordLogger.Notificat import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; Loading Loading @@ -9370,6 +9371,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyInt()); } /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ private ZenModeHelper setUpMockZenTest() { ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); mService.setZenHelper(zenModeHelper); Loading Loading @@ -13974,6 +13976,76 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } } @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { setUpRealZenTest(); mService.setCallerIsNormalPackage(); assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); // Create an implicit zen rule by calling setNotificationPolicy from an app. mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(rule.getValue().getOwner()).isNull(); assertThat(rule.getValue().getConfigurationActivity()).isNull(); // Now try to update said rule (e.g. disable it). Should fail. // We also validate the exception message because NPE could be thrown by all sorts of test // issues (e.g. misconfigured mocks). rule.getValue().setEnabled(false); NullPointerException e = assertThrows(NullPointerException.class, () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false)); assertThat(e.getMessage()).isEqualTo( "Rule must have a ConditionProviderService and/or configuration activity"); } @Test @EnableFlags(android.app.Flags.FLAG_MODES_API) @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { setUpRealZenTest(); mService.setCallerIsNormalPackage(); assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); // Create an implicit zen rule by calling setNotificationPolicy from an app. mBinderService.setNotificationPolicy(PKG, new NotificationManager.Policy(0, 0, 0), false); assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(rule.getValue().getOwner()).isNull(); assertThat(rule.getValue().getConfigurationActivity()).isNull(); // Now update said rule from Settings (e.g. disable it). Should work! mService.isSystemUid = true; rule.getValue().setEnabled(false); mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false); Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement( mBinderService.getAutomaticZenRules().entrySet()); assertThat(updatedRule.getValue().isEnabled()).isFalse(); } /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ private void setUpRealZenTest() throws Exception { when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) .thenReturn(true); int iconResId = 79; String iconResName = "icon_79"; String pkg = mContext.getPackageName(); ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); appInfoSpy.icon = iconResId; when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); } @Test public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR);