Support adding an automatic schedule to previously-manual system-owned modes
Bug: 342156843 Bug: 326442408 Flag: android.app.modes_ui Test: atest com.android.settings.notification.modes Change-Id: Ib7d15b8fc949fa73015537f03a882ef7eb6b4bcd
This commit is contained in:
62
res/layout/zen_mode_type_item.xml
Normal file
62
res/layout/zen_mode_type_item.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignStart="@id/title"
|
||||
android:layout_below="@id/title"
|
||||
android:maxLines="2"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
@@ -7927,6 +7927,19 @@
|
||||
<!-- Zen Modes: Summary for the Do not Disturb option and associated settings page. [CHAR LIMIT=240]-->
|
||||
<string name="zen_mode_settings_summary">Only get notified by important people and apps</string>
|
||||
|
||||
<!-- Zen Modes: Option to add an automatic schedule for a mode. [CHAR_LIMIT=40] -->
|
||||
<string name="zen_mode_select_schedule">Select activation type</string>
|
||||
|
||||
<!-- Zen Modes: Option to choose a time-based schedule for a mode. [CHAR_LIMIT=40] -->
|
||||
<string name="zen_mode_select_schedule_time">Time</string>
|
||||
<!-- Zen Modes: Example text for the option to choose a time-based schedule for a mode. [CHAR_LIMIT=60] -->
|
||||
<string name="zen_mode_select_schedule_time_example">Ex. \"9:30 – 5:00 PM\"</string>
|
||||
|
||||
<!-- Zen Modes: Option to choose a calendar-events-based schedule for a mode. [CHAR_LIMIT=40] -->
|
||||
<string name="zen_mode_select_schedule_calendar">Calendar</string>
|
||||
<!-- Zen Modes: Example text for the option to choose a calendar-events-based schedule for a mode. [CHAR_LIMIT=60] -->
|
||||
<string name="zen_mode_select_schedule_calendar_example">Ex. \"Personal calendar\"</string>
|
||||
|
||||
<!-- Subtitle for the Do not Disturb slice. [CHAR LIMIT=50]-->
|
||||
<string name="zen_mode_slice_subtitle">Limit interruptions</string>
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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<ScheduleOption> 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<ScheduleOption> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -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<ZenMode, ZenMode> 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;
|
||||
};
|
||||
}
|
||||
|
@@ -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<ZenMode, ZenMode> 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;
|
||||
}
|
||||
|
@@ -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?
|
||||
};
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -29,7 +29,7 @@ class ZenSubSettingLauncher {
|
||||
SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION);
|
||||
}
|
||||
|
||||
private static SubSettingLauncher forModeFragment(Context context,
|
||||
static SubSettingLauncher forModeFragment(Context context,
|
||||
Class<? extends ZenModeFragmentBase> fragmentClass, String modeId,
|
||||
int sourceMetricsCategory) {
|
||||
Bundle bundle = new Bundle();
|
||||
|
@@ -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");
|
||||
|
@@ -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
|
||||
|
@@ -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<Intent> 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<Intent> 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<ZenMode> 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());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user