diff --git a/res/layout/zen_mode_type_item.xml b/res/layout/zen_mode_type_item.xml new file mode 100644 index 00000000000..841ca0066f8 --- /dev/null +++ b/res/layout/zen_mode_type_item.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index f92fd2aca84..386ece3caf4 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7927,6 +7927,19 @@ Only get notified by important people and apps + + Select activation type + + + Time + + Ex. \"9:30 – 5:00 PM\" + + + Calendar + + Ex. \"Personal calendar\" + Limit interruptions diff --git a/src/com/android/settings/notification/modes/ZenMode.java b/src/com/android/settings/notification/modes/ZenMode.java index cbe915b5bab..1040d1e0021 100644 --- a/src/com/android/settings/notification/modes/ZenMode.java +++ b/src/com/android/settings/notification/modes/ZenMode.java @@ -18,6 +18,12 @@ package com.android.settings.notification.modes; import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; +import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleEvent; +import static android.service.notification.SystemZenRules.getTriggerDescriptionForScheduleTime; +import static android.service.notification.ZenModeConfig.tryParseEventConditionId; +import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId; + +import static com.google.common.base.Preconditions.checkState; import static java.util.Objects.requireNonNull; @@ -26,7 +32,10 @@ import android.app.AutomaticZenRule; import android.app.NotificationManager; import android.content.Context; import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.service.notification.SystemZenRules; import android.service.notification.ZenDeviceEffects; +import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; import android.util.Log; @@ -204,6 +213,44 @@ class ZenMode { : new ZenDeviceEffects.Builder().build(); } + public void setCustomModeConditionId(Context context, Uri conditionId) { + checkState(SystemZenRules.PACKAGE_ANDROID.equals(mRule.getPackageName()), + "Trying to change condition of non-system-owned rule %s (to %s)", + mRule, conditionId); + + Uri oldCondition = mRule.getConditionId(); + mRule.setConditionId(conditionId); + + ZenModeConfig.ScheduleInfo scheduleInfo = tryParseScheduleConditionId(conditionId); + if (scheduleInfo != null) { + mRule.setType(AutomaticZenRule.TYPE_SCHEDULE_TIME); + mRule.setOwner(ZenModeConfig.getScheduleConditionProvider()); + mRule.setTriggerDescription( + getTriggerDescriptionForScheduleTime(context, scheduleInfo)); + return; + } + + ZenModeConfig.EventInfo eventInfo = tryParseEventConditionId(conditionId); + if (eventInfo != null) { + mRule.setType(AutomaticZenRule.TYPE_SCHEDULE_CALENDAR); + mRule.setOwner(ZenModeConfig.getEventConditionProvider()); + mRule.setTriggerDescription(getTriggerDescriptionForScheduleEvent(context, eventInfo)); + return; + } + + if (ZenModeConfig.isValidCustomManualConditionId(conditionId)) { + mRule.setType(AutomaticZenRule.TYPE_OTHER); + mRule.setOwner(ZenModeConfig.getCustomManualConditionProvider()); + mRule.setTriggerDescription(""); + return; + } + + Log.wtf(TAG, String.format( + "Changed condition of rule %s (%s -> %s) but cannot recognize which kind of " + + "condition it was!", + mRule, oldCondition, conditionId)); + } + public boolean canEditName() { return !isManualDnd(); } @@ -224,6 +271,15 @@ class ZenMode { return mIsActive; } + public boolean isSystemOwned() { + return SystemZenRules.PACKAGE_ANDROID.equals(mRule.getPackageName()); + } + + @AutomaticZenRule.Type + public int getType() { + return mRule.getType(); + } + @Override public boolean equals(@Nullable Object obj) { return obj instanceof ZenMode other diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java index 6bda5e13c97..ee497ae74df 100644 --- a/src/com/android/settings/notification/modes/ZenModeFragment.java +++ b/src/com/android/settings/notification/modes/ZenModeFragment.java @@ -52,7 +52,7 @@ public class ZenModeFragment extends ZenModeFragmentBase { prefControllers.add(new ZenModeDisplayLinkPreferenceController( context, "mode_display_settings", mBackend, mHelperBackend)); prefControllers.add(new ZenModeSetTriggerLinkPreferenceController(context, - "zen_automatic_trigger_category", mBackend)); + "zen_automatic_trigger_category", this, mBackend)); return prefControllers; } diff --git a/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java new file mode 100644 index 00000000000..14264b7a844 --- /dev/null +++ b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java @@ -0,0 +1,149 @@ +/* + * 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.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import android.app.Dialog; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.service.notification.ZenModeConfig; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AlertDialog; + +import com.android.settings.R; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.dashboard.DashboardFragment; + +import com.google.common.collect.ImmutableList; + +public class ZenModeScheduleChooserDialog extends InstrumentedDialogFragment { + + private static final String TAG = "ZenModeScheduleChooserDialog"; + + static final int OPTION_TIME = 0; + static final int OPTION_CALENDAR = 1; + + private record ScheduleOption(@StringRes int nameResId, @StringRes int exampleResId, + @DrawableRes int iconResId) {} + + private static final ImmutableList SCHEDULE_OPTIONS = ImmutableList.of( + new ScheduleOption(R.string.zen_mode_select_schedule_time, + R.string.zen_mode_select_schedule_time_example, + com.android.internal.R.drawable.ic_zen_mode_type_schedule_time), + new ScheduleOption(R.string.zen_mode_select_schedule_calendar, + R.string.zen_mode_select_schedule_calendar_example, + com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar)); + + private OnScheduleOptionListener mOptionListener; + + interface OnScheduleOptionListener { + void onScheduleSelected(Uri conditionId); + } + + @Override + public int getMetricsCategory() { + // TODO: b/332937635 - Update metrics category + return 0; + } + + static void show(DashboardFragment parent, OnScheduleOptionListener optionListener) { + ZenModeScheduleChooserDialog dialog = new ZenModeScheduleChooserDialog(); + dialog.mOptionListener = optionListener; + dialog.setTargetFragment(parent, 0); + dialog.show(parent.getParentFragmentManager(), TAG); + } + + @NonNull + @Override + public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + checkState(getContext() != null); + return new AlertDialog.Builder(getContext()) + .setTitle(R.string.zen_mode_choose_rule_type) + .setAdapter(new OptionsAdapter(getContext()), + (dialog, which) -> onScheduleTypeSelected(which)) + .setNegativeButton(R.string.cancel, null) + .create(); + } + + private static class OptionsAdapter extends ArrayAdapter { + + private final LayoutInflater mInflater; + + OptionsAdapter(@NonNull Context context) { + super(context, R.layout.zen_mode_type_item, SCHEDULE_OPTIONS); + mInflater = LayoutInflater.from(context); + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + if (convertView == null) { + convertView = mInflater.inflate(R.layout.zen_mode_type_item, parent, false); + } + // No need for holder pattern since we have only 2 items. + ImageView imageView = checkNotNull(convertView.findViewById(R.id.icon)); + TextView title = checkNotNull(convertView.findViewById(R.id.title)); + TextView subtitle = checkNotNull(convertView.findViewById(R.id.subtitle)); + + ScheduleOption option = checkNotNull(getItem(position)); + imageView.setImageResource(option.iconResId()); + title.setText(option.nameResId()); + subtitle.setText(option.exampleResId()); + + return convertView; + } + } + + private void onScheduleTypeSelected(int whichOption) { + Uri conditionId = switch (whichOption) { + case OPTION_TIME -> getDefaultScheduleTimeCondition(); + case OPTION_CALENDAR -> getDefaultScheduleCalendarCondition(); + default -> ZenModeConfig.toCustomManualConditionId(); + }; + + mOptionListener.onScheduleSelected(conditionId); + } + + private static Uri getDefaultScheduleTimeCondition() { + ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo(); + schedule.days = ZenModeConfig.ALL_DAYS; + schedule.startHour = 9; + schedule.startMinute = 30; + schedule.endHour = 17; + return ZenModeConfig.toScheduleConditionId(schedule); + } + + private static Uri getDefaultScheduleCalendarCondition() { + ZenModeConfig.EventInfo eventInfo = new ZenModeConfig.EventInfo(); + eventInfo.calendarId = null; // All calendars of the current user. + eventInfo.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO; + return ZenModeConfig.toEventConditionId(eventInfo); + } +} diff --git a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java index 28413091a37..e87907647db 100644 --- a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java @@ -16,14 +16,12 @@ package com.android.settings.notification.modes; -import android.app.Flags; import android.content.Context; import android.content.pm.PackageManager; import android.database.Cursor; import android.os.UserHandle; import android.os.UserManager; import android.provider.CalendarContract; -import android.service.notification.SystemZenRules; import android.service.notification.ZenModeConfig; import androidx.annotation.NonNull; @@ -42,7 +40,7 @@ import java.util.List; import java.util.Objects; import java.util.function.Function; -public class ZenModeSetCalendarPreferenceController extends AbstractZenModePreferenceController { +class ZenModeSetCalendarPreferenceController extends AbstractZenModePreferenceController { @VisibleForTesting protected static final String KEY_CALENDAR = "calendar"; @VisibleForTesting @@ -122,11 +120,7 @@ public class ZenModeSetCalendarPreferenceController extends AbstractZenModePrefe @VisibleForTesting protected Function updateEventMode(ZenModeConfig.EventInfo event) { return (zenMode) -> { - zenMode.getRule().setConditionId(ZenModeConfig.toEventConditionId(event)); - if (Flags.modesApi() && Flags.modesUi()) { - zenMode.getRule().setTriggerDescription( - SystemZenRules.getTriggerDescriptionForScheduleEvent(mContext, event)); - } + zenMode.setCustomModeConditionId(mContext, ZenModeConfig.toEventConditionId(event)); return zenMode; }; } diff --git a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java index a6008ccd768..3432ed5154f 100644 --- a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java @@ -16,9 +16,7 @@ package com.android.settings.notification.modes; -import android.app.Flags; import android.content.Context; -import android.service.notification.SystemZenRules; import android.service.notification.ZenModeConfig; import android.text.format.DateFormat; import android.util.ArraySet; @@ -116,16 +114,13 @@ class ZenModeSetSchedulePreferenceController extends AbstractZenModePreferenceCo @VisibleForTesting protected Function updateScheduleMode(ZenModeConfig.ScheduleInfo schedule) { return (zenMode) -> { - zenMode.getRule().setConditionId(ZenModeConfig.toScheduleConditionId(schedule)); - if (Flags.modesApi() && Flags.modesUi()) { - zenMode.getRule().setTriggerDescription( - SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, schedule)); - } + zenMode.setCustomModeConditionId(mContext, + ZenModeConfig.toScheduleConditionId(schedule)); return zenMode; }; } - private ZenModeTimePickerFragment.TimeSetter mStartSetter = (hour, minute) -> { + private final ZenModeTimePickerFragment.TimeSetter mStartSetter = (hour, minute) -> { if (!isValidTime(hour, minute)) { return; } @@ -137,7 +132,7 @@ class ZenModeSetSchedulePreferenceController extends AbstractZenModePreferenceCo saveMode(updateScheduleMode(mSchedule)); }; - private ZenModeTimePickerFragment.TimeSetter mEndSetter = (hour, minute) -> { + private final ZenModeTimePickerFragment.TimeSetter mEndSetter = (hour, minute) -> { if (!isValidTime(hour, minute)) { return; } diff --git a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java index 14d5d59a19d..fd27958db95 100644 --- a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java +++ b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.settings.notification.modes; import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR; import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME; -import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID; - import android.content.Context; -import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -29,7 +27,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import com.android.settings.R; -import com.android.settings.core.SubSettingLauncher; +import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.PrimarySwitchPreference; /** @@ -39,9 +37,13 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc @VisibleForTesting protected static final String AUTOMATIC_TRIGGER_PREF_KEY = "zen_automatic_trigger_settings"; + private final DashboardFragment mFragment; + ZenModeSetTriggerLinkPreferenceController(Context context, String key, + DashboardFragment fragment, ZenModesBackend backend) { super(context, key, backend); + mFragment = fragment; } @Override @@ -54,46 +56,52 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc // This controller is expected to govern a preference category so that it controls the // availability of the entire preference category if the mode doesn't have a way to // automatically trigger (such as manual DND). - Preference switchPref = ((PreferenceCategory) preference).findPreference( + PrimarySwitchPreference switchPref = ((PreferenceCategory) preference).findPreference( AUTOMATIC_TRIGGER_PREF_KEY); if (switchPref == null) { return; } - ((PrimarySwitchPreference) switchPref).setChecked(zenMode.getRule().isEnabled()); + switchPref.setChecked(zenMode.getRule().isEnabled()); switchPref.setOnPreferenceChangeListener(mSwitchChangeListener); - Bundle bundle = new Bundle(); - bundle.putString(MODE_ID, zenMode.getId()); + switchPref.setSummary(zenMode.getRule().getTriggerDescription()); + switchPref.setIcon(null); + switchPref.setOnPreferenceClickListener(null); + switchPref.setIntent(null); - // TODO: b/341961712 - direct preference to app-owned intent if available - switch (zenMode.getRule().getType()) { - case TYPE_SCHEDULE_TIME: - switchPref.setTitle(R.string.zen_mode_set_schedule_link); - switchPref.setSummary(zenMode.getRule().getTriggerDescription()); - switchPref.setIntent(new SubSettingLauncher(mContext) - .setDestination(ZenModeSetScheduleFragment.class.getName()) - // TODO: b/332937635 - set correct metrics category - .setSourceMetricsCategory(0) - .setArguments(bundle) - .toIntent()); - break; - case TYPE_SCHEDULE_CALENDAR: - switchPref.setTitle(R.string.zen_mode_set_calendar_link); - switchPref.setSummary(zenMode.getRule().getTriggerDescription()); - switchPref.setIntent(new SubSettingLauncher(mContext) - .setDestination(ZenModeSetCalendarFragment.class.getName()) - // TODO: b/332937635 - set correct metrics category - .setSourceMetricsCategory(0) - .setArguments(bundle) - .toIntent()); - break; - default: - // TODO: b/342156843 - change this to allow adding a trigger condition for system - // rules that don't yet have a type selected - switchPref.setTitle("not implemented"); + if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_TIME) { + switchPref.setTitle(R.string.zen_mode_set_schedule_link); + // TODO: b/332937635 - set correct metrics category + switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext, + ZenModeSetScheduleFragment.class, zenMode.getId(), 0).toIntent()); + } else if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_CALENDAR) { + switchPref.setTitle(R.string.zen_mode_set_calendar_link); + switchPref.setIcon(null); + // TODO: b/332937635 - set correct metrics category + switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext, + ZenModeSetCalendarFragment.class, zenMode.getId(), 0).toIntent()); + } else if (zenMode.isSystemOwned()) { + switchPref.setTitle(R.string.zen_mode_select_schedule); + switchPref.setIcon(R.drawable.ic_add_24dp); + switchPref.setSummary(""); + // TODO: b/342156843 - Hide the switch (needs support in SettingsLib). + switchPref.setOnPreferenceClickListener(clickedPreference -> { + ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener); + return true; + }); + } else { + // TODO: b/341961712 - direct preference to app-owned intent if available + switchPref.setTitle("not implemented"); } } + @VisibleForTesting + final ZenModeScheduleChooserDialog.OnScheduleOptionListener mOnScheduleOptionListener = + conditionId -> saveMode(mode -> { + mode.setCustomModeConditionId(mContext, conditionId); + return mode; + }); + @VisibleForTesting protected Preference.OnPreferenceChangeListener mSwitchChangeListener = (p, newValue) -> { final boolean newEnabled = (Boolean) newValue; @@ -103,5 +111,6 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc } return zenMode; }); + // TODO: b/342156843 - Do we want to jump to the corresponding schedule editing screen? }; } diff --git a/src/com/android/settings/notification/modes/ZenModesBackend.java b/src/com/android/settings/notification/modes/ZenModesBackend.java index b58e3107934..4f86778cf63 100644 --- a/src/com/android/settings/notification/modes/ZenModesBackend.java +++ b/src/com/android/settings/notification/modes/ZenModesBackend.java @@ -24,7 +24,6 @@ import android.content.Context; import android.net.Uri; import android.provider.Settings; import android.service.notification.Condition; -import android.service.notification.SystemZenRules; import android.service.notification.ZenModeConfig; import android.util.Log; @@ -194,19 +193,11 @@ class ZenModesBackend { */ @Nullable ZenMode addCustomMode(String name) { - ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo(); - schedule.days = ZenModeConfig.ALL_DAYS; - schedule.startHour = 22; - schedule.endHour = 7; - - // TODO: b/326442408 - Create as "manual" (i.e. no trigger) instead of schedule-time. AutomaticZenRule rule = new AutomaticZenRule.Builder(name, - ZenModeConfig.toScheduleConditionId(schedule)) - .setPackage(ZenModeConfig.getScheduleConditionProvider().getPackageName()) - .setType(AutomaticZenRule.TYPE_SCHEDULE_CALENDAR) - .setOwner(ZenModeConfig.getScheduleConditionProvider()) - .setTriggerDescription(SystemZenRules.getTriggerDescriptionForScheduleTime( - mContext, schedule)) + ZenModeConfig.toCustomManualConditionId()) + .setPackage(ZenModeConfig.getCustomManualConditionProvider().getPackageName()) + .setType(AutomaticZenRule.TYPE_OTHER) + .setOwner(ZenModeConfig.getCustomManualConditionProvider()) .setManualInvocationAllowed(true) .build(); diff --git a/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java b/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java index 11f3492f36d..aa66e6c5186 100644 --- a/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java +++ b/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java @@ -29,7 +29,7 @@ class ZenSubSettingLauncher { SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION); } - private static SubSettingLauncher forModeFragment(Context context, + static SubSettingLauncher forModeFragment(Context context, Class fragmentClass, String modeId, int sourceMetricsCategory) { Bundle bundle = new Bundle(); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java index 6b24fa21832..0ede058aed7 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java @@ -34,6 +34,7 @@ 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.SystemZenRules; import android.service.notification.ZenModeConfig; import androidx.preference.DropDownPreference; @@ -85,7 +86,9 @@ public class ZenModeSetCalendarPreferenceControllerTest { @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) public void updateEventMode_updatesConditionAndTriggerDescription() { ZenMode mode = new ZenMode("id", - new AutomaticZenRule.Builder("name", Uri.parse("condition")).build(), + new AutomaticZenRule.Builder("name", Uri.parse("condition")) + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .build(), true); // is active // Explicitly update preference controller with mode info first, which will also call @@ -99,6 +102,7 @@ public class ZenModeSetCalendarPreferenceControllerTest { // apply event mode updater to existing mode ZenMode out = mPrefController.updateEventMode(eventInfo).apply(mode); + assertThat(out.getRule().getOwner()).isEqualTo(ZenModeConfig.getEventConditionProvider()); assertThat(out.getRule().getConditionId()).isEqualTo( ZenModeConfig.toEventConditionId(eventInfo)); assertThat(out.getRule().getTriggerDescription()).isEqualTo("My events"); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java index 7cf327c983e..5f492b971a8 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java @@ -29,6 +29,7 @@ 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.SystemZenRules; import android.service.notification.ZenModeConfig; import android.view.ViewGroup; import android.widget.ToggleButton; @@ -81,7 +82,9 @@ public class ZenModeSetSchedulePreferenceControllerTest { @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI}) public void updateScheduleRule_updatesConditionAndTriggerDescription() { ZenMode mode = new ZenMode("id", - new AutomaticZenRule.Builder("name", Uri.parse("condition")).build(), + new AutomaticZenRule.Builder("name", Uri.parse("condition")) + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .build(), true); // is active ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo(); @@ -93,6 +96,8 @@ public class ZenModeSetSchedulePreferenceControllerTest { assertThat(out.getRule().getConditionId()) .isEqualTo(ZenModeConfig.toScheduleConditionId(scheduleInfo)); assertThat(out.getRule().getTriggerDescription()).isNotEmpty(); + assertThat(out.getRule().getOwner()).isEqualTo( + ZenModeConfig.getScheduleConditionProvider()); } @Test diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java index 91de4ea8348..ff4d4a3c94c 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java @@ -16,6 +16,7 @@ package com.android.settings.notification.modes; +import static android.app.AutomaticZenRule.TYPE_OTHER; import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR; import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME; import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; @@ -31,10 +32,10 @@ import static org.mockito.Mockito.when; import android.app.AutomaticZenRule; import android.app.Flags; import android.content.Context; -import android.content.Intent; import android.net.Uri; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; +import android.service.notification.SystemZenRules; import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; @@ -43,6 +44,7 @@ import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.PrimarySwitchPreference; import org.junit.Before; @@ -57,6 +59,7 @@ import org.robolectric.RobolectricTestRunner; import java.util.Calendar; @RunWith(RobolectricTestRunner.class) +@EnableFlags(Flags.FLAG_MODES_UI) public class ZenModeSetTriggerLinkPreferenceControllerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @@ -65,10 +68,13 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest { private ZenModesBackend mBackend; private Context mContext; + private PrimarySwitchPreference mPreference; + @Mock private PreferenceCategory mPrefCategory; @Mock - private PrimarySwitchPreference mPreference; + private DashboardFragment mFragment; + private ZenModeSetTriggerLinkPreferenceController mPrefController; @Before @@ -77,12 +83,12 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest { mContext = ApplicationProvider.getApplicationContext(); mPrefController = new ZenModeSetTriggerLinkPreferenceController(mContext, - "zen_automatic_trigger_category", mBackend); + "zen_automatic_trigger_category", mFragment, mBackend); + mPreference = new PrimarySwitchPreference(mContext); when(mPrefCategory.findPreference(AUTOMATIC_TRIGGER_PREF_KEY)).thenReturn(mPreference); } @Test - @EnableFlags(Flags.FLAG_MODES_UI) public void testIsAvailable() { // should not be available for manual DND ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb", @@ -117,12 +123,12 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest { // Update preference controller with a zen mode that is not enabled mPrefController.updateZenMode(mPrefCategory, zenMode); - verify(mPreference).setChecked(false); + assertThat(mPreference.getCheckedState()).isFalse(); // Now with the rule enabled zenMode.getRule().setEnabled(true); mPrefController.updateZenMode(mPrefCategory, zenMode); - verify(mPreference).setChecked(true); + assertThat(mPreference.getCheckedState()).isTrue(); } @Test @@ -154,21 +160,24 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest { eventInfo.calName = "My events"; ZenMode mode = new ZenMode("id", new AutomaticZenRule.Builder("name", ZenModeConfig.toEventConditionId(eventInfo)) + .setPackage(SystemZenRules.PACKAGE_ANDROID) .setType(TYPE_SCHEDULE_CALENDAR) .setTriggerDescription("My events") .build(), true); // is active mPrefController.updateZenMode(mPrefCategory, mode); - verify(mPreference).setTitle(R.string.zen_mode_set_calendar_link); - verify(mPreference).setSummary(mode.getRule().getTriggerDescription()); + assertThat(mPreference.getTitle()).isNotNull(); + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.zen_mode_set_calendar_link)); + assertThat(mPreference.getSummary()).isNotNull(); + assertThat(mPreference.getSummary().toString()).isEqualTo( + mode.getRule().getTriggerDescription()); + assertThat(mPreference.getIcon()).isNull(); - ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); - verify(mPreference).setIntent(captor.capture()); // Destination as written into the intent by SubSettingLauncher - assertThat( - captor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( - ZenModeSetCalendarFragment.class.getName()); + assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(ZenModeSetCalendarFragment.class.getName()); } @Test @@ -179,20 +188,75 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest { scheduleInfo.endHour = 15; ZenMode mode = new ZenMode("id", new AutomaticZenRule.Builder("name", ZenModeConfig.toScheduleConditionId(scheduleInfo)) + .setPackage(SystemZenRules.PACKAGE_ANDROID) .setType(TYPE_SCHEDULE_TIME) .setTriggerDescription("some schedule") .build(), true); // is active mPrefController.updateZenMode(mPrefCategory, mode); - verify(mPreference).setTitle(R.string.zen_mode_set_schedule_link); - verify(mPreference).setSummary(mode.getRule().getTriggerDescription()); + assertThat(mPreference.getTitle()).isNotNull(); + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.zen_mode_set_schedule_link)); + assertThat(mPreference.getSummary()).isNotNull(); + assertThat(mPreference.getSummary().toString()).isEqualTo( + mode.getRule().getTriggerDescription()); + assertThat(mPreference.getIcon()).isNull(); - ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); - verify(mPreference).setIntent(captor.capture()); // Destination as written into the intent by SubSettingLauncher - assertThat( - captor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( - ZenModeSetScheduleFragment.class.getName()); + assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(ZenModeSetScheduleFragment.class.getName()); + } + + @Test + public void testRuleLink_manual() { + ZenMode mode = new ZenMode("id", new AutomaticZenRule.Builder("name", + ZenModeConfig.toCustomManualConditionId()) + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .setType(TYPE_OTHER) + .setTriggerDescription("Will not be shown") + .build(), + true); // is active + mPrefController.updateZenMode(mPrefCategory, mode); + + assertThat(mPreference.getTitle()).isNotNull(); + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.zen_mode_select_schedule)); + assertThat(mPreference.getIcon()).isNotNull(); + assertThat(mPreference.getSummary()).isNotNull(); + assertThat(mPreference.getSummary().toString()).isEqualTo(""); + + // Set up a click listener to open the dialog. + assertThat(mPreference.getOnPreferenceClickListener()).isNotNull(); + } + + @Test + public void onScheduleChosen_updatesMode() { + ZenMode originalMode = new ZenMode("id", + new AutomaticZenRule.Builder("name", ZenModeConfig.toCustomManualConditionId()) + .setPackage(SystemZenRules.PACKAGE_ANDROID) + .setType(TYPE_OTHER) + .setTriggerDescription("") + .build(), + false); + mPrefController.updateZenMode(mPrefCategory, originalMode); + + ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo(); + scheduleInfo.days = new int[] { Calendar.MONDAY }; + scheduleInfo.startHour = 12; + scheduleInfo.endHour = 15; + Uri scheduleUri = ZenModeConfig.toScheduleConditionId(scheduleInfo); + + mPrefController.mOnScheduleOptionListener.onScheduleSelected(scheduleUri); + + // verify the backend got asked to update the mode to be schedule-based. + ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class); + verify(mBackend).updateMode(captor.capture()); + ZenMode updatedMode = captor.getValue(); + assertThat(updatedMode.getType()).isEqualTo(TYPE_SCHEDULE_TIME); + assertThat(updatedMode.getRule().getConditionId()).isEqualTo(scheduleUri); + assertThat(updatedMode.getRule().getTriggerDescription()).isNotEmpty(); + assertThat(updatedMode.getRule().getOwner()).isEqualTo( + ZenModeConfig.getScheduleConditionProvider()); } }