diff --git a/res/drawable/ic_modes_event.xml b/res/drawable/ic_modes_event.xml new file mode 100644 index 00000000000..40004899ad8 --- /dev/null +++ b/res/drawable/ic_modes_event.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/res/drawable/ic_modes_time.xml b/res/drawable/ic_modes_time.xml new file mode 100644 index 00000000000..dff3c43933d --- /dev/null +++ b/res/drawable/ic_modes_time.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml index d7e26946829..1b79153cf7b 100644 --- a/res/xml/modes_rule_settings.xml +++ b/res/xml/modes_rule_settings.xml @@ -18,8 +18,8 @@ - - + \ 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 66d68c5c7cd..51c92e6eae5 100644 --- a/src/com/android/settings/notification/modes/ZenMode.java +++ b/src/com/android/settings/notification/modes/ZenMode.java @@ -155,8 +155,8 @@ class ZenMode { int iconResIdFromType = switch (mRule.getType()) { case AutomaticZenRule.TYPE_UNKNOWN -> R.drawable.ic_do_not_disturb_on_24dp; case AutomaticZenRule.TYPE_OTHER -> R.drawable.ic_do_not_disturb_on_24dp; - case AutomaticZenRule.TYPE_SCHEDULE_TIME -> R.drawable.ic_do_not_disturb_on_24dp; - case AutomaticZenRule.TYPE_SCHEDULE_CALENDAR -> R.drawable.ic_do_not_disturb_on_24dp; + case AutomaticZenRule.TYPE_SCHEDULE_TIME -> R.drawable.ic_modes_time; + case AutomaticZenRule.TYPE_SCHEDULE_CALENDAR -> R.drawable.ic_modes_event; case AutomaticZenRule.TYPE_BEDTIME -> R.drawable.ic_do_not_disturb_on_24dp; case AutomaticZenRule.TYPE_DRIVING -> R.drawable.ic_do_not_disturb_on_24dp; case AutomaticZenRule.TYPE_IMMERSIVE -> R.drawable.ic_do_not_disturb_on_24dp; diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java index 616332e0d1f..d2126810358 100644 --- a/src/com/android/settings/notification/modes/ZenModeFragment.java +++ b/src/com/android/settings/notification/modes/ZenModeFragment.java @@ -41,6 +41,7 @@ public class ZenModeFragment extends ZenModeFragmentBase { // 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)); return prefControllers; } @@ -55,19 +56,6 @@ public class ZenModeFragment extends ZenModeFragmentBase { return; } getActivity().setTitle(azr.getName()); - - // TODO: b/308819292 - implement the real screen! - final PreferenceScreen screen = getPreferenceScreen(); - if (screen == null) { - return; - } - - Preference tmpPref = screen.findPreference("zen_mode_test"); - if (tmpPref == null) { - return; - } - tmpPref.setTitle(azr.getTriggerDescription()); - tmpPref.setSummary("active?: " + mode.isActive()); } @Override diff --git a/src/com/android/settings/notification/modes/ZenModeHeaderController.java b/src/com/android/settings/notification/modes/ZenModeHeaderController.java new file mode 100644 index 00000000000..246eee85d77 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeHeaderController.java @@ -0,0 +1,75 @@ +/* + * 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.Flags; +import android.content.Context; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.widget.EntityHeaderController; +import com.android.settingslib.widget.LayoutPreference; + +import java.util.concurrent.TimeUnit; + +public class ZenModeHeaderController extends AbstractZenModePreferenceController { + + private final DashboardFragment mFragment; + private EntityHeaderController mHeaderController; + + ZenModeHeaderController( + @NonNull Context context, + @NonNull String key, + @NonNull DashboardFragment fragment, + @Nullable ZenModesBackend backend) { + super(context, key, backend); + mFragment = fragment; + } + + @Override + public boolean isAvailable() { + return Flags.modesApi(); + } + + @Override + public void updateState(Preference preference) { + if (getAZR() == null || mFragment == null) { + return; + } + + if (mHeaderController == null) { + final LayoutPreference pref = (LayoutPreference) preference; + mHeaderController = EntityHeaderController.newInstance( + mFragment.getActivity(), + mFragment, + pref.findViewById(R.id.entity_header)); + } + Drawable icon = null; + try { + icon = getMode().getIcon(mContext).get(200, TimeUnit.MILLISECONDS); + } catch (Exception e) { + // no icon + } + mHeaderController.setIcon(icon) + .setLabel(getAZR().getName()) + .done(false /* rebindActions */); + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeListPreference.java b/src/com/android/settings/notification/modes/ZenModeListPreference.java index cb0456140bf..2a95dffc5e0 100644 --- a/src/com/android/settings/notification/modes/ZenModeListPreference.java +++ b/src/com/android/settings/notification/modes/ZenModeListPreference.java @@ -25,6 +25,10 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.notification.zen.ZenModeSettings; import com.android.settingslib.RestrictedPreference; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + /** * Preference representing a single mode item on the modes aggregator page. Clicking on this * preference leads to an individual mode's configuration page. @@ -36,10 +40,8 @@ public class ZenModeListPreference extends RestrictedPreference { ZenModeListPreference(Context context, ZenMode zenMode) { super(context); mContext = context; - mZenMode = zenMode; - setTitle(mZenMode.getRule().getName()); - setSummary((mZenMode.isActive() ? "ACTIVE" : "inactive") + ": " - + mZenMode.getRule().getTriggerDescription()); + setZenMode(zenMode); + setKey(zenMode.getId()); } @Override @@ -60,6 +62,16 @@ public class ZenModeListPreference extends RestrictedPreference { .setSourceMetricsCategory(SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION) .launch(); } + } + public void setZenMode(ZenMode zenMode) { + mZenMode = zenMode; + setTitle(mZenMode.getRule().getName()); + setSummary(mZenMode.getRule().getTriggerDescription()); + try { + setIcon(mZenMode.getIcon(mContext).get(200, TimeUnit.MILLISECONDS)); + } catch (Exception e) { + // no icon + } } } diff --git a/src/com/android/settings/notification/modes/ZenModesBackend.java b/src/com/android/settings/notification/modes/ZenModesBackend.java index 373d6540acc..e019ea27940 100644 --- a/src/com/android/settings/notification/modes/ZenModesBackend.java +++ b/src/com/android/settings/notification/modes/ZenModesBackend.java @@ -33,6 +33,7 @@ import com.android.settings.R; import java.time.Duration; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Map; @@ -77,7 +78,15 @@ class ZenModesBackend { isRuleActive(ruleId, currentConfig))); } - // TODO: b/331429435 - Sort modes. + modes.sort((l, r) -> { + if (l.isManualDnd()) { + return -1; + } else if (r.isManualDnd()) { + return 1; + } + return l.getRule().getName().compareTo(r.getRule().getName()); + }); + return modes; } @@ -105,10 +114,10 @@ class ZenModesBackend { .setZenPolicy(ZenAdapters.notificationPolicyToZenPolicy( mNotificationManager.getNotificationPolicy())) .setDeviceEffects(null) - .setTriggerDescription(mContext.getString(R.string.zen_mode_settings_summary)) .setManualInvocationAllowed(true) .setConfigurationActivity(null) // No further settings .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY) + .setIconResId(com.android.internal.R.drawable.ic_zen_24dp) .build(); return ZenMode.manualDndMode(manualDndRule, diff --git a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java index 53336c84be3..dbeaa2cceca 100644 --- a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java @@ -15,6 +15,7 @@ */ package com.android.settings.notification.modes; +import android.app.AutomaticZenRule; import android.app.Flags; import android.content.Context; @@ -26,6 +27,9 @@ import androidx.preference.PreferenceCategory; import com.android.settingslib.core.AbstractPreferenceController; +import java.util.HashMap; +import java.util.Map; + /** * Controller for the PreferenceCategory on the modes aggregator page ({@link ZenModesListFragment}) * containing links to each individual mode. This is a central controller that populates and updates @@ -65,16 +69,30 @@ public class ZenModesListPreferenceController extends AbstractPreferenceControll // category for each rule that exists. PreferenceCategory category = (PreferenceCategory) preference; - // TODO: b/322373473 - This is not the right way to replace these preferences; we should - // follow something similar to what - // ZenModeAutomaticRulesPreferenceController does to change rules - // only as necessary and update them. - category.removeAll(); + Map originalPreferences = new HashMap<>(); + for (int i = 0; i < category.getPreferenceCount(); i++) { + ZenModeListPreference pref = (ZenModeListPreference) category.getPreference(i); + originalPreferences.put(pref.getKey(), pref); + } + // Loop through each rule, either updating the existing rule or creating the rule's + // preference for (ZenMode mode : mBackend.getModes()) { - Preference pref = new ZenModeListPreference(mContext, mode); - category.addPreference(pref); + if (originalPreferences.containsKey(mode.getId())) { + // existing rule; update its info if it's changed since the last display + AutomaticZenRule rule = mode.getRule(); + originalPreferences.get(mode.getId()).setZenMode(mode); + } else { + // new rule; create a new ZenRulePreference & add it to the preference category + Preference pref = new ZenModeListPreference(mContext, mode); + category.addPreference(pref); + } + + originalPreferences.remove(mode.getId()); + } + // Remove preferences that no longer have a rule + for (String key : originalPreferences.keySet()) { + category.removePreferenceRecursively(key); } } - }