diff --git a/res/values/strings.xml b/res/values/strings.xml index 82d72348bca..d09489e47c3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7984,6 +7984,26 @@ Calendar events + + + {count, plural, offset:2 + =0 {} + =1 {{mode_1} is active} + =2 {{mode_1} and {mode_2} are active} + =3 {{mode_1}, {mode_2}, and {mode_3} are active} + other {{mode_1}, {mode_2}, and # more are active} + } + + + + + {count, plural, + =0 {} + =1 {1 mode can turn on automatically} + other {# modes can turn on automatically} + } + + ON diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java index 7a16d91d743..eec6808478f 100644 --- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java +++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java @@ -42,13 +42,10 @@ import static android.service.notification.ZenPolicy.VISUAL_EFFECT_STATUS_BAR; import android.content.Context; import android.icu.text.MessageFormat; -import android.provider.Settings; import android.service.notification.ZenDeviceEffects; -import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; import android.service.notification.ZenPolicy.ConversationSenders; import android.service.notification.ZenPolicy.PeopleType; -import android.util.ArrayMap; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -496,32 +493,36 @@ class ZenModeSummaryHelper { return msgFormat.format(args); } - String getSoundSummary(int zenMode, ZenModeConfig config) { - if (zenMode != Settings.Global.ZEN_MODE_OFF) { - String description = ZenModeConfig.getDescription(mContext, true, config, false); + String getModesSummary(List modes) { + List activeModes = modes.stream().filter(ZenMode::isActive).toList(); - if (description == null) { - return mContext.getString(R.string.zen_mode_sound_summary_on); - } else { - return mContext.getString(R.string.zen_mode_sound_summary_on_with_info, - description); - } - } else { - int count = 0; - final ArrayMap ruleMap = config.automaticRules; - if (ruleMap != null) { - for (ZenModeConfig.ZenRule rule : ruleMap.values()) { - if (rule != null && rule.enabled) { - count++; - } + if (!activeModes.isEmpty()) { + MessageFormat msgFormat = new MessageFormat( + mContext.getString(R.string.zen_modes_summary_some_active), + Locale.getDefault()); + + Map args = new HashMap<>(); + args.put("count", activeModes.size()); + args.put("mode_1", activeModes.get(0).getName()); + if (activeModes.size() >= 2) { + args.put("mode_2", activeModes.get(1).getName()); + if (activeModes.size() == 3) { + args.put("mode_3", activeModes.get(2).getName()); } } + + return msgFormat.format(args); + } else { + int automaticModeCount = (int) modes.stream() + .filter(m -> !m.isManualDnd() && !m.isCustomManual()) + .count(); + MessageFormat msgFormat = new MessageFormat( - mContext.getString(R.string.modes_sound_summary_off), + mContext.getString(R.string.zen_modes_summary_none_active), Locale.getDefault()); - Map msgArgs = new HashMap<>(); - msgArgs.put("count", count); + Map msgArgs = Map.of("count", automaticModeCount); return msgFormat.format(msgArgs); } } + } diff --git a/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java index f2679d7d0d0..aba82c823ec 100644 --- a/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java @@ -17,35 +17,31 @@ package com.android.settings.notification.modes; import android.app.Flags; -import android.app.NotificationManager; -import android.content.ContentResolver; import android.content.Context; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Handler; -import android.os.UserHandle; -import android.provider.Settings; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnPause; -import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.notification.modes.ZenModesBackend; public class ZenModesLinkPreferenceController extends BasePreferenceController - implements LifecycleObserver, OnResume, OnPause { + implements LifecycleObserver, OnStart, OnStop { - private SettingObserver mSettingObserver; - private ZenModeSummaryHelper mSummaryBuilder; - private NotificationManager mNm; + private final ZenModesBackend mBackend; + private final ZenSettingsObserver mSettingObserver; + private final ZenModeSummaryHelper mSummaryBuilder; + + private Preference mPreference; public ZenModesLinkPreferenceController(Context context, String key) { super(context, key); + mBackend = ZenModesBackend.getInstance(context); mSummaryBuilder = new ZenModeSummaryHelper(context, ZenHelperBackend.getInstance(context)); - mNm = mContext.getSystemService(NotificationManager.class); + mSettingObserver = new ZenSettingsObserver(context, this::onZenSettingsChanged); } @Override @@ -57,64 +53,31 @@ public class ZenModesLinkPreferenceController extends BasePreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - Preference preference = screen.findPreference(getPreferenceKey()); - mSettingObserver = new SettingObserver(preference); + mPreference = screen.findPreference(getPreferenceKey()); } @Override - public void onResume() { + public void onStart() { if (mSettingObserver != null) { - mSettingObserver.register(mContext.getContentResolver()); + mSettingObserver.register(); } } - @Override - public void onPause() { - if (mSettingObserver != null) { - mSettingObserver.unregister(mContext.getContentResolver()); + private void onZenSettingsChanged() { + if (mPreference != null) { + updateState(mPreference); } } @Override public void updateState(Preference preference) { - preference.setSummary(mSummaryBuilder.getSoundSummary( - Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.ZEN_MODE, - Settings.Global.ZEN_MODE_OFF), - mNm.getZenModeConfig())); + preference.setSummary(mSummaryBuilder.getModesSummary(mBackend.getModes())); } - class SettingObserver extends ContentObserver { - private final Uri ZEN_MODE_URI = Settings.Global.getUriFor(Settings.Global.ZEN_MODE); - private final Uri ZEN_MODE_CONFIG_ETAG_URI = Settings.Global.getUriFor( - Settings.Global.ZEN_MODE_CONFIG_ETAG); - - private final Preference mPreference; - - public SettingObserver(Preference preference) { - super(new Handler()); - mPreference = preference; - } - - public void register(ContentResolver cr) { - cr.registerContentObserver(ZEN_MODE_URI, false, this, UserHandle.USER_ALL); - cr.registerContentObserver(ZEN_MODE_CONFIG_ETAG_URI, false, this, UserHandle.USER_ALL); - } - - public void unregister(ContentResolver cr) { - cr.unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - super.onChange(selfChange, uri); - if (ZEN_MODE_URI.equals(uri)) { - updateState(mPreference); - } - - if (ZEN_MODE_CONFIG_ETAG_URI.equals(uri)) { - updateState(mPreference); - } + @Override + public void onStop() { + if (mSettingObserver != null) { + mSettingObserver.unregister(); } } } 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 948eec0277d..7ad7abc0934 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java @@ -16,10 +16,6 @@ package com.android.settings.notification.modes; -import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; -import static android.provider.Settings.Global.ZEN_MODE_OFF; -import static android.service.notification.Condition.SOURCE_UNKNOWN; -import static android.service.notification.Condition.STATE_TRUE; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE; import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE; @@ -33,17 +29,16 @@ import static com.google.common.truth.Truth.assertThat; import static org.robolectric.Shadows.shadowOf; +import android.app.AutomaticZenRule; import android.app.Flags; -import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.UserInfo; -import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; -import android.service.notification.Condition; +import android.service.notification.SystemZenRules; import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; @@ -65,6 +60,7 @@ import org.robolectric.RuntimeEnvironment; import java.util.Random; @RunWith(RobolectricTestRunner.class) +@EnableFlags(Flags.FLAG_MODES_UI) public class ZenModesSummaryHelperTest { private static final int WORK_PROFILE_ID = 3; @@ -480,85 +476,86 @@ public class ZenModesSummaryHelperTest { } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_off_noRules() { - ZenModeConfig config = new ZenModeConfig(); - - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_OFF, config)).isEqualTo("Off"); + public void getModesSummary_noRules_noSummary() { + String summary = mSummaryHelper.getModesSummary(ImmutableList.of()); + assertThat(summary).isEmpty(); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_off_oneRule() { - ZenModeConfig config = new ZenModeConfig(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - rule.enabled = true; - config.automaticRules.put("key", rule); - - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_OFF, config)) - .isEqualTo("Off / 1 mode can turn on automatically"); + public void getModesSummary_onlyDndAndNotActive_noSummary() { + ImmutableList modes = ImmutableList.of(TestModeBuilder.MANUAL_DND_INACTIVE); + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEmpty(); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_off_twoRules() { - ZenModeConfig config = new ZenModeConfig(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - rule.enabled = true; - ZenModeConfig.ZenRule rule2 = new ZenModeConfig.ZenRule(); - rule2.enabled = true; - config.automaticRules.put("key", rule); - config.automaticRules.put("key2", rule2); + public void getModesSummary_noRulesActive_countsOnlyAutomaticModes() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_INACTIVE, // Not automatic + new TestModeBuilder().setName("Auto 1").build(), // App provided automatic + new TestModeBuilder() + .setName("Custom manual 1") + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .setType(AutomaticZenRule.TYPE_OTHER) + .setConditionId(ZenModeConfig.toCustomManualConditionId()) + .build(), // Custom manual, not automatic + new TestModeBuilder() + .setName("Sleep") + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME) + .build() // Time based, automatic. + ); - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_OFF, config)) - .isEqualTo("Off / 2 modes can turn on automatically"); + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("2 modes can turn on automatically"); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_on_noDescription() { - ZenModeConfig config = new ZenModeConfig(); - config.manualRule.conditionId = Uri.EMPTY; - config.manualRule.pkg = "android"; - config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - config.manualRule.condition = new Condition(Uri.EMPTY, "", STATE_TRUE, SOURCE_UNKNOWN); - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config)) - .isEqualTo("On"); + public void getModesSummary_oneModeActive_listsMode() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_ACTIVE, + new TestModeBuilder().setName("Inactive").setActive(false).build()); + + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("Do Not Disturb is active"); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_on_manualDescription() { - ZenModeConfig config = new ZenModeConfig(); - config.manualRule.conditionId = ZenModeConfig.toCountdownConditionId( - System.currentTimeMillis() + 10000, false); - config.manualRule.pkg = "android"; - config.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - config.manualRule.condition = new Condition(Uri.EMPTY, "", STATE_TRUE, SOURCE_UNKNOWN); - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config)) - .startsWith("On /"); + public void getModesSummary_twoModesActive_listsModes() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_ACTIVE, + new TestModeBuilder().setName("Inactive").setActive(false).build(), + new TestModeBuilder().setName("Active #1").setActive(true).build()); + + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("Do Not Disturb and Active #1 are active"); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) - public void getSoundSummary_on_automatic() { - ZenModeConfig config = new ZenModeConfig(); - ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); - rule.configurationActivity = new ComponentName("a", "a"); - rule.component = new ComponentName("b", "b"); - rule.conditionId = new Uri.Builder().scheme("hello").build(); - rule.condition = new Condition(rule.conditionId, "", STATE_TRUE); - rule.enabled = true; - rule.creationTime = 123; - rule.id = "id"; - rule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; - rule.modified = true; - rule.name = "name"; - rule.snoozing = false; - rule.pkg = "b"; - config.automaticRules.put("key", rule); + public void getModesSummary_threeModesActive_listsModes() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_INACTIVE, + new TestModeBuilder().setName("Inactive #1").setActive(false).build(), + new TestModeBuilder().setName("Active #1").setActive(true).build(), + new TestModeBuilder().setName("Active #2").setActive(true).build(), + new TestModeBuilder().setName("Inactive #2").setActive(false).build(), + new TestModeBuilder().setName("Active #3").setActive(true).build()); - assertThat(mSummaryHelper.getSoundSummary(ZEN_MODE_IMPORTANT_INTERRUPTIONS, config)) - .startsWith("On /"); + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("Active #1, Active #2, and Active #3 are active"); + } + + @Test + public void getModesSummary_manyModesActive_listsACouple() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_ACTIVE, + new TestModeBuilder().setName("Inactive #1").setActive(false).build(), + new TestModeBuilder().setName("Active #1").setActive(true).build(), + new TestModeBuilder().setName("Active #2").setActive(true).build(), + new TestModeBuilder().setName("Inactive #2").setActive(false).build(), + new TestModeBuilder().setName("Active #3").setActive(true).build()); + + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("Do Not Disturb, Active #1, and 2 more are active"); } }