diff --git a/res/values/strings.xml b/res/values/strings.xml index 56b0a41d370..08fa254d1a3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7994,6 +7994,7 @@ } + Display options for filtered notifications @@ -9155,6 +9156,17 @@ Events + + Apps + + Apps that can interrupt + + Selected apps + + None + + All + Allow apps to override diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml index a380987d377..0cea0fea112 100644 --- a/res/xml/modes_rule_settings.xml +++ b/res/xml/modes_rule_settings.xml @@ -29,6 +29,10 @@ android:key="zen_mode_people" android:title="@string/zen_category_people"/> + + diff --git a/res/xml/zen_mode_apps_settings.xml b/res/xml/zen_mode_apps_settings.xml new file mode 100644 index 00000000000..4ee14e41c5e --- /dev/null +++ b/res/xml/zen_mode_apps_settings.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/notification/modes/ZenModeAppsFragment.java b/src/com/android/settings/notification/modes/ZenModeAppsFragment.java new file mode 100644 index 00000000000..73329a242fd --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeAppsFragment.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 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.modes; + +import android.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.ArrayList; +import java.util.List; + +/** + * Mode > Apps + */ +public class ZenModeAppsFragment extends ZenModeFragmentBase { + + @Override + protected List createPreferenceControllers(Context context) { + List controllers = new ArrayList<>(); + controllers.add(new ZenModeAppsPreferenceController( + context, ZenModeAppsPreferenceController.KEY_PRIORITY, mBackend)); + controllers.add(new ZenModeAppsPreferenceController( + context, ZenModeAppsPreferenceController.KEY_NONE, mBackend)); + // TODO: b/308819928 - The manual DND mode cannot have the ALL type; + // unify the controllers into one and only create a preference if isManualDnd is false. + controllers.add(new ZenModeAppsPreferenceController( + context, ZenModeAppsPreferenceController.KEY_ALL, mBackend)); + return controllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.zen_mode_apps_settings; + } + + @Override + public int getMetricsCategory() { + // TODO: b/332937635 - make this the correct metrics category + return SettingsEnums.NOTIFICATION_ZEN_MODE_PRIORITY; + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java new file mode 100644 index 00000000000..42b58b1346e --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 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.modes; + +import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID; + +import android.content.Context; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; + +import com.android.settings.core.SubSettingLauncher; + +/** + * Preference with a link and summary about what apps can break through the mode + */ +public class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceController { + + private final ZenModeSummaryHelper mSummaryHelper; + + public ZenModeAppsLinkPreferenceController(Context context, String key, + ZenModesBackend backend) { + super(context, key, backend); + mSummaryHelper = new ZenModeSummaryHelper(mContext, mBackend); + } + + @Override + public void updateState(Preference preference, @NonNull ZenMode zenMode) { + Bundle bundle = new Bundle(); + bundle.putString(MODE_ID, zenMode.getId()); + // TODO(b/332937635): Update metrics category + preference.setIntent(new SubSettingLauncher(mContext) + .setDestination(ZenModeAppsFragment.class.getName()) + .setSourceMetricsCategory(0) + .setArguments(bundle) + .toIntent()); + preference.setSummary(mSummaryHelper.getAppsSummary(zenMode)); + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java new file mode 100644 index 00000000000..2b5a479b840 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 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.modes; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.service.notification.ZenPolicy; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + +import com.android.settings.core.SubSettingLauncher; +import com.android.settings.notification.zen.ZenModeBypassingAppsSettings; +import com.android.settingslib.widget.SelectorWithWidgetPreference; + +public class ZenModeAppsPreferenceController extends + AbstractZenModePreferenceController implements Preference.OnPreferenceChangeListener { + + static final String KEY_PRIORITY = "zen_mode_apps_priority"; + static final String KEY_NONE = "zen_mode_apps_none"; + static final String KEY_ALL = "zen_mode_apps_all"; + + + public ZenModeAppsPreferenceController(@NonNull Context context, + @NonNull String key, @Nullable ZenModesBackend backend) { + super(context, key, backend); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + SelectorWithWidgetPreference pref = screen.findPreference(getPreferenceKey()); + if (pref != null) { + pref.setOnClickListener(mSelectorClickListener); + + // Adds the widget to only the priority category. + if (getPreferenceKey().equals(KEY_PRIORITY)) { + pref.setExtraWidgetOnClickListener(p -> { + launchPrioritySettings(); + }); + } + } + super.displayPreference(screen); + } + + @Override + public void updateState(Preference preference, @NonNull ZenMode zenMode) { + TwoStatePreference pref = (TwoStatePreference) preference; + switch (getPreferenceKey()) { + case KEY_PRIORITY: + boolean policy_priority = zenMode.getPolicy().getAllowedChannels() + == ZenPolicy.CHANNEL_POLICY_PRIORITY; + pref.setChecked(policy_priority); + break; + case KEY_NONE: + boolean policy_none = zenMode.getPolicy().getAllowedChannels() + == ZenPolicy.CHANNEL_POLICY_NONE; + pref.setChecked(policy_none); + break; + case KEY_ALL: + // A UI-only setting; the underlying policy never actually has this value, + // but ZenMode acts as though it does for the sake of UI consistency. + boolean policy_all = zenMode.getPolicy().getAllowedChannels() + == ZenMode.CHANNEL_POLICY_ALL; + pref.setChecked(policy_all); + break; + } + } + + @Override + public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) { + switch (getPreferenceKey()) { + case KEY_PRIORITY: + return savePolicy(p -> p.allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)); + case KEY_NONE: + return savePolicy(p -> p.allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)); + case KEY_ALL: + return savePolicy(p -> p.allowChannels(ZenMode.CHANNEL_POLICY_ALL)); + } + return true; + } + + @VisibleForTesting + SelectorWithWidgetPreference.OnClickListener mSelectorClickListener = + new SelectorWithWidgetPreference.OnClickListener() { + @Override + public void onRadioButtonClicked(SelectorWithWidgetPreference preference) { + onPreferenceChange(preference, true); + } + }; + + private void launchPrioritySettings() { + // TODO(b/332937635): Update metrics category + new SubSettingLauncher(mContext) + .setDestination(ZenModeBypassingAppsSettings.class.getName()) + .setSourceMetricsCategory(SettingsEnums.SETTINGS_ZEN_NOTIFICATIONS) + .launch(); + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java index 7f805eeb669..bf09e3e6e11 100644 --- a/src/com/android/settings/notification/modes/ZenModeFragment.java +++ b/src/com/android/settings/notification/modes/ZenModeFragment.java @@ -39,6 +39,8 @@ public class ZenModeFragment extends ZenModeFragmentBase { prefControllers.add(new ZenModeHeaderController(context, "header", this, mBackend)); prefControllers.add(new ZenModePeopleLinkPreferenceController( context, "zen_mode_people", mBackend)); + prefControllers.add(new ZenModeAppsLinkPreferenceController( + context, "zen_mode_apps", mBackend)); prefControllers.add(new ZenModeOtherLinkPreferenceController( context, "zen_other_settings", mBackend)); prefControllers.add(new ZenModeDisplayLinkPreferenceController( diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java index 41a3d20d0a3..b4075cde656 100644 --- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java +++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java @@ -395,4 +395,19 @@ class ZenModeSummaryHelper { return mContext.getResources().getString(R.string.zen_mode_people_some); } } + + /** + * Generates a summary to display under the top level "Apps" preference for a mode. + */ + public String getAppsSummary(ZenMode zenMode) { + // TODO: b/308819928 - Set summary using priority app list if Selected Apps Chosen. + if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_PRIORITY) { + return mContext.getResources().getString(R.string.zen_mode_apps_priority_apps); + } else if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) { + return mContext.getResources().getString(R.string.zen_mode_apps_none_apps); + } else if (zenMode.getPolicy().getAllowedChannels() == ZenMode.CHANNEL_POLICY_ALL) { + return mContext.getResources().getString(R.string.zen_mode_apps_all_apps); + } + return ""; + } } diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java new file mode 100644 index 00000000000..67e1f9f919a --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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.modes; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.AutomaticZenRule; +import android.app.Flags; +import android.content.Context; +import android.net.Uri; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.service.notification.ZenPolicy; + +import androidx.preference.Preference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +@EnableFlags(Flags.FLAG_MODES_UI) +public final class ZenModeAppsLinkPreferenceControllerTest { + + private ZenModeAppsLinkPreferenceController mController; + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new ZenModeAppsLinkPreferenceController( + mContext, "controller_key", mBackend); + } + + @Test + @EnableFlags(Flags.FLAG_MODES_UI) + public void testHasSummary() { + Preference pref = mock(Preference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build()) + .build(), true); + mController.updateZenMode(pref, zenMode); + verify(pref).setSummary(any()); + } + +} diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java new file mode 100644 index 00000000000..750453dabe6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2024 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.modes; + +import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; +import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE; +import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; + +import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_ALL; +import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_NONE; +import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_PRIORITY; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.app.AutomaticZenRule; +import android.app.Flags; +import android.content.Context; +import android.net.Uri; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.service.notification.ZenPolicy; + +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + +import com.android.settingslib.widget.SelectorWithWidgetPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +@EnableFlags(Flags.FLAG_MODES_UI) +public final class ZenModeAppsPreferenceControllerTest { + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + private ZenModeAppsPreferenceController mPriorityController; + private ZenModeAppsPreferenceController mAllController; + private ZenModeAppsPreferenceController mNoneController; + + private SelectorWithWidgetPreference mPriorityPref; + private SelectorWithWidgetPreference mAllPref; + private SelectorWithWidgetPreference mNonePref; + private PreferenceCategory mPrefCategory; + private PreferenceScreen mPreferenceScreen; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + mPriorityController = new ZenModeAppsPreferenceController(mContext, KEY_PRIORITY, mBackend); + mNoneController = new ZenModeAppsPreferenceController(mContext, KEY_NONE, mBackend); + mAllController = new ZenModeAppsPreferenceController(mContext, KEY_ALL, mBackend); + + mPriorityPref = makePreference(KEY_PRIORITY, mPriorityController); + mAllPref = makePreference(KEY_ALL, mAllController); + mNonePref = makePreference(KEY_NONE, mNoneController); + + mPrefCategory = new PreferenceCategory(mContext); + mPrefCategory.setKey("zen_mode_apps_category"); + + PreferenceManager preferenceManager = new PreferenceManager(mContext); + mPreferenceScreen = preferenceManager.createPreferenceScreen(mContext); + + mPreferenceScreen.addPreference(mPrefCategory); + mPrefCategory.addPreference(mPriorityPref); + mPrefCategory.addPreference(mAllPref); + mPrefCategory.addPreference(mNonePref); + + mAllController.displayPreference(mPreferenceScreen); + mPriorityController.displayPreference(mPreferenceScreen); + mNoneController.displayPreference(mPreferenceScreen); + } + + private SelectorWithWidgetPreference makePreference(String key, + ZenModeAppsPreferenceController controller) { + final SelectorWithWidgetPreference pref = new SelectorWithWidgetPreference(mContext, false); + pref.setKey(key); + pref.setOnClickListener(controller.mSelectorClickListener); + return pref; + } + + @Test + public void testUpdateState_All() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenMode.CHANNEL_POLICY_ALL) + .build()) + .build(), true); + mAllController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testUpdateState_All_Unchecked() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(), true); + mAllController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(false); + } + + @Test + public void testUpdateState_None() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(), true); + mNoneController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testUpdateState_None_Unchecked() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenMode.CHANNEL_POLICY_ALL) + .build()) + .build(), true); + mNoneController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(false); + } + + @Test + public void testUpdateState_Priority() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY) + .build()) + .build(), true); + mPriorityController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testUpdateState_Priority_Unchecked() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(), true); + mPriorityController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(false); + } + + @Test + public void testOnPreferenceChange_All() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_NONE) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenMode.CHANNEL_POLICY_ALL) + .build()) + .build(), true); + + mAllController.updateZenMode(preference, zenMode); + mAllController.onPreferenceChange(preference, true); + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + + assertThat(captor.getValue().getPolicy().getAllowedChannels()) + .isEqualTo(ZenMode.CHANNEL_POLICY_ALL); + } + + @Test + public void testPreferenceClick_passesCorrectCheckedState_All() { + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(), true); + + + mAllController.updateZenMode(mAllPref, zenMode); + mNoneController.updateZenMode(mNonePref, zenMode); + mPriorityController.updateZenMode(mPriorityPref, zenMode); + + // MPME is checked; ALL and PRIORITY are unchecked. + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + + mPrefCategory.findPreference(KEY_ALL).performClick(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + // Checks the policy value for ALL is set. + // The important part is that the interruption filter is propagated to the backend. + assertThat(captor.getValue().getRule().getInterruptionFilter()) + .isEqualTo(INTERRUPTION_FILTER_ALL); + // ALL is now checked; others are unchecked. + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + } + + @Test + public void testPreferenceClick_passesCorrectCheckedState_None() { + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY) + .build()) + .build(), true); + + mAllController.updateZenMode(mAllPref, zenMode); + mNoneController.updateZenMode(mNonePref, zenMode); + mPriorityController.updateZenMode(mPriorityPref, zenMode); + + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + + // Click on NONE + mPrefCategory.findPreference(KEY_NONE).performClick(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + // NONE is not actually propagated to the backend as an interruption filter; + // the filter is set to priority, and sounds and visual effects are disallowed. + // See AbstractZenModePreferenceController. + assertThat(captor.getValue().getRule().getInterruptionFilter()) + .isEqualTo(INTERRUPTION_FILTER_PRIORITY); + // NONE is now checked; others are unchecked. + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + } + + @Test + public void testPreferenceClick_passesCorrectCheckedState_Priority() { + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(), true); + + mAllController.updateZenMode(mAllPref, zenMode); + mNoneController.updateZenMode(mNonePref, zenMode); + mPriorityController.updateZenMode(mPriorityPref, zenMode); + + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + + // Click on PRIORITY + mPrefCategory.findPreference(KEY_PRIORITY).performClick(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + // Checks the policy value for PRIORITY is propagated to the backend. + assertThat(captor.getValue().getRule().getInterruptionFilter()) + .isEqualTo(INTERRUPTION_FILTER_PRIORITY); + // PRIORITY is now checked; others are unchecked. + assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL)) + .isChecked()); + assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE)) + .isChecked()); + } + +} diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java index 3e41778cdc0..d8c8bf0bfb5 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java @@ -22,6 +22,7 @@ import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS; import static android.service.notification.ZenPolicy.VISUAL_EFFECT_AMBIENT; import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS; + import static com.google.common.truth.Truth.assertThat; import android.app.AutomaticZenRule; @@ -29,6 +30,7 @@ import android.content.Context; import android.net.Uri; import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenPolicy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -325,4 +327,46 @@ public class ZenModesSummaryHelperTest { assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( "Notifications partially hidden, grayscale, and 2 more"); } + + @Test + public void getAppsSummary_all() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenMode.CHANNEL_POLICY_ALL) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getAppsSummary(zenMode)).isEqualTo("All"); + } + + @Test + public void getAppsSummary_none() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getAppsSummary(zenMode)).isEqualTo("None"); + } + + @Test + public void getAppsSummary_priorityApps() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getAppsSummary(zenMode)).isEqualTo("Selected apps"); + } }