1 /* 2 * Copyright (C) 2017 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 com.android.settings.notification; 18 19 import static android.provider.Settings.Global.ZEN_MODE; 20 import static android.provider.Settings.Global.ZEN_MODE_ALARMS; 21 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 22 import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; 23 import static android.provider.Settings.Global.ZEN_MODE_OFF; 24 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.spy; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.app.NotificationManager; 33 import android.content.ComponentName; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.net.Uri; 37 import android.provider.Settings; 38 import android.service.notification.ZenModeConfig; 39 import android.service.notification.ZenModeConfig.ZenRule; 40 import android.util.ArrayMap; 41 42 import androidx.fragment.app.FragmentManager; 43 import androidx.preference.Preference; 44 import androidx.preference.PreferenceScreen; 45 46 import com.android.settings.notification.AbstractZenModePreferenceController.ZenModeConfigWrapper; 47 import com.android.settingslib.core.lifecycle.Lifecycle; 48 49 import org.junit.Before; 50 import org.junit.Test; 51 import org.junit.runner.RunWith; 52 import org.mockito.Mock; 53 import org.mockito.MockitoAnnotations; 54 import org.robolectric.RobolectricTestRunner; 55 import org.robolectric.RuntimeEnvironment; 56 import org.robolectric.shadows.ShadowApplication; 57 import org.robolectric.util.ReflectionHelpers; 58 59 @RunWith(RobolectricTestRunner.class) 60 public class ZenModeSettingsFooterPreferenceControllerTest { 61 62 private static final String TEST_APP_NAME = "test_app"; 63 private static final String TEST_RULE_NAME = "test_rule_name"; 64 private static final String MANUAL_RULE_FIELD = "manualRule"; 65 private static final String AUTOMATIC_RULES_FIELD = "automaticRules"; 66 67 private ZenModeSettingsFooterPreferenceController mController; 68 69 private final ArrayMap<String, ZenRule> mInjectedAutomaticRules = new ArrayMap<>(); 70 71 @Mock 72 private NotificationManager mNotificationManager; 73 @Mock 74 private Preference mockPref; 75 @Mock 76 private ZenModeConfig mZenModeConfig; 77 @Mock 78 private PreferenceScreen mPreferenceScreen; 79 @Mock 80 private ZenModeConfigWrapper mConfigWrapper; 81 82 private Context mContext; 83 private ContentResolver mContentResolver; 84 85 @Before setup()86 public void setup() { 87 MockitoAnnotations.initMocks(this); 88 ShadowApplication shadowApplication = ShadowApplication.getInstance(); 89 shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); 90 91 mContext = RuntimeEnvironment.application; 92 mContentResolver = RuntimeEnvironment.application.getContentResolver(); 93 when(mNotificationManager.getZenModeConfig()).thenReturn(mZenModeConfig); 94 95 mController = new ZenModeSettingsFooterPreferenceController(mContext, mock(Lifecycle.class), 96 mock(FragmentManager.class)); 97 ReflectionHelpers.setField(mZenModeConfig, AUTOMATIC_RULES_FIELD, mInjectedAutomaticRules); 98 ReflectionHelpers.setField(mController, "mZenModeConfigWrapper", mConfigWrapper); 99 100 when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); 101 mController.displayPreference(mPreferenceScreen); 102 } 103 104 @Test totalSilence_footerIsAvailable()105 public void totalSilence_footerIsAvailable() { 106 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS); 107 assertTrue(mController.isAvailable()); 108 } 109 110 @Test alarmsOnly_footerIsAvailable()111 public void alarmsOnly_footerIsAvailable() { 112 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS); 113 assertTrue(mController.isAvailable()); 114 } 115 116 @Test priorityOnly_footerIsAvailable()117 public void priorityOnly_footerIsAvailable() { 118 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 119 assertTrue(mController.isAvailable()); 120 } 121 122 @Test zenModeOff_footerIsNotAvailable()123 public void zenModeOff_footerIsNotAvailable() { 124 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF); 125 assertFalse(mController.isAvailable()); 126 } 127 128 @Test testDefaultNotifPolicy_app_manualRule_setFooterTitle()129 public void testDefaultNotifPolicy_app_manualRule_setFooterTitle() { 130 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 131 injectManualRuleFromApp(); 132 mController.updateState(mockPref); 133 134 verify(mockPref).setTitle(mContext.getString( 135 com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule_app, 136 TEST_APP_NAME)); 137 } 138 139 @Test testDefaultNotifPolicy_time_manualRule_setFooterTitle()140 public void testDefaultNotifPolicy_time_manualRule_setFooterTitle() { 141 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 142 String placeholder = "placeholder"; 143 injectManualRuleWithTimeCountdown(1000, placeholder); 144 mController.updateState(mockPref); 145 146 verify(mockPref).setTitle(mContext.getString( 147 com.android.settings.R.string.zen_mode_settings_dnd_manual_end_time, placeholder)); 148 } 149 150 @Test testDefaultNotifPolicy_forever_manualRule_setFooterTitle()151 public void testDefaultNotifPolicy_forever_manualRule_setFooterTitle() { 152 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 153 injectManualRuleWithIndefiniteEnd(); 154 mController.updateState(mockPref); 155 156 verify(mockPref).setTitle(mContext.getString( 157 com.android.settings.R.string.zen_mode_settings_dnd_manual_indefinite)); 158 } 159 160 @Test testDefaultNotifPolicy_automaticRule_noManualRule_setFooterTitle()161 public void testDefaultNotifPolicy_automaticRule_noManualRule_setFooterTitle() { 162 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 163 // no manual rule 164 ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, null); 165 166 // adding automatic rule 167 injectNewAutomaticRule(TEST_RULE_NAME, true, false); 168 169 mController.updateState(mockPref); 170 171 verify(mockPref).setTitle(mContext.getString( 172 com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, 173 TEST_RULE_NAME)); 174 } 175 176 @Test testDefaultNotifPolicy_manualRuleEndsLast_hasAutomaticRule_setFooterTitle()177 public void testDefaultNotifPolicy_manualRuleEndsLast_hasAutomaticRule_setFooterTitle() { 178 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 179 // manual rule that ends after automatic rule ends 180 injectManualRuleWithIndefiniteEnd(); 181 182 // automatic rule that ends before manual rule ends 183 injectNewAutomaticRule(TEST_RULE_NAME, true, false); 184 185 mController.updateState(mockPref); 186 187 // manual rule end time is after automatic rule end time, so it is displayed 188 verify(mockPref).setTitle(mContext.getString( 189 com.android.settings.R.string.zen_mode_settings_dnd_manual_indefinite)); 190 } 191 192 @Test testDefaultNotifPolicy_automaticRuleEndsLast_hasManualRule_setFooterTitle()193 public void testDefaultNotifPolicy_automaticRuleEndsLast_hasManualRule_setFooterTitle() { 194 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 195 // manual rule that ends before automatic rule ends 196 injectManualRuleWithTimeCountdown(1000, ""); 197 198 // automatic rule that ends after manual rule ends 199 ZenRule rule = injectNewAutomaticRule(TEST_RULE_NAME, true, false); 200 when(mConfigWrapper.parseAutomaticRuleEndTime(rule.conditionId)).thenReturn(2000L); 201 202 mController.updateState(mockPref); 203 204 // automatic rule end time is after manual rule end time, so it is displayed 205 verify(mockPref).setTitle(mContext.getString( 206 com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, 207 TEST_RULE_NAME)); 208 } 209 210 @Test testDefaultNotifPolicy_multipleAutomaticRules_autoRuleApp_setFooterTitle()211 public void testDefaultNotifPolicy_multipleAutomaticRules_autoRuleApp_setFooterTitle() { 212 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 213 214 // automatic rule that ends after manual rule ends 215 ZenRule rule1 = injectNewAutomaticRule(TEST_RULE_NAME + "1", false, false); 216 when(mConfigWrapper.parseAutomaticRuleEndTime(rule1.conditionId)).thenReturn(10000L); 217 218 // automatic rule that is an app 219 injectNewAutomaticRule(TEST_RULE_NAME + "2", true, true); 220 221 ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", true, false); 222 when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(9000L); 223 224 mController.updateState(mockPref); 225 226 // automatic rule from app is displayed 227 verify(mockPref).setTitle(mContext.getString( 228 com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, 229 TEST_RULE_NAME + "2")); 230 } 231 232 @Test testDefaultNotifPolicy_multipleAutomaticRules_setFooterTitle()233 public void testDefaultNotifPolicy_multipleAutomaticRules_setFooterTitle() { 234 Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); 235 236 // automatic rule that ends after manual rule ends 237 ZenRule rule1 = injectNewAutomaticRule(TEST_RULE_NAME + "1", true, false); 238 when(mConfigWrapper.parseAutomaticRuleEndTime(rule1.conditionId)).thenReturn(2000L); 239 240 ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true, false); 241 when(mConfigWrapper.parseAutomaticRuleEndTime(rule2.conditionId)).thenReturn(8000L); 242 243 ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", false, false); 244 when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(12000L); 245 246 mController.updateState(mockPref); 247 248 // active automatic rule with the latest end time will display 249 verify(mockPref).setTitle(mContext.getString( 250 com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, 251 TEST_RULE_NAME + "2")); 252 } 253 254 // manual rule that has no end condition (forever) injectManualRuleWithIndefiniteEnd()255 private void injectManualRuleWithIndefiniteEnd() { 256 ZenRule injectedManualRule = new ZenRule(); 257 injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; 258 injectedManualRule.conditionId = null; 259 injectedManualRule.enabler = null; 260 ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); 261 } 262 263 // manual rule triggered by an app injectManualRuleFromApp()264 private void injectManualRuleFromApp() { 265 ZenRule injectedManualRule = new ZenRule(); 266 injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; 267 injectedManualRule.enabler = TEST_APP_NAME; 268 when(mConfigWrapper.getOwnerCaption(injectedManualRule.enabler)).thenReturn(TEST_APP_NAME); 269 ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); 270 } 271 272 // manual rule that ends in specified time injectManualRuleWithTimeCountdown(long time, String timePlaceholder)273 private void injectManualRuleWithTimeCountdown(long time, String timePlaceholder) { 274 ZenRule injectedManualRule = new ZenRule(); 275 injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; 276 injectedManualRule.enabler = null; 277 injectedManualRule.conditionId = mock(Uri.class); 278 when(mConfigWrapper.parseManualRuleTime(injectedManualRule.conditionId)).thenReturn(time); 279 when(mConfigWrapper.getFormattedTime(time, mContext.getUserId())) 280 .thenReturn(timePlaceholder); 281 ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); 282 } 283 284 // manual rule that ends in time injectNewAutomaticRule(String nameAndId, boolean isActive, boolean isApp)285 private ZenRule injectNewAutomaticRule(String nameAndId, boolean isActive, boolean isApp) { 286 ZenRule injectedRule = spy(new ZenRule()); 287 injectedRule.zenMode = ZEN_MODE_NO_INTERRUPTIONS; 288 injectedRule.component = mock(ComponentName.class); 289 injectedRule.name = nameAndId; 290 injectedRule.conditionId = new Uri.Builder().authority(nameAndId).build(); // unique uri 291 when(injectedRule.isAutomaticActive()).thenReturn(isActive); 292 when(mConfigWrapper.isTimeRule(injectedRule.conditionId)).thenReturn(!isApp); 293 if (isApp) { 294 when(injectedRule.component.getPackageName()).thenReturn(TEST_APP_NAME); 295 } 296 mInjectedAutomaticRules.put(nameAndId, injectedRule); 297 298 return injectedRule; 299 } 300 } 301