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
192 lines
8.2 KiB
Java
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();
|
|
}
|
|
}
|