1 /* 2 * Copyright (C) 2025 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app; 18 19 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; 20 import static android.app.NotificationSystemUtil.runAsSystemUi; 21 import static android.app.NotificationSystemUtil.toggleNotificationPolicyAccess; 22 import static android.service.notification.Condition.STATE_FALSE; 23 import static android.service.notification.Condition.STATE_TRUE; 24 25 import static com.google.common.truth.Truth.assertThat; 26 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.net.Uri; 30 import android.platform.test.annotations.RequiresFlagsEnabled; 31 import android.platform.test.flag.junit.CheckFlagsRule; 32 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 33 import android.service.notification.Condition; 34 35 import androidx.test.core.app.ApplicationProvider; 36 import androidx.test.ext.junit.runners.AndroidJUnit4; 37 38 import org.junit.After; 39 import org.junit.Before; 40 import org.junit.Rule; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 44 import java.util.Map; 45 46 @RunWith(AndroidJUnit4.class) 47 public class NotificationManagerZenTest { 48 49 private Context mContext; 50 private NotificationManager mNotificationManager; 51 52 @Rule 53 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 54 55 @Before setUp()56 public void setUp() throws Exception { 57 mContext = ApplicationProvider.getApplicationContext(); 58 mNotificationManager = mContext.getSystemService(NotificationManager.class); 59 60 toggleNotificationPolicyAccess(mContext, mContext.getPackageName(), true); 61 runAsSystemUi(() -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL)); 62 removeAutomaticZenRules(); 63 } 64 65 @After tearDown()66 public void tearDown() { 67 runAsSystemUi(() -> mNotificationManager.setInterruptionFilter(INTERRUPTION_FILTER_ALL)); 68 removeAutomaticZenRules(); 69 } 70 removeAutomaticZenRules()71 private void removeAutomaticZenRules() { 72 // Delete AZRs created by this test (query "as app", then delete "as system" so they are 73 // not preserved to be restored later). 74 Map<String, AutomaticZenRule> rules = mNotificationManager.getAutomaticZenRules(); 75 runAsSystemUi(() -> { 76 for (String ruleId : rules.keySet()) { 77 mNotificationManager.removeAutomaticZenRule(ruleId); 78 } 79 }); 80 } 81 82 @Test 83 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_manualActivation()84 public void setAutomaticZenRuleState_manualActivation() { 85 AutomaticZenRule ruleToCreate = createZenRule("rule"); 86 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 87 Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on", 88 STATE_TRUE, Condition.SOURCE_USER_ACTION); 89 Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 90 STATE_FALSE, Condition.SOURCE_USER_ACTION); 91 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 92 STATE_TRUE); 93 Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off", 94 STATE_FALSE); 95 96 // User manually activates -> it's active. 97 runAsSystemUi( 98 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate)); 99 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 100 101 // User manually deactivates -> it's inactive. 102 runAsSystemUi( 103 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate)); 104 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 105 106 // And app can activate and deactivate. 107 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 108 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 109 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 110 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 111 } 112 113 @Test 114 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_manualDeactivation()115 public void setAutomaticZenRuleState_manualDeactivation() { 116 AutomaticZenRule ruleToCreate = createZenRule("rule"); 117 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 118 Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on", 119 STATE_TRUE, Condition.SOURCE_USER_ACTION); 120 Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 121 STATE_FALSE, Condition.SOURCE_USER_ACTION); 122 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 123 STATE_TRUE); 124 Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off", 125 STATE_FALSE); 126 127 // App activates rule. 128 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 129 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 130 131 // User manually deactivates -> it's inactive. 132 runAsSystemUi( 133 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate)); 134 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 135 136 // User manually reactivates -> it's active. 137 runAsSystemUi( 138 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate)); 139 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 140 141 // That manual activation removed the override-deactivate, but didn't put an 142 // override-activate, so app can deactivate when its natural schedule ends. 143 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 144 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 145 } 146 147 @Test 148 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_respectsManuallyActivated()149 public void setAutomaticZenRuleState_respectsManuallyActivated() { 150 AutomaticZenRule ruleToCreate = createZenRule("rule"); 151 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 152 Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-on", 153 STATE_TRUE, Condition.SOURCE_USER_ACTION); 154 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 155 STATE_TRUE); 156 Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off", 157 STATE_FALSE); 158 159 // App thinks rule should be inactive. 160 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 161 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 162 163 // Manually activate -> it's active. 164 runAsSystemUi(() -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate)); 165 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 166 167 // App says it should be inactive, but it's ignored. 168 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 169 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 170 171 // App says it should be active. No change now... 172 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 173 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 174 175 // ... but when the app wants to deactivate next time, it works. 176 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 177 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 178 } 179 180 @Test 181 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_respectsManuallyDeactivated()182 public void setAutomaticZenRuleState_respectsManuallyDeactivated() { 183 AutomaticZenRule ruleToCreate = createZenRule("rule"); 184 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 185 Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 186 STATE_FALSE, Condition.SOURCE_USER_ACTION); 187 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 188 STATE_TRUE); 189 Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off", 190 STATE_FALSE); 191 192 // App activates rule. 193 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 194 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 195 196 // User manually deactivates -> it's inactive. 197 runAsSystemUi( 198 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate)); 199 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 200 201 // App says it should be active, but it's ignored. 202 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 203 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 204 205 // App says it should be inactive. No change now... 206 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 207 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 208 209 // ... but when the app wants to activate next time, it works. 210 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 211 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 212 } 213 214 @Test 215 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_manualActivationFromApp()216 public void setAutomaticZenRuleState_manualActivationFromApp() { 217 AutomaticZenRule ruleToCreate = createZenRule("rule"); 218 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 219 Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 220 STATE_TRUE, Condition.SOURCE_USER_ACTION); 221 Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 222 STATE_FALSE, Condition.SOURCE_USER_ACTION); 223 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 224 STATE_TRUE); 225 Condition autoDeactivate = new Condition(ruleToCreate.getConditionId(), "auto-off", 226 STATE_FALSE); 227 228 // App activates rule. 229 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 230 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 231 232 // User manually deactivates from SysUI -> it's inactive. 233 runAsSystemUi( 234 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate)); 235 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 236 237 // User manually activates from App -> it's active. 238 mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate); 239 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 240 241 // And app can automatically deactivate it later. 242 mNotificationManager.setAutomaticZenRuleState(ruleId, autoDeactivate); 243 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 244 } 245 246 @Test 247 @RequiresFlagsEnabled(Flags.FLAG_MODES_UI) setAutomaticZenRuleState_manualDeactivationFromApp()248 public void setAutomaticZenRuleState_manualDeactivationFromApp() { 249 AutomaticZenRule ruleToCreate = createZenRule("rule"); 250 String ruleId = mNotificationManager.addAutomaticZenRule(ruleToCreate); 251 Condition manualActivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 252 STATE_TRUE, Condition.SOURCE_USER_ACTION); 253 Condition manualDeactivate = new Condition(ruleToCreate.getConditionId(), "manual-off", 254 STATE_FALSE, Condition.SOURCE_USER_ACTION); 255 Condition autoActivate = new Condition(ruleToCreate.getConditionId(), "auto-on", 256 STATE_TRUE); 257 258 // User manually activates from SysUI -> it's active. 259 runAsSystemUi( 260 () -> mNotificationManager.setAutomaticZenRuleState(ruleId, manualActivate)); 261 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 262 263 // User manually deactivates from App -> it's inactive. 264 mNotificationManager.setAutomaticZenRuleState(ruleId, manualDeactivate); 265 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_FALSE); 266 267 // And app can automatically activate it later. 268 mNotificationManager.setAutomaticZenRuleState(ruleId, autoActivate); 269 assertThat(mNotificationManager.getAutomaticZenRuleState(ruleId)).isEqualTo(STATE_TRUE); 270 } 271 createZenRule(String name)272 private AutomaticZenRule createZenRule(String name) { 273 return createZenRule(name, NotificationManager.INTERRUPTION_FILTER_PRIORITY); 274 } 275 createZenRule(String name, int filter)276 private AutomaticZenRule createZenRule(String name, int filter) { 277 return new AutomaticZenRule(name, null, 278 new ComponentName(mContext, ExampleActivity.class), 279 new Uri.Builder().scheme("scheme") 280 .appendPath("path") 281 .appendQueryParameter("fake_rule", "fake_value") 282 .build(), null, filter, true); 283 } 284 } 285