diff --git a/res/values/strings.xml b/res/values/strings.xml index ff585c3173f..264a40fd394 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7948,8 +7948,55 @@ Allow visual signals + + Notifications that can reach you + + Additional actions + + + + Display settings + + Display options + + Grayscale + + grayscale + + Change the screen to black and white + + Keep the screen dark + + keep the screen dark + + Disable always on display + + Dim the wallpaper + + dim the wallpaper + + Filter the brightness of the wallpaper + + Enable dark theme + + enable dark theme + + Switch the OS and apps to prefer light text on a dark + background, which may be easier on the eyes and confers significant battery savings on some devices + + + {count, plural, offset:2 + =0 {No display changes} + =1 {{effect_1}} + =2 {{effect_1} and {effect_2}} + =3 {{effect_1}, {effect_2}, and {effect_3}} + other {{effect_1}, {effect_2}, and # more} + } + + - Display options for hidden notifications + Display options for filtered + notifications When Do Not Disturb is on @@ -7971,11 +8018,12 @@ Remove custom setting - No sound from notifications + Notifications shown - Partially hidden + Notifications partially + hidden - No visuals or sound from notifications + Notifications hidden Custom restrictions diff --git a/res/xml/modes_display_settings.xml b/res/xml/modes_display_settings.xml new file mode 100644 index 00000000000..53268ecc95d --- /dev/null +++ b/res/xml/modes_display_settings.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + diff --git a/res/xml/modes_notif_vis_settings.xml b/res/xml/modes_notif_vis_settings.xml new file mode 100644 index 00000000000..551c704a24a --- /dev/null +++ b/res/xml/modes_notif_vis_settings.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml index 7a08a68d8c0..a380987d377 100644 --- a/res/xml/modes_rule_settings.xml +++ b/res/xml/modes_rule_settings.xml @@ -22,12 +22,23 @@ android:key="header" android:layout="@layout/settings_entity_header" /> - + + - + + + + + \ No newline at end of file diff --git a/src/com/android/settings/notification/modes/ZenMode.java b/src/com/android/settings/notification/modes/ZenMode.java index 51c92e6eae5..ea94f7d8c8f 100644 --- a/src/com/android/settings/notification/modes/ZenMode.java +++ b/src/com/android/settings/notification/modes/ZenMode.java @@ -90,7 +90,7 @@ class ZenMode { .build(); private final String mId; - private final AutomaticZenRule mRule; + private AutomaticZenRule mRule; private final boolean mIsActive; private final boolean mIsManualDnd; @@ -190,6 +190,14 @@ class ZenMode { } } + /** + * Use sparingly. If you're updating a policy field, use + * {@link #setPolicy(android.service.notification.ZenPolicy)} instead. + */ + public void setAzr(@NonNull AutomaticZenRule newRule) { + mRule = newRule; + } + /** * Updates the {@link ZenPolicy} of the associated {@link AutomaticZenRule} based on the * supplied policy. In some cases this involves conversions, so that the following call diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java new file mode 100644 index 00000000000..f69d0d63fac --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java @@ -0,0 +1,94 @@ +/* + * 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.service.notification.ZenPolicy.PRIORITY_CATEGORY_ALARMS; +import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_EVENTS; +import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_MEDIA; +import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_REMINDERS; +import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_SYSTEM; + +import android.app.AutomaticZenRule; +import android.content.Context; +import android.service.notification.ZenDeviceEffects; +import android.service.notification.ZenPolicy; +import androidx.preference.Preference; +import androidx.preference.TwoStatePreference; + +public class ZenModeDisplayEffectPreferenceController extends AbstractZenModePreferenceController + implements Preference.OnPreferenceChangeListener { + + public ZenModeDisplayEffectPreferenceController(Context context, String key, + ZenModesBackend backend) { + super(context, key, backend); + } + + @Override + public void updateState(Preference preference) { + TwoStatePreference pref = (TwoStatePreference) preference; + ZenDeviceEffects effects = getMode().getRule().getDeviceEffects(); + if (effects == null) { + pref.setChecked(false); + } else { + switch (getPreferenceKey()) { + case "effect_greyscale": + pref.setChecked(effects.shouldDisplayGrayscale()); + break; + case "effect_aod": + pref.setChecked(effects.shouldSuppressAmbientDisplay()); + break; + case "effect_wallpaper": + pref.setChecked(effects.shouldDimWallpaper()); + break; + case "effect_dark_theme": + pref.setChecked(effects.shouldUseNightMode()); + break; + } + } + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean allow = (Boolean) newValue; + + ZenDeviceEffects currEffects = getMode().getRule().getDeviceEffects(); + ZenDeviceEffects.Builder updatedEffects = currEffects == null + ? new ZenDeviceEffects.Builder() + : new ZenDeviceEffects.Builder(getMode().getRule().getDeviceEffects()); + switch (getPreferenceKey()) { + case "effect_greyscale": + updatedEffects.setShouldDisplayGrayscale(allow); + break; + case "effect_aod": + updatedEffects.setShouldSuppressAmbientDisplay(allow); + break; + case "effect_wallpaper": + updatedEffects.setShouldDimWallpaper(allow); + break; + case "effect_dark_theme": + updatedEffects.setShouldUseNightMode(allow); + break; + } + AutomaticZenRule updatedAzr = new AutomaticZenRule.Builder(getMode().getRule()) + .setDeviceEffects(updatedEffects.build()) + .build(); + getMode().setAzr(updatedAzr); + mBackend.updateMode(getMode()); + + return true; + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayFragment.java b/src/com/android/settings/notification/modes/ZenModeDisplayFragment.java new file mode 100644 index 00000000000..09720495ed1 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeDisplayFragment.java @@ -0,0 +1,59 @@ +/* + * 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; + +/** + * Settings page that shows what device effects/notification visuals will change when this mode + * is on. + */ +public class ZenModeDisplayFragment extends ZenModeFragmentBase { + + @Override + protected List createPreferenceControllers(Context context) { + List prefControllers = new ArrayList<>(); + prefControllers.add(new ZenModeNotifVisLinkPreferenceController( + context, "notification_visibility", mBackend)); + prefControllers.add(new ZenModeDisplayEffectPreferenceController( + context, "effect_greyscale", mBackend)); + prefControllers.add(new ZenModeDisplayEffectPreferenceController( + context, "effect_aod", mBackend)); + prefControllers.add(new ZenModeDisplayEffectPreferenceController( + context, "effect_wallpaper", mBackend)); + prefControllers.add(new ZenModeDisplayEffectPreferenceController( + context, "effect_dark_theme", mBackend)); + return prefControllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.modes_display_settings; + } + + @Override + public int getMetricsCategory() { + // TODO: b/332937635 - make this the correct metrics category + return SettingsEnums.DND_PEOPLE; + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java new file mode 100644 index 00000000000..943874a5d48 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java @@ -0,0 +1,53 @@ +/* + * 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.preference.Preference; +import com.android.settings.core.SubSettingLauncher; + +public class ZenModeDisplayLinkPreferenceController extends AbstractZenModePreferenceController { + + ZenModeSummaryHelper mSummaryHelper; + + public ZenModeDisplayLinkPreferenceController(Context context, String key, + ZenModesBackend backend) { + super(context, key, backend); + mSummaryHelper = new ZenModeSummaryHelper(context, backend); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + Bundle bundle = new Bundle(); + bundle.putString(MODE_ID, getMode().getId()); + // TODO(b/332937635): Update metrics category + preference.setIntent(new SubSettingLauncher(mContext) + .setDestination(ZenModeDisplayFragment.class.getName()) + .setSourceMetricsCategory(0) + .setArguments(bundle) + .toIntent()); + } + + @Override + public CharSequence getSummary() { + return mSummaryHelper.getDisplayEffectsSummary(getMode()); + } +} \ No newline at end of file diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java index 51772f00a45..7f805eeb669 100644 --- a/src/com/android/settings/notification/modes/ZenModeFragment.java +++ b/src/com/android/settings/notification/modes/ZenModeFragment.java @@ -35,14 +35,14 @@ public class ZenModeFragment extends ZenModeFragmentBase { @Override protected List createPreferenceControllers(Context context) { - // TODO: fill in with all the elements of this page. Each should be an instance of - // {@link AbstractZenModePreferenceController}. List prefControllers = new ArrayList<>(); prefControllers.add(new ZenModeHeaderController(context, "header", this, mBackend)); prefControllers.add(new ZenModePeopleLinkPreferenceController( context, "zen_mode_people", mBackend)); prefControllers.add(new ZenModeOtherLinkPreferenceController( context, "zen_other_settings", mBackend)); + prefControllers.add(new ZenModeDisplayLinkPreferenceController( + context, "mode_display_settings", mBackend)); return prefControllers; } diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisFragment.java b/src/com/android/settings/notification/modes/ZenModeNotifVisFragment.java new file mode 100644 index 00000000000..3fdfec6e106 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeNotifVisFragment.java @@ -0,0 +1,63 @@ +/* + * 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 com.android.settings.R; +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.ArrayList; +import java.util.List; + +/** + * Settings page that shows what notification visuals will change when this mode is on. + */ +public class ZenModeNotifVisFragment extends ZenModeFragmentBase { + @Override + protected List createPreferenceControllers(Context context) { + List prefControllers = new ArrayList<>(); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_intent", ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT, null, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_light", ZenPolicy.VISUAL_EFFECT_LIGHTS, null, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_peek", ZenPolicy.VISUAL_EFFECT_PEEK, null, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_status", ZenPolicy.VISUAL_EFFECT_STATUS_BAR, + new int[] {ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST}, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_badge", ZenPolicy.VISUAL_EFFECT_BADGE, null, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_ambient", ZenPolicy.VISUAL_EFFECT_AMBIENT, null, mBackend)); + prefControllers.add(new ZenModeNotifVisPreferenceController(context, + "zen_effect_list", ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST, null, mBackend)); + return prefControllers; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.modes_notif_vis_settings; + } + + @Override + public int getMetricsCategory() { + // TODO: b/332937635 - make this the correct metrics category + return SettingsEnums.DND_PEOPLE; + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java new file mode 100644 index 00000000000..9807431fb17 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java @@ -0,0 +1,52 @@ +/* + * 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.preference.Preference; +import com.android.settings.core.SubSettingLauncher; + +public class ZenModeNotifVisLinkPreferenceController extends AbstractZenModePreferenceController { + + ZenModeSummaryHelper mSummaryBuilder; + public ZenModeNotifVisLinkPreferenceController(Context context, String key, + ZenModesBackend backend) { + super(context, key, backend); + mSummaryBuilder = new ZenModeSummaryHelper(context, backend); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + Bundle bundle = new Bundle(); + bundle.putString(MODE_ID, getMode().getId()); + // TODO(b/332937635): Update metrics category + preference.setIntent(new SubSettingLauncher(mContext) + .setDestination(ZenModeNotifVisFragment.class.getName()) + .setSourceMetricsCategory(0) + .setArguments(bundle) + .toIntent()); + } + + @Override + public CharSequence getSummary() { + return mSummaryBuilder.getBlockedEffectsSummary(getMode()); + } +} \ No newline at end of file diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java new file mode 100644 index 00000000000..9b89a646811 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java @@ -0,0 +1,91 @@ +/* + * 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.content.Context; +import android.service.notification.ZenPolicy; +import androidx.annotation.VisibleForTesting; +import androidx.preference.CheckBoxPreference; +import androidx.preference.Preference; +import com.android.settings.widget.DisabledCheckBoxPreference; + +public class ZenModeNotifVisPreferenceController extends AbstractZenModePreferenceController + implements Preference.OnPreferenceChangeListener { + + @VisibleForTesting protected @ZenPolicy.VisualEffect int mEffect; + + // if any of these effects are suppressed, this effect must be too + @VisibleForTesting protected @ZenPolicy.VisualEffect int[] mParentSuppressedEffects; + + public ZenModeNotifVisPreferenceController(Context context, String key, + @ZenPolicy.VisualEffect int visualEffect, + @ZenPolicy.VisualEffect int[] parentSuppressedEffects, ZenModesBackend backend) { + super(context, key, backend); + mEffect = visualEffect; + mParentSuppressedEffects = parentSuppressedEffects; + } + + @Override + public boolean isAvailable() { + if (!super.isAvailable()) { + return false; + } + + if (mEffect == ZenPolicy.VISUAL_EFFECT_LIGHTS) { + return mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed); + } + return true; + } + + @Override + public void updateState(Preference preference) { + + boolean suppressed = !getMode().getPolicy().isVisualEffectAllowed(mEffect, false); + boolean parentSuppressed = false; + if (mParentSuppressedEffects != null) { + for (@ZenPolicy.VisualEffect int parentEffect : mParentSuppressedEffects) { + if (!getMode().getPolicy().isVisualEffectAllowed(parentEffect, true)) { + parentSuppressed = true; + } + } + } + if (parentSuppressed) { + ((CheckBoxPreference) preference).setChecked(true); + onPreferenceChange(preference, true); + ((DisabledCheckBoxPreference) preference).enableCheckbox(false); + } else { + ((DisabledCheckBoxPreference) preference).enableCheckbox(true); + ((CheckBoxPreference) preference).setChecked(suppressed); + } + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean allowEffect = !((Boolean) newValue); + + if (getMode().getPolicy().isVisualEffectAllowed(mEffect, true) != allowEffect) { + ZenPolicy diffPolicy = new ZenPolicy.Builder() + .showVisualEffect(mEffect, allowEffect) + .build(); + getMode().setPolicy(diffPolicy); + mBackend.updateMode(getMode()); + } + + return true; + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java index cf0c3db7499..e1a7cafa786 100644 --- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java +++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java @@ -30,11 +30,21 @@ import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_MESSAGES; import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_REMINDERS; import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS; import static android.service.notification.ZenPolicy.PRIORITY_CATEGORY_SYSTEM; +import static android.service.notification.ZenPolicy.STATE_DISALLOW; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_AMBIENT; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_BADGE; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_PEEK; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_STATUS_BAR; import android.content.Context; import android.icu.text.MessageFormat; +import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenPolicy; +import android.util.SparseArray; import com.android.settings.R; import java.util.ArrayList; @@ -129,10 +139,22 @@ public class ZenModeSummaryHelper { } String getBlockedEffectsSummary(ZenMode zenMode) { - if (zenMode.getPolicy().shouldShowAllVisualEffects()) { + List relevantVisualEffects = new ArrayList<>(); + relevantVisualEffects.add(VISUAL_EFFECT_FULL_SCREEN_INTENT); + relevantVisualEffects.add(VISUAL_EFFECT_PEEK); + relevantVisualEffects.add(VISUAL_EFFECT_STATUS_BAR); + relevantVisualEffects.add(VISUAL_EFFECT_BADGE); + relevantVisualEffects.add(VISUAL_EFFECT_AMBIENT); + relevantVisualEffects.add(VISUAL_EFFECT_NOTIFICATION_LIST); + if (mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) { + relevantVisualEffects.add(VISUAL_EFFECT_LIGHTS); + } + + if (shouldShowAllVisualEffects(zenMode.getPolicy(), relevantVisualEffects)) { return mContext.getResources().getString( R.string.zen_mode_restrict_notifications_summary_muted); - } else if (zenMode.getPolicy().shouldHideAllVisualEffects()) { + } else if (shouldHideAllVisualEffects(zenMode.getPolicy(), relevantVisualEffects)) { return mContext.getResources().getString( R.string.zen_mode_restrict_notifications_summary_hidden); } else { @@ -141,6 +163,89 @@ public class ZenModeSummaryHelper { } } + private boolean shouldShowAllVisualEffects(ZenPolicy policy, List relevantEffects) { + for (int i = 0; i < relevantEffects.size(); i++) { + if (!policy.isVisualEffectAllowed(relevantEffects.get(i), false)) { + return false; + } + } + return true; + } + + private boolean shouldHideAllVisualEffects(ZenPolicy policy, List relevantEffects) { + for (int i = 0; i < relevantEffects.size(); i++) { + if (policy.isVisualEffectAllowed(relevantEffects.get(i), false)) { + return false; + } + } + return true; + } + + String getDisplayEffectsSummary(ZenMode zenMode) { + boolean isFirst = true; + List enabledEffects = new ArrayList<>(); + if (!zenMode.getPolicy().shouldShowAllVisualEffects()) { + enabledEffects.add(getBlockedEffectsSummary(zenMode)); + isFirst = false; + } + ZenDeviceEffects currEffects = zenMode.getRule().getDeviceEffects(); + if (currEffects != null) { + if (currEffects.shouldDisplayGrayscale()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_grayscale_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_grayscale_title_secondary_list)); + } + isFirst = false; + } + if (currEffects.shouldSuppressAmbientDisplay()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_aod_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_aod_title_secondary_list)); + } + isFirst = false; + } + if (currEffects.shouldDimWallpaper()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_wallpaper_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_wallpaper_title_secondary_list)); + } + isFirst = false; + } + if (currEffects.shouldUseNightMode()) { + if (isFirst) { + enabledEffects.add(mContext.getString(R.string.mode_dark_theme_title)); + } else { + enabledEffects.add(mContext.getString( + R.string.mode_dark_theme_title_secondary_list)); + } + isFirst = false; + } + } + + int numCategories = enabledEffects.size(); + MessageFormat msgFormat = new MessageFormat( + mContext.getString(R.string.mode_display_settings_summary), + Locale.getDefault()); + Map args = new HashMap<>(); + args.put("count", numCategories); + if (numCategories >= 1) { + args.put("effect_1", enabledEffects.get(0)); + if (numCategories >= 2) { + args.put("effect_2", enabledEffects.get(1)); + if (numCategories == 3) { + args.put("effect_3", enabledEffects.get(2)); + } + } + } + return msgFormat.format(args); + } + private List getEnabledCategories(ZenPolicy policy, Predicate filteredCategories, boolean capitalizeFirstInList) { List enabledCategories = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java new file mode 100644 index 00000000000..1a62b75468a --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java @@ -0,0 +1,252 @@ +/* + * 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_PRIORITY; +import static android.service.notification.ZenPolicy.STATE_ALLOW; +import static android.service.notification.ZenPolicy.STATE_UNSET; +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.ZenDeviceEffects; +import android.service.notification.ZenPolicy; +import androidx.preference.TwoStatePreference; +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 ZenModeDisplayEffectPreferenceControllerTest { + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + } + + @Test + public void testUpdateState_grayscale() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDisplayGrayscale(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController( + mContext, "effect_greyscale", mBackend); + + controller.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testOnPreferenceChange_grayscale() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowAlarms(false).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDisplayGrayscale(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController(mContext, "effect_greyscale", mBackend); + + controller.updateZenMode(preference, zenMode); + + controller.onPreferenceChange(preference, false); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getRule().getDeviceEffects().shouldDisplayGrayscale()) + .isFalse(); + } + + @Test + public void testUpdateState_aod() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowMedia(true).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldSuppressAmbientDisplay(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController(mContext, "effect_aod", mBackend); + + controller.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testOnPreferenceChange_aod() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowMedia(false).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldSuppressAmbientDisplay(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController(mContext, "effect_aod", mBackend); + + controller.updateZenMode(preference, zenMode); + + controller.onPreferenceChange(preference, false); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getRule().getDeviceEffects().shouldSuppressAmbientDisplay()) + .isFalse(); + } + + @Test + public void testUpdateState_wallpaper() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowSystem(true).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDimWallpaper(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController( + mContext, "effect_wallpaper", mBackend); + + controller.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testOnPreferenceChange_wallpaper() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowSystem(false).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDimWallpaper(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController( + mContext, "effect_wallpaper", mBackend); + + controller.updateZenMode(preference, zenMode); + + controller.onPreferenceChange(preference, false); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getRule().getDeviceEffects().shouldDimWallpaper()).isFalse(); + } + + @Test + public void testUpdateState_darkTheme() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowReminders(true).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldUseNightMode(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController(mContext, "effect_dark_theme", + mBackend); + + controller.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + } + + @Test + public void testOnPreferenceChange_darkTheme() { + TwoStatePreference preference = mock(TwoStatePreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowReminders(false).build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldUseNightMode(true) + .build()) + .build(), true); + + ZenModeDisplayEffectPreferenceController controller = + new ZenModeDisplayEffectPreferenceController(mContext, "effect_dark_theme", + mBackend); + + controller.updateZenMode(preference, zenMode); + + controller.onPreferenceChange(preference, false); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getRule().getDeviceEffects().shouldUseNightMode()).isFalse(); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java new file mode 100644 index 00000000000..9d33b0b7600 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.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 android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; +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) +public final class ZenModeDisplayLinkPreferenceControllerTest { + + private ZenModeDisplayLinkPreferenceController mController; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + + mController = new ZenModeDisplayLinkPreferenceController( + mContext, "something", 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) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build()) + .build(), true); + mController.updateZenMode(pref, zenMode); + verify(pref).setSummary(any()); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java new file mode 100644 index 00000000000..646c7aae9c6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.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 android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; +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) +public final class ZenModeNotifVisLinkPreferenceControllerTest { + + private ZenModeNotifVisLinkPreferenceController mController; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + + mController = new ZenModeNotifVisLinkPreferenceController( + mContext, "something", 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) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build()) + .build(), true); + mController.updateZenMode(pref, zenMode); + verify(pref).setSummary(any()); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java new file mode 100644 index 00000000000..7424ae6c1f9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java @@ -0,0 +1,241 @@ +/* + * 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_PRIORITY; +import static android.service.notification.ZenPolicy.STATE_ALLOW; +import static android.service.notification.ZenPolicy.STATE_DISALLOW; +import static android.service.notification.ZenPolicy.STATE_UNSET; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_PEEK; +import static android.service.notification.ZenPolicy.VISUAL_EFFECT_STATUS_BAR; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.AutomaticZenRule; +import android.app.Flags; +import android.content.Context; +import android.content.res.Resources; +import android.net.Uri; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.service.notification.ZenDeviceEffects; +import android.service.notification.ZenPolicy; +import androidx.preference.TwoStatePreference; +import com.android.settings.notification.zen.ZenModeVisEffectPreferenceController; +import com.android.settings.widget.DisabledCheckBoxPreference; +import com.android.settingslib.core.lifecycle.Lifecycle; +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 ZenModeNotifVisPreferenceControllerTest { + + private Context mContext; + @Mock + private ZenModesBackend mBackend; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private ZenModeNotifVisPreferenceController mController; + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new ZenModeNotifVisPreferenceController(mContext, + "zen_effect_peek", VISUAL_EFFECT_PEEK, null, mBackend); + } + @Test + public void isAvailable() { + // SUPPRESSED_EFFECT_PEEK is always available: + assertThat(mController.isAvailable()).isTrue(); + + // SUPPRESSED_EFFECT_LIGHTS is only available if the device has an LED: + Context mockContext = mock(Context.class); + mController = new ZenModeNotifVisPreferenceController(mockContext, + "zen_effect_light", VISUAL_EFFECT_LIGHTS, null, mBackend); + Resources mockResources = mock(Resources.class); + when(mockContext.getResources()).thenReturn(mockResources); + + when(mockResources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) + .thenReturn(false); // no light + assertThat(mController.isAvailable()).isFalse(); + + when(mockResources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed)) + .thenReturn(true); // has light + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void updateState_notChecked() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showAllVisualEffects() + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(false); + verify(preference).enableCheckbox(true); + } + + @Test + public void updateState_checked() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showVisualEffect(VISUAL_EFFECT_PEEK, false) + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + verify(preference).enableCheckbox(true); + } + + @Test + public void updateState_checkedFalse_parentChecked() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + mController = new ZenModeNotifVisPreferenceController(mContext, + "zen_effect_status", VISUAL_EFFECT_STATUS_BAR, + new int[]{VISUAL_EFFECT_NOTIFICATION_LIST}, mBackend); + + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, false) + .showVisualEffect(VISUAL_EFFECT_STATUS_BAR, true) + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(true); + verify(preference).enableCheckbox(false); + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getPolicy().getVisualEffectStatusBar()) + .isEqualTo(STATE_DISALLOW); + assertThat(captor.getValue().getPolicy().getVisualEffectNotificationList()) + .isEqualTo(STATE_UNSET); + } + + @Test + public void updateState_checkedFalse_parentNotChecked() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + mController = new ZenModeNotifVisPreferenceController(mContext, + "zen_effect_status", VISUAL_EFFECT_STATUS_BAR, + new int[]{VISUAL_EFFECT_NOTIFICATION_LIST}, mBackend); + + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showAllVisualEffects() + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + verify(preference).setChecked(false); + verify(preference).enableCheckbox(true); + verify(mBackend, never()).updateMode(any()); + } + + @Test + public void onPreferenceChanged_checkedFalse() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .hideAllVisualEffects() + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + mController.onPreferenceChange(preference, false); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getPolicy().getVisualEffectPeek()) + .isEqualTo(STATE_ALLOW); + assertThat(captor.getValue().getPolicy().getVisualEffectNotificationList()) + .isEqualTo(STATE_UNSET); + } + + @Test + public void onPreferenceChanged_checkedTrue() { + DisabledCheckBoxPreference preference = mock(DisabledCheckBoxPreference.class); + ZenMode zenMode = new ZenMode("id", + new AutomaticZenRule.Builder("Driving", Uri.parse("drive")) + .setType(AutomaticZenRule.TYPE_DRIVING) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showAllVisualEffects() + .build()) + .build(), true); + + mController.updateZenMode(preference, zenMode); + + mController.onPreferenceChange(preference, true); + + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + assertThat(captor.getValue().getPolicy().getVisualEffectPeek()) + .isEqualTo(STATE_DISALLOW); + assertThat(captor.getValue().getPolicy().getVisualEffectNotificationList()) + .isEqualTo(STATE_UNSET); + } +} \ No newline at end of file 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 67be82f9032..3e41778cdc0 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java @@ -20,11 +20,14 @@ import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE; 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; 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; @@ -165,4 +168,161 @@ public class ZenModesSummaryHelperTest { assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo( "Alarms, media, and 3 more can interrupt"); } + + @Test + public void getBlockedEffectsSummary_none() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .showAllVisualEffects() + .allowAlarms(true) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode)) + .isEqualTo("Notifications shown"); + } + + @Test + public void getBlockedEffectsSummary_some() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .showAllVisualEffects() + .showVisualEffect(VISUAL_EFFECT_AMBIENT, false) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode)) + .isEqualTo("Notifications partially hidden"); + } + + @Test + public void getBlockedEffectsSummary_all() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .allowAlarms(true) + .hideAllVisualEffects() + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode)) + .isEqualTo("Notifications hidden"); + } + + @Test + public void getDisplayEffectsSummary_single_notifVis() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .showAllVisualEffects() + .showVisualEffect(VISUAL_EFFECT_AMBIENT, false) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Notifications partially hidden"); + } + + @Test + public void getDisplayEffectsSummary_single_notifVis_unusedEffect() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .showAllVisualEffects() + .showVisualEffect(VISUAL_EFFECT_LIGHTS, false) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Notifications shown"); + } + + @Test + public void getDisplayEffectsSummary_single_displayEffect() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().showAllVisualEffects().build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDimWallpaper(true) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Dim the wallpaper"); + } + + @Test + public void getDisplayEffectsSummary_duo() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().showAllVisualEffects().build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDimWallpaper(true) + .setShouldDisplayGrayscale(true) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Grayscale and dim the wallpaper"); + } + + @Test + public void getDisplayEffectsSummary_trio() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .hideAllVisualEffects() + .allowAlarms(true) + .allowMedia(true) + .allowSystem(true) + .build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDisplayGrayscale(true) + .setShouldDimWallpaper(true) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Notifications hidden, grayscale, and dim the wallpaper"); + } + + @Test + public void getDisplayEffectsSummary_quad() { + AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed")) + .setType(AutomaticZenRule.TYPE_BEDTIME) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder() + .showAllVisualEffects() + .showVisualEffect(VISUAL_EFFECT_AMBIENT, false) + .allowAlarms(true) + .allowMedia(true) + .allowSystem(true) + .build()) + .setDeviceEffects(new ZenDeviceEffects.Builder() + .setShouldDimWallpaper(true) + .setShouldDisplayGrayscale(true) + .setShouldUseNightMode(true) + .build()) + .build(); + ZenMode zenMode = new ZenMode("id", rule, true); + + assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo( + "Notifications partially hidden, grayscale, and 2 more"); + } }