diff --git a/AndroidManifest.xml b/AndroidManifest.xml index af565d6a02f..38401e8f1ca 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -738,23 +738,6 @@ android:value="true" /> - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/preference_widget_zen_master_icon.xml b/res/layout/preference_widget_zen_master_icon.xml new file mode 100644 index 00000000000..64c0db8d614 --- /dev/null +++ b/res/layout/preference_widget_zen_master_icon.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index b3b068aabf3..7bdb06972eb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7223,8 +7223,39 @@ Allow visual signals + + Restrict notifications + + Notifications + + When Do Not Disturb is turned on + + Mute notifications + + Show notifications but mute sounds & vibrations + + When new notifications arrive your phone won\u2019t make a sound or vibration + + Hide & mute notifications + + Notifications will not appear at all + + You won\u2019t see new or existing notifications when Do Not Disturb is on. However, notifications needed for basic phone activity and status will still appear. + + Custom + + Enable custom setting + + Remove custom setting + + Will appear + + Partially hidden + + Hidden + - Block visual disturbances + Custom restrictions When the screen is on diff --git a/res/xml/zen_mode_restrict_notifications_settings.xml b/res/xml/zen_mode_restrict_notifications_settings.xml new file mode 100644 index 00000000000..d5243f62943 --- /dev/null +++ b/res/xml/zen_mode_restrict_notifications_settings.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml index 717b6c505f6..0f9396840a4 100644 --- a/res/xml/zen_mode_settings.xml +++ b/res/xml/zen_mode_settings.xml @@ -31,8 +31,8 @@ + android:title="@string/zen_mode_restrict_notifications_title" + android:fragment="com.android.settings.notification.ZenModeRestrictNotificationsSettings" /> createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getLifecycle()); + } + + private static List buildPreferenceControllers(Context context, + Lifecycle lifecycle) { + List controllers = new ArrayList<>(); + controllers.add(new ZenModeVisEffectsNonePreferenceController( + context, lifecycle, "zen_mute_notifications")); + controllers.add(new ZenModeVisEffectsAllPreferenceController( + context, lifecycle, "zen_hide_notifications")); + controllers.add(new ZenModeVisEffectsCustomPreferenceController( + context, lifecycle, "zen_custom")); + controllers.add(new ZenFooterPreferenceController(context, lifecycle, + FooterPreference.KEY_FOOTER)); + return controllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.zen_mode_restrict_notifications_settings; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS; + } + + /** + * For Search. + */ + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.zen_mode_restrict_notifications_settings; + result.add(sir); + return result; + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + return keys; + } + + @Override + public List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, null); + } + }; +} diff --git a/src/com/android/settings/notification/ZenModeSettings.java b/src/com/android/settings/notification/ZenModeSettings.java index 1f0dcc28365..bdc24e3c530 100644 --- a/src/com/android/settings/notification/ZenModeSettings.java +++ b/src/com/android/settings/notification/ZenModeSettings.java @@ -158,24 +158,15 @@ public class ZenModeSettings extends ZenModeSettingsBase { } String getBlockedEffectsSummary(Policy policy) { - List blockedStrings = new ArrayList<>(); - if (Policy.areAnyScreenOffEffectsSuppressed(policy.suppressedVisualEffects)) { - blockedStrings.add(mContext.getResources().getString( - R.string.zen_mode_block_effect_summary_screen_off)); - } - if (Policy.areAnyScreenOnEffectsSuppressed(policy.suppressedVisualEffects)) { - blockedStrings.add(mContext.getResources().getString( - R.string.zen_mode_block_effect_summary_screen_on)); - } - - if (blockedStrings.size() == 0) { + if (policy.suppressedVisualEffects == 0) { return mContext.getResources().getString( - R.string.zen_mode_block_effect_summary_none); - } else if (blockedStrings.size() == 1) { - return blockedStrings.get(0); + R.string.zen_mode_restrict_notifications_summary_muted); + } else if (Policy.areAllVisualEffectsSuppressed(policy.suppressedVisualEffects)) { + return mContext.getResources().getString( + R.string.zen_mode_restrict_notifications_summary_hidden); } else { - return mContext.getResources().getString(R.string.join_two_unrelated_items, - blockedStrings.get(0), blockedStrings.get(1)); + return mContext.getResources().getString( + R.string.zen_mode_restrict_notifications_summary_custom); } } diff --git a/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceController.java new file mode 100644 index 00000000000..70618aac88d --- /dev/null +++ b/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceController.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 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 android.app.NotificationManager.Policy; +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settingslib.core.lifecycle.Lifecycle; + +public class ZenModeVisEffectsAllPreferenceController + extends AbstractZenModePreferenceController + implements ZenCustomRadioButtonPreference.OnRadioButtonClickListener { + + protected static final int EFFECTS = Policy.SUPPRESSED_EFFECT_SCREEN_OFF + | Policy.SUPPRESSED_EFFECT_SCREEN_ON + | Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | Policy.SUPPRESSED_EFFECT_LIGHTS + | Policy.SUPPRESSED_EFFECT_PEEK + | Policy.SUPPRESSED_EFFECT_STATUS_BAR + | Policy.SUPPRESSED_EFFECT_BADGE + | Policy.SUPPRESSED_EFFECT_AMBIENT + | Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; + + public ZenModeVisEffectsAllPreferenceController(Context context, Lifecycle lifecycle, + String key) { + super(context, key, lifecycle); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + boolean everythingBlocked = Policy.areAllVisualEffectsSuppressed( + mBackend.mPolicy.suppressedVisualEffects); + ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference; + pref.setOnRadioButtonClickListener(this); + pref.setChecked(everythingBlocked); + } + + protected void deselect(PreferenceScreen screen) { + ZenCustomRadioButtonPreference preference = + (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey()); + if (preference != null) { + preference.setChecked(false); + } + } + + @Override + public void onRadioButtonClick(ZenCustomRadioButtonPreference p) { + mMetricsFeatureProvider.action(mContext, + MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_AND_VIS_EFFECTS, true); + mBackend.saveVisualEffectsPolicy(EFFECTS, true); + } +} diff --git a/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java new file mode 100644 index 00000000000..fd235e61fcb --- /dev/null +++ b/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceController.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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 android.app.NotificationManager.Policy; +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.core.SubSettingLauncher; +import com.android.settingslib.core.lifecycle.Lifecycle; + +public class ZenModeVisEffectsCustomPreferenceController + extends AbstractZenModePreferenceController { + + protected boolean mShowMenuSelected; + protected static final int INTERRUPTIVE_EFFECTS = Policy.SUPPRESSED_EFFECT_AMBIENT + | Policy.SUPPRESSED_EFFECT_PEEK + | Policy.SUPPRESSED_EFFECT_LIGHTS + | Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; + + public ZenModeVisEffectsCustomPreferenceController(Context context, Lifecycle lifecycle, + String key) { + super(context, key, lifecycle); + } + + @Override + public boolean isAvailable() { + if (mShowMenuSelected) { + return true; + } + + return areCustomOptionsSelected(); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference; + pref.setChecked(areCustomOptionsSelected()); + + pref.setOnGearClickListener(p -> { + new SubSettingLauncher(mContext) + .setDestination(ZenModeBlockedEffectsSettings.class.getName()) + .setTitle(R.string.zen_mode_what_to_block_title) + .setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_ZEN_NOTIFICATIONS) + .launch(); + }); + + pref.setOnRadioButtonClickListener(p -> { + select(); + }); + } + + protected void setShownByMenu(boolean shown) { + mShowMenuSelected = shown; + } + + protected boolean areCustomOptionsSelected() { + boolean allEffectsSuppressed = + Policy.areAllVisualEffectsSuppressed(mBackend.mPolicy.suppressedVisualEffects); + boolean noEffectsSuppressed = mBackend.mPolicy.suppressedVisualEffects == 0; + + return !(allEffectsSuppressed || noEffectsSuppressed); + } + + protected void select() { + mMetricsFeatureProvider.action(mContext, + MetricsProto.MetricsEvent.ACTION_ZEN_CUSTOM, true); + mBackend.savePolicy(mBackend.mPolicy.priorityCategories, + mBackend.mPolicy.priorityCallSenders, + mBackend.mPolicy.priorityMessageSenders, + INTERRUPTIVE_EFFECTS); + } +} \ No newline at end of file diff --git a/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceController.java b/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceController.java new file mode 100644 index 00000000000..8958d081a05 --- /dev/null +++ b/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceController.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 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 android.app.NotificationManager.Policy; +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settingslib.core.lifecycle.Lifecycle; + +public class ZenModeVisEffectsNonePreferenceController + extends AbstractZenModePreferenceController + implements ZenCustomRadioButtonPreference.OnRadioButtonClickListener { + + protected static final int EFFECTS = Policy.SUPPRESSED_EFFECT_SCREEN_OFF + | Policy.SUPPRESSED_EFFECT_SCREEN_ON + | Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | Policy.SUPPRESSED_EFFECT_LIGHTS + | Policy.SUPPRESSED_EFFECT_PEEK + | Policy.SUPPRESSED_EFFECT_STATUS_BAR + | Policy.SUPPRESSED_EFFECT_BADGE + | Policy.SUPPRESSED_EFFECT_AMBIENT + | Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; + + public ZenModeVisEffectsNonePreferenceController(Context context, Lifecycle lifecycle, + String key) { + super(context, key, lifecycle); + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + + boolean nothingBlocked = mBackend.mPolicy.suppressedVisualEffects == 0; + ZenCustomRadioButtonPreference pref = (ZenCustomRadioButtonPreference) preference; + pref.setOnRadioButtonClickListener(this); + pref.setChecked(nothingBlocked); + } + + @Override + public void onRadioButtonClick(ZenCustomRadioButtonPreference preference) { + mMetricsFeatureProvider.action(mContext, + MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_ONLY, true); + mBackend.saveVisualEffectsPolicy(EFFECTS, false); + } + + protected void deselect(PreferenceScreen screen) { + ZenCustomRadioButtonPreference preference = + (ZenCustomRadioButtonPreference) screen.findPreference(getPreferenceKey()); + if (preference != null) { + preference.setChecked(false); + } + } +} diff --git a/src/com/android/settings/search/SearchIndexableResourcesImpl.java b/src/com/android/settings/search/SearchIndexableResourcesImpl.java index 3b58c64ed36..d5e4eb9983c 100644 --- a/src/com/android/settings/search/SearchIndexableResourcesImpl.java +++ b/src/com/android/settings/search/SearchIndexableResourcesImpl.java @@ -77,6 +77,7 @@ import com.android.settings.notification.SoundSettings; import com.android.settings.notification.ZenModeAutomationSettings; import com.android.settings.notification.ZenModeBehaviorSettings; import com.android.settings.notification.ZenModeBlockedEffectsSettings; +import com.android.settings.notification.ZenModeRestrictNotificationsSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintSettingsFragment; import com.android.settings.security.EncryptionAndCredential; @@ -180,6 +181,7 @@ public class SearchIndexableResourcesImpl implements SearchIndexableResources { addIndex(ZenModeBehaviorSettings.class); addIndex(ZenModeBlockedEffectsSettings.class); addIndex(ZenModeAutomationSettings.class); + addIndex(ZenModeRestrictNotificationsSettings.class); addIndex(NightDisplaySettings.class); addIndex(SmartBatterySettings.class); addIndex(MyDeviceInfoFragment.class); diff --git a/tests/robotests/src/com/android/settings/notification/ZenCustomRadioButtonPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/ZenCustomRadioButtonPreferenceTest.java new file mode 100644 index 00000000000..0993f33d3c2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenCustomRadioButtonPreferenceTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2018 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 com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.support.v7.preference.Preference.OnPreferenceChangeListener; +import android.support.v7.preference.PreferenceViewHolder; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.Switch; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.MasterSwitchPreference; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenCustomRadioButtonPreferenceTest { + + private Context mContext; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + } + + @Test + public void createNewPreference_shouldSetLayout() { + final ZenCustomRadioButtonPreference preference + = new ZenCustomRadioButtonPreference(mContext); + + assertThat(preference.getLayoutResource()).isEqualTo(R.layout.preference_two_target_radio); + assertThat(preference.getWidgetLayoutResource()) + .isEqualTo(R.layout.preference_widget_gear); + } + + @Test + public void setChecked_shouldUpdateButtonCheckedState() { + final ZenCustomRadioButtonPreference preference = + new ZenCustomRadioButtonPreference(mContext); + final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate( + R.layout.preference_two_target_radio, null)); + final RadioButton toggle = (RadioButton) holder.findViewById(android.R.id.checkbox); + preference.onBindViewHolder(holder); + + preference.setChecked(true); + assertThat(toggle.isChecked()).isTrue(); + + preference.setChecked(false); + assertThat(toggle.isChecked()).isFalse(); + } + + @Test + public void clickRadioButton_shouldNotifyRadioButtonClicked() { + final ZenCustomRadioButtonPreference preference + = new ZenCustomRadioButtonPreference(mContext); + final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate(R.layout.preference_two_target_radio, null)); + final View toggle = holder.findViewById(R.id.checkbox_frame); + + ZenCustomRadioButtonPreference.OnRadioButtonClickListener l = mock( + ZenCustomRadioButtonPreference.OnRadioButtonClickListener.class); + preference.setOnRadioButtonClickListener(l); + preference.onBindViewHolder(holder); + + toggle.performClick(); + verify(l).onRadioButtonClick(preference); + } + + @Test + public void clickWidgetView_shouldNotifyWidgetClicked() { + final ZenCustomRadioButtonPreference preference = + new ZenCustomRadioButtonPreference(mContext); + final PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests( + LayoutInflater.from(mContext).inflate(R.layout.preference_two_target_radio, null)); + final View widgetView = holder.findViewById(android.R.id.widget_frame); + + ZenCustomRadioButtonPreference.OnGearClickListener l = mock( + ZenCustomRadioButtonPreference.OnGearClickListener.class); + preference.setOnGearClickListener(l); + preference.onBindViewHolder(holder); + + widgetView.performClick(); + verify(l).onGearClick(preference); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..13f4fb1e5b0 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenFooterPreferenceControllerTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2018 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.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.widget.FooterPreference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenFooterPreferenceControllerTest { + private ZenFooterPreferenceController mController; + + @Mock + private ZenModeBackend mBackend; + @Mock + private FooterPreference mockPref; + private Context mContext; + @Mock + private PreferenceScreen mScreen; + @Mock NotificationManager mNotificationManager; + + private static final String PREF_KEY = "main_pref"; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + mContext = shadowApplication.getApplicationContext(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + when(mNotificationManager.getNotificationPolicy()).thenReturn( + mock(NotificationManager.Policy.class)); + mController = new ZenFooterPreferenceController( + mContext, mock(Lifecycle.class), PREF_KEY); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); + } + + @Test + public void isAvailable_noVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_someVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2); + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_allVisEffects() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed); + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void updateSummary_noVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + mController.updateState(mockPref); + verify(mockPref).setTitle(R.string.zen_mode_restrict_notifications_mute_footer); + } + + @Test + public void getSummary_someVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2); + mController.updateState(mockPref); + verify(mockPref).setTitle(null); + } + + @Test + public void getSummary_allVisEffects() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed); + mController.updateState(mockPref); + verify(mockPref).setTitle(R.string.zen_mode_restrict_notifications_hide_footer); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java index d706d126c07..b26989d3475 100644 --- a/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java +++ b/tests/robotests/src/com/android/settings/notification/ZenModeSettingsTest.java @@ -74,29 +74,23 @@ public class ZenModeSettingsTest { @Test public void testBlockedEffectsSummary_none() { NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0, 0); - assertEquals("Never", mBuilder.getBlockedEffectsSummary(policy)); + assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_muted), + mBuilder.getBlockedEffectsSummary(policy)); } @Test - public void testBlockedEffectsSummary_screen_on() { + public void testBlockedEffectsSummary_some() { NotificationManager.Policy policy = new NotificationManager.Policy( 0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK); - assertEquals("When screen is on", mBuilder.getBlockedEffectsSummary(policy)); + assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_custom), + mBuilder.getBlockedEffectsSummary(policy)); } @Test - public void testBlockedEffectsSummary_screen_off() { + public void testBlockedEffectsSummary_all() { NotificationManager.Policy policy = new NotificationManager.Policy( - 0, 0, 0, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT); - assertEquals("When screen is off", mBuilder.getBlockedEffectsSummary(policy)); - } - - @Test - public void testBlockedEffectsSummary_both() { - NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0, - NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST - | NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS); - assertEquals("When screen is off, When screen is on", + 0, 0, 0, 511); + assertEquals(mContext.getString(R.string.zen_mode_restrict_notifications_summary_hidden), mBuilder.getBlockedEffectsSummary(policy)); } diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceControllerTest.java new file mode 100644 index 00000000000..30583883464 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsAllPreferenceControllerTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 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.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .ACTION_ZEN_SOUND_AND_VIS_EFFECTS; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.DisabledCheckBoxPreference; +import com.android.settings.widget.RadioButtonPreference; +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.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenModeVisEffectsAllPreferenceControllerTest { + private ZenModeVisEffectsAllPreferenceController mController; + + @Mock + private ZenModeBackend mBackend; + @Mock + private ZenCustomRadioButtonPreference mockPref; + private Context mContext; + private FakeFeatureFactory mFeatureFactory; + @Mock + private PreferenceScreen mScreen; + @Mock NotificationManager mNotificationManager; + + private static final String PREF_KEY = "main_pref"; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + mContext = shadowApplication.getApplicationContext(); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + when(mNotificationManager.getNotificationPolicy()).thenReturn( + mock(NotificationManager.Policy.class)); + mController = new ZenModeVisEffectsAllPreferenceController( + mContext, mock(Lifecycle.class), PREF_KEY); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); + mController.displayPreference(mScreen); + } + + @Test + public void isAvailable() { + assertTrue(mController.isAvailable()); + } + + @Test + public void updateState_notChecked() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.updateState(mockPref); + + verify(mockPref).setChecked(false); + } + + @Test + public void updateState_checked() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed); + mController.updateState(mockPref); + + verify(mockPref).setChecked(true); + } + + @Test + public void onPreferenceChanged_checkedTrue() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.onRadioButtonClick(mockPref); + verify(mBackend).saveVisualEffectsPolicy(allSuppressed, true); + verify(mFeatureFactory.metricsFeatureProvider).action(eq(mContext), + eq(ACTION_ZEN_SOUND_AND_VIS_EFFECTS), + eq(true)); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java new file mode 100644 index 00000000000..56fa1c2dd1a --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsCustomPreferenceControllerTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2018 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.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_CUSTOM; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .ACTION_ZEN_SOUND_AND_VIS_EFFECTS; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.testutils.FakeFeatureFactory; +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.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenModeVisEffectsCustomPreferenceControllerTest { + private ZenModeVisEffectsCustomPreferenceController mController; + + @Mock + private ZenModeBackend mBackend; + @Mock + private ZenCustomRadioButtonPreference mockPref; + private Context mContext; + private FakeFeatureFactory mFeatureFactory; + @Mock + private PreferenceScreen mScreen; + @Mock NotificationManager mNotificationManager; + + private static final String PREF_KEY = "main_pref"; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + mContext = shadowApplication.getApplicationContext(); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + when(mNotificationManager.getNotificationPolicy()).thenReturn( + mock(NotificationManager.Policy.class)); + mController = new ZenModeVisEffectsCustomPreferenceController( + mContext, mock(Lifecycle.class), PREF_KEY); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); + } + + @Test + public void isAvailable_menuOff_noVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + mController.mShowMenuSelected = false; + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_menuOn_noVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + mController.mShowMenuSelected = true; + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_menuOn_visEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.mShowMenuSelected = false; + assertThat(mController.isAvailable()).isTrue(); + } + + + @Test + public void updateState_notChecked_noVisEffects() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + mController.updateState(mockPref); + + verify(mockPref).setChecked(false); + } + + @Test + public void updateState_notChecked_allVisEffects() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, allSuppressed); + mController.updateState(mockPref); + + verify(mockPref).setChecked(false); + } + + @Test + public void updateState_checked() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2); + mController.updateState(mockPref); + + verify(mockPref).setChecked(true); + } + + @Test + public void updateState_listeners() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 2); + mController.updateState(mockPref); + + verify(mockPref).setOnGearClickListener(any()); + verify(mockPref).setOnRadioButtonClickListener(any()); + } + + @Test + public void select() { + int interruptiveSuppressed = SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.select(); + verify(mBackend).savePolicy(anyInt(), anyInt(), anyInt(), eq(interruptiveSuppressed)); + verify(mFeatureFactory.metricsFeatureProvider).action(eq(mContext), + eq(ACTION_ZEN_CUSTOM), + eq(true)); + } +} diff --git a/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceControllerTest.java new file mode 100644 index 00000000000..0f99be83bbf --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/ZenModeVisEffectsNonePreferenceControllerTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 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.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ZEN_SOUND_ONLY; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.NotificationManager; +import android.content.Context; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.widget.DisabledCheckBoxPreference; +import com.android.settings.widget.RadioButtonPreference; +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.shadows.ShadowApplication; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ZenModeVisEffectsNonePreferenceControllerTest { + private ZenModeVisEffectsNonePreferenceController mController; + + @Mock + private ZenModeBackend mBackend; + @Mock + private ZenCustomRadioButtonPreference mockPref; + private Context mContext; + private FakeFeatureFactory mFeatureFactory; + @Mock + private PreferenceScreen mScreen; + @Mock NotificationManager mNotificationManager; + + private static final String PREF_KEY = "main_pref"; + private static final int PREF_METRICS = 1; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + ShadowApplication shadowApplication = ShadowApplication.getInstance(); + mContext = shadowApplication.getApplicationContext(); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNotificationManager); + when(mNotificationManager.getNotificationPolicy()).thenReturn( + mock(NotificationManager.Policy.class)); + mController = new ZenModeVisEffectsNonePreferenceController( + mContext, mock(Lifecycle.class), PREF_KEY); + ReflectionHelpers.setField(mController, "mBackend", mBackend); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mockPref); + mController.displayPreference(mScreen); + } + + @Test + public void isAvailable() { + assertTrue(mController.isAvailable()); + } + + @Test + public void updateState_notChecked() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.updateState(mockPref); + + verify(mockPref).setChecked(false); + } + + @Test + public void updateState_checked() { + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 0); + mController.updateState(mockPref); + + verify(mockPref).setChecked(true); + } + + @Test + public void onRadioButtonClick() { + int allSuppressed = SUPPRESSED_EFFECT_SCREEN_OFF + | SUPPRESSED_EFFECT_SCREEN_ON + | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT + | SUPPRESSED_EFFECT_AMBIENT + | SUPPRESSED_EFFECT_STATUS_BAR + | SUPPRESSED_EFFECT_BADGE + | SUPPRESSED_EFFECT_LIGHTS + | SUPPRESSED_EFFECT_PEEK + | SUPPRESSED_EFFECT_NOTIFICATION_LIST; + mBackend.mPolicy = new NotificationManager.Policy(0, 0, 0, 1); + mController.onRadioButtonClick(mockPref); + verify(mBackend).saveVisualEffectsPolicy(allSuppressed, false); + verify(mFeatureFactory.metricsFeatureProvider).action(nullable(Context.class), + eq(ACTION_ZEN_SOUND_ONLY), + eq(true)); + } +}