Files
app_Settings/src/com/android/settings/notification/zen/ZenRuleScheduleHelper.java
Yuri Lin a91e2daea7 Change zen schedules page to use switches.
Also add clearer summaries for schedule and calendar events (rather than just "Off" and "On"): for schedules, list the days & times for which the schedule is active, and for events, the calendar whose events it triggers on.

Bug: 190180868
Bug: 215564123
Test: manual for switches, ZenRuleScheduleHelperTest for descriptions

Change-Id: I3ad579503adae0a66dfa3093b4e3df77db0ede31
2022-01-26 11:21:53 -05:00

192 lines
8.2 KiB
Java

/*
* Copyright (C) 2022 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.zen;
import android.content.Context;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.text.format.DateFormat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
/**
* Helper class for shared functionality regarding descriptions of custom zen rule schedules.
*/
public class ZenRuleScheduleHelper {
// per-instance to ensure we're always using the current locale
private SimpleDateFormat mDayFormat;
// Default constructor, which will use the current locale.
public ZenRuleScheduleHelper() {
mDayFormat = new SimpleDateFormat("EEE");
}
// Constructor for tests to provide an explicit locale
@VisibleForTesting
public ZenRuleScheduleHelper(Locale locale) {
mDayFormat = new SimpleDateFormat("EEE", locale);
}
/**
* Returns an ordered, comma-separated list of the days that a schedule applies, or null if no
* days.
*/
public String getDaysDescription(Context context, ScheduleInfo schedule) {
// Compute an ordered, delimited list of day names based on the persisted user config.
final int[] days = schedule.days;
if (days != null && days.length > 0) {
final StringBuilder sb = new StringBuilder();
final Calendar c = Calendar.getInstance();
int[] daysOfWeek = ZenModeScheduleDaysSelection.getDaysOfWeekForLocale(c);
for (int i = 0; i < daysOfWeek.length; i++) {
final int day = daysOfWeek[i];
for (int j = 0; j < days.length; j++) {
if (day == days[j]) {
c.set(Calendar.DAY_OF_WEEK, day);
if (sb.length() > 0) {
sb.append(context.getString(R.string.summary_divider_text));
}
sb.append(mDayFormat.format(c.getTime()));
break;
}
}
}
if (sb.length() > 0) {
return sb.toString();
}
}
return null;
}
/**
* Returns an ordered summarized list of the days on which this schedule applies, with
* adjacent days grouped together ("Sun-Wed" instead of "Sun,Mon,Tue,Wed").
*/
public String getShortDaysSummary(Context context, ScheduleInfo schedule) {
// Compute a list of days with contiguous days grouped together, for example: "Sun-Thu" or
// "Sun-Mon,Wed,Fri"
final int[] days = schedule.days;
if (days != null && days.length > 0) {
final StringBuilder sb = new StringBuilder();
final Calendar cStart = Calendar.getInstance();
final Calendar cEnd = Calendar.getInstance();
int[] daysOfWeek = ZenModeScheduleDaysSelection.getDaysOfWeekForLocale(cStart);
// the i for loop goes through days in order as determined by locale. as we walk through
// the days of the week, keep track of "start" and "last seen" as indicators for
// what's contiguous, and initialize them to something not near actual indices
int startDay = Integer.MIN_VALUE;
int lastSeenDay = Integer.MIN_VALUE;
for (int i = 0; i < daysOfWeek.length; i++) {
final int day = daysOfWeek[i];
// by default, output if this day is *not* included in the schedule, and thus
// ends a previously existing block. if this day is included in the schedule
// after all (as will be determined in the inner for loop), then output will be set
// to false.
boolean output = (i == lastSeenDay + 1);
for (int j = 0; j < days.length; j++) {
if (day == days[j]) {
// match for this day in the schedule (indicated by counter i)
if (i == lastSeenDay + 1) {
// contiguous to the block we're walking through right now, record it
// (specifically, i, the day index) and move on to the next day
lastSeenDay = i;
output = false;
} else {
// it's a match, but not 1 past the last match, we are starting a new
// block
startDay = i;
lastSeenDay = i;
}
// if there is a match on the last day, also make sure to output at the end
// of this loop, and mark the day as the last day we'll have seen in the
// scheduled days.
if (i == daysOfWeek.length - 1) {
output = true;
}
break;
}
}
// output in either of 2 cases: this day is not a match, so has ended any previous
// block, or this day *is* a match but is the last day of the week, so we need to
// summarize
if (output) {
// either describe just the single day if startDay == lastSeenDay, or
// output "startDay - lastSeenDay" as a group
if (sb.length() > 0) {
sb.append(context.getString(R.string.summary_divider_text));
}
if (startDay == lastSeenDay) {
// last group was only one day
cStart.set(Calendar.DAY_OF_WEEK, daysOfWeek[startDay]);
sb.append(mDayFormat.format(cStart.getTime()));
} else {
// last group was a contiguous group of days, so group them together
cStart.set(Calendar.DAY_OF_WEEK, daysOfWeek[startDay]);
cEnd.set(Calendar.DAY_OF_WEEK, daysOfWeek[lastSeenDay]);
sb.append(context.getString(R.string.summary_range_symbol_combination,
mDayFormat.format(cStart.getTime()),
mDayFormat.format(cEnd.getTime())));
}
}
}
if (sb.length() > 0) {
return sb.toString();
}
}
return null;
}
/**
* Convenience method for representing the specified time in string format.
*/
private String timeString(Context context, int hour, int minute) {
final Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.MINUTE, minute);
return DateFormat.getTimeFormat(context).format(c.getTime());
}
/**
* Combination description for a zen rule schedule including both day summary and time bounds.
*/
public String getDaysAndTimeSummary(Context context, ScheduleInfo schedule) {
final StringBuilder sb = new StringBuilder();
String daysSummary = getShortDaysSummary(context, schedule);
if (daysSummary == null) {
// no use outputting times without dates
return null;
}
sb.append(daysSummary);
sb.append(context.getString(R.string.summary_divider_text));
sb.append(context.getString(R.string.summary_range_symbol_combination,
timeString(context, schedule.startHour, schedule.startMinute),
timeString(context, schedule.endHour, schedule.endMinute)));
return sb.toString();
}
}