Added footers to zen mode settings

ZenModeSettings Footer displays when DND will end
ZenModeBehaviorSettings Footer describes why dnd behavior cannot be changed when
in alarms only or total silence mode

Test: make RunSettingsRoboTests -j40
Bug: 63077372
Change-Id: Iefbb3995da4af2b210c8e0c3c3a798d3c613e275
This commit is contained in:
Beverly
2017-11-17 16:29:30 -05:00
parent 22c7164d56
commit b7b74226c3
11 changed files with 882 additions and 9 deletions

View File

@@ -0,0 +1,247 @@
/*
* 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.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ComponentName;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.support.v14.preference.SwitchPreference;
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.TestConfig;
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.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class ZenModeBehaviorFooterPreferenceControllerTest {
private ZenModeBehaviorFooterPreferenceController mController;
private final String TEST_APP_NAME = "test_app";
private final String MANUAL_RULE_FIELD = "manualRule";
private final String AUTOMATIC_RULES_FIELD = "automaticRules";
@Mock
private NotificationManager mNotificationManager;
@Mock
private Preference mockPref;
@Mock
private ZenModeConfig mZenModeConfig;
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private ZenModeConfig mConfig;
@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 ZenModeBehaviorFooterPreferenceController(mContext,
mock(Lifecycle.class));
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);
assertFalse(mController.isAvailable());
}
@Test
public void zenModeOff_footerIsNotAvailable() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF);
assertFalse(mController.isAvailable());
}
@Test
public void zenModeOff_updateState_noFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_OFF);
mController.updateState(mockPref);
verify(mockPref, never()).setTitle(any(String.class));
}
@Test
public void zenModeImportantInterruptions_updateState_noFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_IMPORTANT_INTERRUPTIONS);
mController.updateState(mockPref);
verify(mockPref, never()).setTitle(any(String.class));
}
@Test
public void deprecatedZenModeAlarms_qsManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS);
ZenRule injectedManualRule = new ZenRule();
injectedManualRule.zenMode = ZEN_MODE_ALARMS;
ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_qs_set_behavior));
}
@Test
public void deprecatedZenModeAlarms_appManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS);
ZenRule injectedManualRule = new ZenRule();
injectedManualRule.zenMode = ZEN_MODE_ALARMS;
injectedManualRule.enabler = TEST_APP_NAME;
when(mConfigWrapper.getOwnerCaption(injectedManualRule.enabler)).thenReturn(TEST_APP_NAME);
ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_app_set_behavior, TEST_APP_NAME));
}
@Test
public void deprecatedZenModeNoInterruptions_qsManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS);
ZenRule injectedManualRule = new ZenRule();
injectedManualRule.zenMode = ZEN_MODE_NO_INTERRUPTIONS;
ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_qs_set_behavior));
}
@Test
public void deprecatedZenModeNoInterruptions_appManualRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS);
ZenRule injectedManualRule = new ZenRule();
injectedManualRule.zenMode = ZEN_MODE_NO_INTERRUPTIONS;
injectedManualRule.enabler = TEST_APP_NAME;
when(mConfigWrapper.getOwnerCaption(injectedManualRule.enabler)).thenReturn(TEST_APP_NAME);
ReflectionHelpers.setField(mZenModeConfig, MANUAL_RULE_FIELD, injectedManualRule);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_app_set_behavior, TEST_APP_NAME));
}
@Test
public void deprecatedZenModeAlarms_automaticRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_ALARMS);
ArrayMap<String, ZenRule> injectedAutomaticRules = new ArrayMap<>();
ZenRule injectedRule = spy(new ZenRule());
injectedRule.zenMode = ZEN_MODE_ALARMS;
injectedRule.component = mock(ComponentName.class);
when(injectedRule.isAutomaticActive()).thenReturn(true);
when(injectedRule.component.getPackageName()).thenReturn(TEST_APP_NAME);
injectedAutomaticRules.put("testid", injectedRule);
ReflectionHelpers.setField(mZenModeConfig, AUTOMATIC_RULES_FIELD, injectedAutomaticRules);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_app_set_behavior, TEST_APP_NAME));
}
@Test
public void deprecatedZenModeNoInterruptions_automaticRule_setFooterTitle() {
Settings.Global.putInt(mContentResolver, ZEN_MODE, ZEN_MODE_NO_INTERRUPTIONS);
ArrayMap<String, ZenRule> injectedAutomaticRules = new ArrayMap<>();
ZenRule injectedRule = spy(new ZenRule());
injectedRule.zenMode = ZEN_MODE_NO_INTERRUPTIONS;
injectedRule.component = mock(ComponentName.class);
when(injectedRule.isAutomaticActive()).thenReturn(true);
when(injectedRule.component.getPackageName()).thenReturn(TEST_APP_NAME);
injectedAutomaticRules.put("testid", injectedRule);
ReflectionHelpers.setField(mZenModeConfig, AUTOMATIC_RULES_FIELD, injectedAutomaticRules);
mController.updateState(mockPref);
verify(mockPref).setTitle(mContext.getString(
com.android.settings.R.string.zen_mode_app_set_behavior, TEST_APP_NAME));
}
}

View File

@@ -0,0 +1,317 @@
/*
* 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.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ComponentName;
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.TestConfig;
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.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class ZenModeSettingsFooterPreferenceControllerTest {
private ZenModeSettingsFooterPreferenceController mController;
private final String TEST_APP_NAME = "test_app";
private final String TEST_RULE_NAME = "test_rule_name";
private final String MANUAL_RULE_FIELD = "manualRule";
private final String AUTOMATIC_RULES_FIELD = "automaticRules";
private final ArrayMap<String, ZenRule> 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(
(long) 2000);
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(
(long) 10000);
ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true,
true);
ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", true,
false);
when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(
(long) 9000);
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(
(long) 2000);
ZenRule rule2 = injectNewAutomaticRule(TEST_RULE_NAME + "2", true,
false);
when(mConfigWrapper.parseAutomaticRuleEndTime(rule2.conditionId)).thenReturn(
(long) 8000);
ZenRule rule3 = injectNewAutomaticRule(TEST_RULE_NAME + "3", false,
false);
when(mConfigWrapper.parseAutomaticRuleEndTime(rule3.conditionId)).thenReturn(
(long) 12000);
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;
}
}