/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.notification; import static android.provider.Settings.Global.ZEN_MODE; import static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS; import static android.provider.Settings.Global.ZEN_MODE_OFF; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertFalse; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.NotificationManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.net.Uri; import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ZenRule; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.util.ArrayMap; import com.android.settings.notification.AbstractZenModePreferenceController.ZenModeConfigWrapper; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) public class ZenModeSettingsFooterPreferenceControllerTest { private static final String TEST_APP_NAME = "test_app"; private static final String TEST_RULE_NAME = "test_rule_name"; private static final String MANUAL_RULE_FIELD = "manualRule"; private static final String AUTOMATIC_RULES_FIELD = "automaticRules"; private ZenModeSettingsFooterPreferenceController mController; private final ArrayMap mInjectedAutomaticRules = new ArrayMap<>(); @Mock private NotificationManager mNotificationManager; @Mock private Preference mockPref; @Mock private ZenModeConfig mZenModeConfig; @Mock private PreferenceScreen mPreferenceScreen; @Mock private ZenModeConfigWrapper mConfigWrapper; private Context mContext; private ContentResolver mContentResolver; @Before public void setup() { MockitoAnnotations.initMocks(this); ShadowApplication shadowApplication = ShadowApplication.getInstance(); shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); mContext = shadowApplication.getApplicationContext(); mContentResolver = RuntimeEnvironment.application.getContentResolver(); when(mNotificationManager.getZenModeConfig()).thenReturn(mZenModeConfig); mController = new ZenModeSettingsFooterPreferenceController(mContext, mock(Lifecycle.class)); ReflectionHelpers.setField(mZenModeConfig, AUTOMATIC_RULES_FIELD, mInjectedAutomaticRules); ReflectionHelpers.setField(mController, "mZenModeConfigWrapper", mConfigWrapper); when(mPreferenceScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); mController.displayPreference(mPreferenceScreen); } @Test public void totalSilence_footerIsAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS); assertTrue(mController.isAvailable()); } @Test public void alarmsOnly_footerIsAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS); assertTrue(mController.isAvailable()); } @Test public void priorityOnly_footerIsAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); assertTrue(mController.isAvailable()); } @Test public void zenModeOff_footerIsNotAvailable() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF); assertFalse(mController.isAvailable()); } @Test public void app_manualRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); injectManualRuleFromApp(); mController.updateState(mockPref); verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule_app, TEST_APP_NAME)); } @Test public void time_manualRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); String placeholder = "placeholder"; injectManualRuleWithTimeCountdown(1000, placeholder); mController.updateState(mockPref); verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_manual_end_time, placeholder)); } @Test public void forever_manualRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); injectManualRuleWithIndefiniteEnd(); mController.updateState(mockPref); verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_manual_indefinite)); } @Test public void automaticRule_noManualRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); // no manual rule ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, null); // adding automatic rule injectNewAutomaticRule(TEST_RULE_NAME, true, false); mController.updateState(mockPref); verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, TEST_RULE_NAME)); } @Test public void manualRuleEndsLast_hasAutomaticRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); // manual rule that ends after automatic rule ends injectManualRuleWithIndefiniteEnd(); // automatic rule that ends before manual rule ends injectNewAutomaticRule(TEST_RULE_NAME, true, false); mController.updateState(mockPref); // manual rule end time is after automatic rule end time, so it is displayed verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_manual_indefinite)); } @Test public void automaticRuleEndsLast_hasManualRule_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); // manual rule that ends before automatic rule ends injectManualRuleWithTimeCountdown(1000, ""); // automatic rule that ends after manual rule ends ZenRule rule = injectNewAutomaticRule(TEST_RULE_NAME, true, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule.conditionId)).thenReturn(2000L); mController.updateState(mockPref); // automatic rule end time is after manual rule end time, so it is displayed verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, TEST_RULE_NAME)); } @Test public void multipleAutomaticRules_appAutoRuleautomaticRuleApp_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); // automatic rule that ends after manual rule ends ZenRule rule1 = injectNewAutomaticRule(TEST_RULE_NAME + "1", false, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule1.conditionId)).thenReturn(10000L); ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true, true); ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", true, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(9000L); mController.updateState(mockPref); // automatic rule from app is displayed verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, TEST_RULE_NAME + "2")); } @Test public void multipleAutomaticRules_setFooterTitle() { Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS); // automatic rule that ends after manual rule ends ZenRule rule1 = injectNewAutomaticRule(TEST_RULE_NAME + "1", true, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule1.conditionId)).thenReturn(2000L); ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule2.conditionId)).thenReturn(8000L); ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", false, false); when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(12000L); mController.updateState(mockPref); // active automatic rule with the latest end time will display verify(mockPref).setTitle(mContext.getString( com.android.settings.R.string.zen_mode_settings_dnd_automatic_rule, TEST_RULE_NAME + "2")); } // manual rule that has no end condition (forever) private void injectManualRuleWithIndefiniteEnd() { ZenRule injectedManualRule = new ZenRule(); injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; injectedManualRule.conditionId = null; injectedManualRule.enabler = null; ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); } // manual rule triggered by an app private void injectManualRuleFromApp() { ZenRule injectedManualRule = new ZenRule(); injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; injectedManualRule.enabler = TEST_APP_NAME; when(mConfigWrapper.getOwnerCaption(injectedManualRule.enabler)).thenReturn(TEST_APP_NAME); ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); } // manual rule that ends in specified time private void injectManualRuleWithTimeCountdown(long time, String timePlaceholder) { ZenRule injectedManualRule = new ZenRule(); injectedManualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; injectedManualRule.enabler = null; injectedManualRule.conditionId = mock(Uri.class); when(mConfigWrapper.parseManualRuleTime(injectedManualRule.conditionId)).thenReturn(time); when(mConfigWrapper.getFormattedTime(time, mContext.getUserId())) .thenReturn(timePlaceholder); ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule); } // manual rule that ends in time private ZenRule injectNewAutomaticRule(String nameAndId, boolean isActive, boolean isApp) { ZenRule injectedRule = spy(new ZenRule()); injectedRule.zenMode = ZEN_MODE_NO_INTERRUPTIONS; injectedRule.component = mock(ComponentName.class); injectedRule.name = nameAndId; injectedRule.conditionId = new Uri.Builder().authority(nameAndId).build(); // unique uri when(injectedRule.isAutomaticActive()).thenReturn(isActive); when(mConfigWrapper.isTimeRule(injectedRule.conditionId)).thenReturn(!isApp); if (isApp) { when(injectedRule.component.getPackageName()).thenReturn(TEST_APP_NAME); } mInjectedAutomaticRules.put(nameAndId, injectedRule); return injectedRule; } }