An update on Downtime.
The update is that Downtime is obsolete. Replaced by the
ability to define multiple named schedule calendars.
- Make changes to ZenModeConfig to properly model manual
and automatic rules.
- Refactor the zen mode helper (and supporting classes) to
properly handle / report multiple claims on zen mode.
The "manual" rule (specified by the user in the UI) vs
one or more automatic rules.
- Automatic rules are still backed by condition providers,
but the layering is now cleaner. ConditionProviders is now
completely generic, has no ties to zen mode.
- Specifically, the new layering for zen mode (below noman) is:
ZenModeHelper: Source of truth for zen state
ZenModeFiltering: Subhelper dedicated to filtering rules.
ZenModeConditions: Subhelper dedicated to managing automatic rules.
ConditionProviders: Underlying engine for reporting named boolean state.
- Migration story for users with existing downtime config, migrated
to a single new calendar named downtime.
- For users with no existing downtime, two default calendars are created
for weeknights + weekends (icu4j for all locales will be done in a followup).
- Remove obsolete DowntimeConditionProvider/NextAlarmConditionProvider and tracking.
- Clean up obsolete resources.
- Add common zen summary description string computation.
- Add proper noman wrappers for the new model.
- Change the semantics of the global zen setting. It is now read-only. Setters
must call noman, added a "reason" to all calls for better attribution.
- Update zenmodepanel + volumedialog to the new model.
- Display the one or more automatic rules in the new zen footer summary.
- "Snooze" the automatic rules when the user explicitly turns zen off.
Bug: 20064962
Change-Id: Idd9deb865a6035ad0cfae660198dccb517e6d7cc
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 33262b3..e2230da 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -76,12 +76,10 @@
boolean matchesCallFilter(in Bundle extras);
boolean isSystemConditionProviderEnabled(String path);
+ int getZenMode();
ZenModeConfig getZenModeConfig();
- boolean setZenModeConfig(in ZenModeConfig config);
- oneway void setZenMode(int mode);
+ boolean setZenModeConfig(in ZenModeConfig config, String reason);
+ oneway void setZenMode(int mode, in Uri conditionId, String reason);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
- oneway void setZenModeCondition(in Condition condition);
- oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
- Condition[] getAutomaticZenModeConditions();
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 479327d..fa61e18 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@
import android.app.Notification.Builder;
import android.content.ComponentName;
import android.content.Context;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -27,7 +28,7 @@
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.UserHandle;
-import android.service.notification.Condition;
+import android.provider.Settings.Global;
import android.service.notification.IConditionListener;
import android.service.notification.ZenModeConfig;
import android.util.Log;
@@ -282,10 +283,10 @@
/**
* @hide
*/
- public void setZenMode(int mode) {
+ public void setZenMode(int mode, Uri conditionId, String reason) {
INotificationManager service = getService();
try {
- service.setZenMode(mode);
+ service.setZenMode(mode, conditionId, reason);
} catch (RemoteException e) {
}
}
@@ -293,6 +294,18 @@
/**
* @hide
*/
+ public boolean setZenModeConfig(ZenModeConfig config, String reason) {
+ INotificationManager service = getService();
+ try {
+ return service.setZenModeConfig(config, reason);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @hide
+ */
public void requestZenModeConditions(IConditionListener listener, int relevance) {
INotificationManager service = getService();
try {
@@ -304,24 +317,22 @@
/**
* @hide
*/
- public void setZenModeCondition(Condition exitCondition) {
+ public int getZenMode() {
INotificationManager service = getService();
try {
- service.setZenModeCondition(exitCondition);
+ return service.getZenMode();
} catch (RemoteException e) {
}
+ return Global.ZEN_MODE_OFF;
}
/**
* @hide
*/
- public Condition getZenModeCondition() {
+ public ZenModeConfig getZenModeConfig() {
INotificationManager service = getService();
try {
- final ZenModeConfig config = service.getZenModeConfig();
- if (config != null) {
- return config.exitCondition;
- }
+ return service.getZenModeConfig();
} catch (RemoteException e) {
}
return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5ee8fb3..3087e1d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -880,6 +880,15 @@
"android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
/**
+ * Activity Action: Show Zen Mode schedule rule configuration settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS
+ = "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
+
+ /**
* Activity Action: Show the regulatory information screen for the device.
* <p>
* In some cases, a matching Activity may not exist, so ensure you safeguard
@@ -7218,6 +7227,18 @@
return "ZEN_MODE_OFF";
}
+ /** @hide */ public static boolean isValidZenMode(int value) {
+ switch (value) {
+ case Global.ZEN_MODE_OFF:
+ case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+ case Global.ZEN_MODE_ALARMS:
+ case Global.ZEN_MODE_NO_INTERRUPTIONS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/**
* Opaque value, changes when persisted zen mode configuration changes.
*
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 2702457..5aaf2e7 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -22,22 +22,25 @@
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.provider.Settings.Global;
import android.text.TextUtils;
import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.R;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import java.util.Objects;
-
-import com.android.internal.R;
+import java.util.UUID;
/**
* Persisted configuration for zen mode.
@@ -47,10 +50,6 @@
public class ZenModeConfig implements Parcelable {
private static String TAG = "ZenModeConfig";
- public static final String SLEEP_MODE_NIGHTS = "nights";
- public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
- public static final String SLEEP_MODE_DAYS_PREFIX = "days:";
-
public static final int SOURCE_ANYONE = 0;
public static final int SOURCE_CONTACT = 1;
public static final int SOURCE_STAR = 2;
@@ -60,6 +59,7 @@
Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY };
public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
Calendar.WEDNESDAY, Calendar.THURSDAY };
+ public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY };
public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
private static final int SECONDS_MS = 1000;
@@ -69,7 +69,7 @@
private static final boolean DEFAULT_ALLOW_REMINDERS = true;
private static final boolean DEFAULT_ALLOW_EVENTS = true;
- private static final int XML_VERSION = 1;
+ private static final int XML_VERSION = 2;
private static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
private static final String ALLOW_TAG = "allow";
@@ -78,14 +78,6 @@
private static final String ALLOW_ATT_FROM = "from";
private static final String ALLOW_ATT_REMINDERS = "reminders";
private static final String ALLOW_ATT_EVENTS = "events";
- private static final String SLEEP_TAG = "sleep";
- private static final String SLEEP_ATT_MODE = "mode";
- private static final String SLEEP_ATT_NONE = "none";
-
- private static final String SLEEP_ATT_START_HR = "startHour";
- private static final String SLEEP_ATT_START_MIN = "startMin";
- private static final String SLEEP_ATT_END_HR = "endHour";
- private static final String SLEEP_ATT_END_MIN = "endMin";
private static final String CONDITION_TAG = "condition";
private static final String CONDITION_ATT_COMPONENT = "component";
@@ -97,8 +89,16 @@
private static final String CONDITION_ATT_STATE = "state";
private static final String CONDITION_ATT_FLAGS = "flags";
- private static final String EXIT_CONDITION_TAG = "exitCondition";
- private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
+ private static final String MANUAL_TAG = "manual";
+ private static final String AUTOMATIC_TAG = "automatic";
+
+ private static final String RULE_ATT_ID = "id";
+ private static final String RULE_ATT_ENABLED = "enabled";
+ private static final String RULE_ATT_SNOOZING = "snoozing";
+ private static final String RULE_ATT_NAME = "name";
+ private static final String RULE_ATT_COMPONENT = "component";
+ private static final String RULE_ATT_ZEN = "zen";
+ private static final String RULE_ATT_CONDITION_ID = "conditionId";
public boolean allowCalls;
public boolean allowMessages;
@@ -106,16 +106,8 @@
public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
public int allowFrom = SOURCE_ANYONE;
- public String sleepMode;
- public int sleepStartHour; // 0-23
- public int sleepStartMinute; // 0-59
- public int sleepEndHour;
- public int sleepEndMinute;
- public boolean sleepNone; // false = priority, true = none
- public ComponentName[] conditionComponents;
- public Uri[] conditionIds;
- public Condition exitCondition;
- public ComponentName exitConditionComponent;
+ public ZenRule manualRule;
+ public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
public ZenModeConfig() { }
@@ -124,27 +116,18 @@
allowMessages = source.readInt() == 1;
allowReminders = source.readInt() == 1;
allowEvents = source.readInt() == 1;
- if (source.readInt() == 1) {
- sleepMode = source.readString();
- }
- sleepStartHour = source.readInt();
- sleepStartMinute = source.readInt();
- sleepEndHour = source.readInt();
- sleepEndMinute = source.readInt();
- sleepNone = source.readInt() == 1;
- int len = source.readInt();
- if (len > 0) {
- conditionComponents = new ComponentName[len];
- source.readTypedArray(conditionComponents, ComponentName.CREATOR);
- }
- len = source.readInt();
- if (len > 0) {
- conditionIds = new Uri[len];
- source.readTypedArray(conditionIds, Uri.CREATOR);
- }
allowFrom = source.readInt();
- exitCondition = source.readParcelable(null);
- exitConditionComponent = source.readParcelable(null);
+ manualRule = source.readParcelable(null);
+ final int len = source.readInt();
+ if (len > 0) {
+ final String[] ids = new String[len];
+ final ZenRule[] rules = new ZenRule[len];
+ source.readStringArray(ids);
+ source.readTypedArray(rules, ZenRule.CREATOR);
+ for (int i = 0; i < len; i++) {
+ automaticRules.put(ids[i], rules[i]);
+ }
+ }
}
@Override
@@ -153,32 +136,22 @@
dest.writeInt(allowMessages ? 1 : 0);
dest.writeInt(allowReminders ? 1 : 0);
dest.writeInt(allowEvents ? 1 : 0);
- if (sleepMode != null) {
- dest.writeInt(1);
- dest.writeString(sleepMode);
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(sleepStartHour);
- dest.writeInt(sleepStartMinute);
- dest.writeInt(sleepEndHour);
- dest.writeInt(sleepEndMinute);
- dest.writeInt(sleepNone ? 1 : 0);
- if (conditionComponents != null && conditionComponents.length > 0) {
- dest.writeInt(conditionComponents.length);
- dest.writeTypedArray(conditionComponents, 0);
- } else {
- dest.writeInt(0);
- }
- if (conditionIds != null && conditionIds.length > 0) {
- dest.writeInt(conditionIds.length);
- dest.writeTypedArray(conditionIds, 0);
- } else {
- dest.writeInt(0);
- }
dest.writeInt(allowFrom);
- dest.writeParcelable(exitCondition, 0);
- dest.writeParcelable(exitConditionComponent, 0);
+ dest.writeParcelable(manualRule, 0);
+ if (!automaticRules.isEmpty()) {
+ final int len = automaticRules.size();
+ final String[] ids = new String[len];
+ final ZenRule[] rules = new ZenRule[len];
+ for (int i = 0; i < len; i++) {
+ ids[i] = automaticRules.keyAt(i);
+ rules[i] = automaticRules.valueAt(i);
+ }
+ dest.writeInt(len);
+ dest.writeStringArray(ids);
+ dest.writeTypedArray(rules, 0);
+ } else {
+ dest.writeInt(0);
+ }
}
@Override
@@ -189,19 +162,38 @@
.append(",allowFrom=").append(sourceToString(allowFrom))
.append(",allowReminders=").append(allowReminders)
.append(",allowEvents=").append(allowEvents)
- .append(",sleepMode=").append(sleepMode)
- .append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
- .append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
- .append(",sleepNone=").append(sleepNone)
- .append(",conditionComponents=")
- .append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
- .append(",conditionIds=")
- .append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
- .append(",exitCondition=").append(exitCondition)
- .append(",exitConditionComponent=").append(exitConditionComponent)
+ .append(",automaticRules=").append(automaticRules)
+ .append(",manualRule=").append(manualRule)
.append(']').toString();
}
+ public boolean isValid() {
+ if (!isValidManualRule(manualRule)) return false;
+ final int N = automaticRules.size();
+ for (int i = 0; i < N; i++) {
+ if (!isValidAutomaticRule(automaticRules.valueAt(i))) return false;
+ }
+ return true;
+ }
+
+ private static boolean isValidManualRule(ZenRule rule) {
+ return rule == null || Global.isValidZenMode(rule.zenMode) && sameCondition(rule);
+ }
+
+ private static boolean isValidAutomaticRule(ZenRule rule) {
+ return rule != null && !TextUtils.isEmpty(rule.name) && Global.isValidZenMode(rule.zenMode)
+ && rule.conditionId != null && sameCondition(rule);
+ }
+
+ private static boolean sameCondition(ZenRule rule) {
+ if (rule == null) return false;
+ if (rule.conditionId == null) {
+ return rule.condition == null;
+ } else {
+ return rule.condition == null || rule.conditionId.equals(rule.condition.id);
+ }
+ }
+
public static String sourceToString(int source) {
switch (source) {
case SOURCE_ANYONE:
@@ -225,45 +217,29 @@
&& other.allowFrom == allowFrom
&& other.allowReminders == allowReminders
&& other.allowEvents == allowEvents
- && Objects.equals(other.sleepMode, sleepMode)
- && other.sleepNone == sleepNone
- && other.sleepStartHour == sleepStartHour
- && other.sleepStartMinute == sleepStartMinute
- && other.sleepEndHour == sleepEndHour
- && other.sleepEndMinute == sleepEndMinute
- && Objects.deepEquals(other.conditionComponents, conditionComponents)
- && Objects.deepEquals(other.conditionIds, conditionIds)
- && Objects.equals(other.exitCondition, exitCondition)
- && Objects.equals(other.exitConditionComponent, exitConditionComponent);
+ && Objects.equals(other.automaticRules, automaticRules)
+ && Objects.equals(other.manualRule, manualRule);
}
@Override
public int hashCode() {
return Objects.hash(allowCalls, allowMessages, allowFrom, allowReminders, allowEvents,
- sleepMode, sleepNone, sleepStartHour, sleepStartMinute, sleepEndHour,
- sleepEndMinute, Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
- exitCondition, exitConditionComponent);
+ automaticRules, manualRule);
}
- public boolean isValid() {
- return isValidHour(sleepStartHour) && isValidMinute(sleepStartMinute)
- && isValidHour(sleepEndHour) && isValidMinute(sleepEndMinute)
- && isValidSleepMode(sleepMode);
+ private static String toDayList(int[] days) {
+ if (days == null || days.length == 0) return "";
+ final StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < days.length; i++) {
+ if (i > 0) sb.append('.');
+ sb.append(days[i]);
+ }
+ return sb.toString();
}
- public static boolean isValidSleepMode(String sleepMode) {
- return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
- || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null;
- }
-
- public static int[] tryParseDays(String sleepMode) {
- if (sleepMode == null) return null;
- sleepMode = sleepMode.trim();
- if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS;
- if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS;
- if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null;
- if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null;
- final String[] tokens = sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()).split(",");
+ private static int[] tryParseDayList(String dayList, String sep) {
+ if (dayList == null) return null;
+ final String[] tokens = dayList.split(sep);
if (tokens.length == 0) return null;
final int[] rt = new int[tokens.length];
for (int i = 0; i < tokens.length; i++) {
@@ -283,7 +259,7 @@
}
}
- public static ZenModeConfig readXml(XmlPullParser parser)
+ public static ZenModeConfig readXml(XmlPullParser parser, Migration migration)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
if (type != XmlPullParser.START_TAG) return null;
@@ -291,16 +267,13 @@
if (!ZEN_TAG.equals(tag)) return null;
final ZenModeConfig rt = new ZenModeConfig();
final int version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
- final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
- final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
+ if (version == 1) {
+ final XmlV1 v1 = XmlV1.readXml(parser);
+ return migration.migrate(v1);
+ }
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
tag = parser.getName();
if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
- if (!conditionComponents.isEmpty()) {
- rt.conditionComponents = conditionComponents
- .toArray(new ComponentName[conditionComponents.size()]);
- rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
- }
return rt;
}
if (type == XmlPullParser.START_TAG) {
@@ -314,31 +287,13 @@
if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) {
throw new IndexOutOfBoundsException("bad source in config:" + rt.allowFrom);
}
- } else if (SLEEP_TAG.equals(tag)) {
- final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
- rt.sleepMode = isValidSleepMode(mode)? mode : null;
- rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
- final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
- final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
- final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
- final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
- rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
- rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
- rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
- rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
- } else if (CONDITION_TAG.equals(tag)) {
- final ComponentName component =
- safeComponentName(parser, CONDITION_ATT_COMPONENT);
- final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
- if (component != null && conditionId != null) {
- conditionComponents.add(component);
- conditionIds.add(conditionId);
- }
- } else if (EXIT_CONDITION_TAG.equals(tag)) {
- rt.exitCondition = readConditionXml(parser);
- if (rt.exitCondition != null) {
- rt.exitConditionComponent =
- safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ } else if (MANUAL_TAG.equals(tag)) {
+ rt.manualRule = readRuleXml(parser);
+ } else if (AUTOMATIC_TAG.equals(tag)) {
+ final String id = parser.getAttributeValue(null, RULE_ATT_ID);
+ final ZenRule automaticRule = readRuleXml(parser);
+ if (id != null && automaticRule != null) {
+ rt.automaticRules.put(id, automaticRule);
}
}
}
@@ -358,39 +313,61 @@
out.attribute(null, ALLOW_ATT_FROM, Integer.toString(allowFrom));
out.endTag(null, ALLOW_TAG);
- out.startTag(null, SLEEP_TAG);
- if (sleepMode != null) {
- out.attribute(null, SLEEP_ATT_MODE, sleepMode);
+ if (manualRule != null) {
+ out.startTag(null, MANUAL_TAG);
+ writeRuleXml(manualRule, out);
+ out.endTag(null, MANUAL_TAG);
}
- out.attribute(null, SLEEP_ATT_NONE, Boolean.toString(sleepNone));
- out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour));
- out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute));
- out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour));
- out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
- out.endTag(null, SLEEP_TAG);
-
- if (conditionComponents != null && conditionIds != null
- && conditionComponents.length == conditionIds.length) {
- for (int i = 0; i < conditionComponents.length; i++) {
- out.startTag(null, CONDITION_TAG);
- out.attribute(null, CONDITION_ATT_COMPONENT,
- conditionComponents[i].flattenToString());
- out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString());
- out.endTag(null, CONDITION_TAG);
- }
- }
- if (exitCondition != null && exitConditionComponent != null) {
- out.startTag(null, EXIT_CONDITION_TAG);
- out.attribute(null, EXIT_CONDITION_ATT_COMPONENT,
- exitConditionComponent.flattenToString());
- writeConditionXml(exitCondition, out);
- out.endTag(null, EXIT_CONDITION_TAG);
+ final int N = automaticRules.size();
+ for (int i = 0; i < N; i++) {
+ final String id = automaticRules.keyAt(i);
+ final ZenRule automaticRule = automaticRules.valueAt(i);
+ out.startTag(null, AUTOMATIC_TAG);
+ out.attribute(null, RULE_ATT_ID, id);
+ writeRuleXml(automaticRule, out);
+ out.endTag(null, AUTOMATIC_TAG);
}
out.endTag(null, ZEN_TAG);
}
+ public static ZenRule readRuleXml(XmlPullParser parser) {
+ final ZenRule rt = new ZenRule();
+ rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
+ rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false);
+ rt.name = parser.getAttributeValue(null, RULE_ATT_NAME);
+ final String zen = parser.getAttributeValue(null, RULE_ATT_ZEN);
+ rt.zenMode = tryParseZenMode(zen, -1);
+ if (rt.zenMode == -1) {
+ Slog.w(TAG, "Bad zen mode in rule xml:" + zen);
+ return null;
+ }
+ rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
+ rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
+ rt.condition = readConditionXml(parser);
+ return rt.condition != null ? rt : null;
+ }
+
+ public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
+ out.attribute(null, RULE_ATT_ENABLED, Boolean.toString(rule.enabled));
+ out.attribute(null, RULE_ATT_SNOOZING, Boolean.toString(rule.snoozing));
+ if (rule.name != null) {
+ out.attribute(null, RULE_ATT_NAME, rule.name);
+ }
+ out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode));
+ if (rule.component != null) {
+ out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
+ }
+ if (rule.conditionId != null) {
+ out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
+ }
+ if (rule.condition != null) {
+ writeConditionXml(rule.condition, out);
+ }
+ }
+
public static Condition readConditionXml(XmlPullParser parser) {
final Uri id = safeUri(parser, CONDITION_ATT_ID);
+ if (id == null) return null;
final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
final String line1 = parser.getAttributeValue(null, CONDITION_ATT_LINE1);
final String line2 = parser.getAttributeValue(null, CONDITION_ATT_LINE2);
@@ -446,6 +423,14 @@
return Uri.parse(val);
}
+ public ArraySet<String> getAutomaticRuleNames() {
+ final ArraySet<String> rt = new ArraySet<String>();
+ for (int i = 0; i < automaticRules.size(); i++) {
+ rt.add(automaticRules.valueAt(i).name);
+ }
+ return rt;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -475,17 +460,6 @@
}
};
- public DowntimeInfo toDowntimeInfo() {
- final DowntimeInfo downtime = new DowntimeInfo();
- downtime.startHour = sleepStartHour;
- downtime.startMinute = sleepStartMinute;
- downtime.endHour = sleepEndHour;
- downtime.endMinute = sleepEndMinute;
- downtime.mode = sleepMode;
- downtime.none = sleepNone;
- return downtime;
- }
-
public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) {
final long now = System.currentTimeMillis();
final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
@@ -548,38 +522,77 @@
return tryParseCountdownConditionId(conditionId) != 0;
}
- // Built-in downtime conditions
- // e.g. condition://android/downtime?start=10.00&end=7.00&mode=days%3A5%2C6&none=false
- public static final String DOWNTIME_PATH = "downtime";
+ // built-in schedule conditions
+ public static final String SCHEDULE_PATH = "schedule";
- public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
+ public static class ScheduleInfo {
+ public int[] days;
+ public int startHour;
+ public int startMinute;
+ public int endHour;
+ public int endMinute;
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ScheduleInfo)) return false;
+ final ScheduleInfo other = (ScheduleInfo) o;
+ return toDayList(days).equals(toDayList(other.days))
+ && startHour == other.startHour
+ && startMinute == other.startMinute
+ && endHour == other.endHour
+ && endMinute == other.endMinute;
+ }
+
+ public ScheduleInfo copy() {
+ final ScheduleInfo rt = new ScheduleInfo();
+ if (days != null) {
+ rt.days = new int[days.length];
+ System.arraycopy(days, 0, rt.days, 0, days.length);
+ }
+ rt.startHour = startHour;
+ rt.startMinute = startMinute;
+ rt.endHour = endHour;
+ rt.endMinute = endMinute;
+ return rt;
+ }
+ }
+
+ public static Uri toScheduleConditionId(ScheduleInfo schedule) {
return new Uri.Builder().scheme(Condition.SCHEME)
.authority(SYSTEM_AUTHORITY)
- .appendPath(DOWNTIME_PATH)
- .appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
- .appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
- .appendQueryParameter("mode", downtime.mode)
- .appendQueryParameter("none", Boolean.toString(downtime.none))
+ .appendPath(SCHEDULE_PATH)
+ .appendQueryParameter("days", toDayList(schedule.days))
+ .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
+ .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
.build();
}
- public static DowntimeInfo tryParseDowntimeConditionId(Uri conditionId) {
- if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)
- || conditionId.getPathSegments().size() != 1
- || !DOWNTIME_PATH.equals(conditionId.getPathSegments().get(0))) {
- return null;
- }
+ public static boolean isValidScheduleConditionId(Uri conditionId) {
+ return tryParseScheduleConditionId(conditionId) != null;
+ }
+
+ public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
+ final boolean isSchedule = conditionId != null
+ && conditionId.getScheme().equals(Condition.SCHEME)
+ && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+ && conditionId.getPathSegments().size() == 1
+ && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
+ if (!isSchedule) return null;
final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
if (start == null || end == null) return null;
- final DowntimeInfo downtime = new DowntimeInfo();
- downtime.startHour = start[0];
- downtime.startMinute = start[1];
- downtime.endHour = end[0];
- downtime.endMinute = end[1];
- downtime.mode = conditionId.getQueryParameter("mode");
- downtime.none = Boolean.toString(true).equals(conditionId.getQueryParameter("none"));
- return downtime;
+ final ScheduleInfo rt = new ScheduleInfo();
+ rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\.");
+ rt.startHour = start[0];
+ rt.startMinute = start[1];
+ rt.endHour = end[0];
+ rt.endMinute = end[1];
+ return rt;
}
private static int[] tryParseHourAndMinute(String value) {
@@ -591,36 +604,268 @@
return isValidHour(hour) && isValidMinute(minute) ? new int[] { hour, minute } : null;
}
- public static boolean isValidDowntimeConditionId(Uri conditionId) {
- return tryParseDowntimeConditionId(conditionId) != null;
+ private static int tryParseZenMode(String value, int defValue) {
+ final int rt = tryParseInt(value, defValue);
+ return Global.isValidZenMode(rt) ? rt : defValue;
}
- public static class DowntimeInfo {
- public int startHour; // 0-23
- public int startMinute; // 0-59
- public int endHour;
- public int endMinute;
- public String mode;
- public boolean none;
+ public String newRuleId() {
+ return UUID.randomUUID().toString().replace("-", "");
+ }
+
+ public static String getConditionLine1(Context context, ZenModeConfig config,
+ int userHandle) {
+ return getConditionLine(context, config, userHandle, true /*useLine1*/);
+ }
+
+ public static String getConditionSummary(Context context, ZenModeConfig config,
+ int userHandle) {
+ return getConditionLine(context, config, userHandle, false /*useLine1*/);
+ }
+
+ private static String getConditionLine(Context context, ZenModeConfig config,
+ int userHandle, boolean useLine1) {
+ if (config == null) return "";
+ if (config.manualRule != null) {
+ final Uri id = config.manualRule.conditionId;
+ if (id == null) {
+ return context.getString(com.android.internal.R.string.zen_mode_forever);
+ }
+ final long time = tryParseCountdownConditionId(id);
+ Condition c = config.manualRule.condition;
+ if (time > 0) {
+ final long now = System.currentTimeMillis();
+ final long span = time - now;
+ c = toTimeCondition(context,
+ time, Math.round(span / (float) MINUTES_MS), now, userHandle);
+ }
+ final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
+ return TextUtils.isEmpty(rt) ? "" : rt;
+ }
+ String summary = "";
+ for (ZenRule automaticRule : config.automaticRules.values()) {
+ if (automaticRule.enabled && !automaticRule.snoozing
+ && automaticRule.isTrueOrUnknown()) {
+ if (summary.isEmpty()) {
+ summary = automaticRule.name;
+ } else {
+ summary = context.getResources()
+ .getString(R.string.zen_mode_rule_name_combination, summary,
+ automaticRule.name);
+ }
+ }
+ }
+ return summary;
+ }
+
+ public static class ZenRule implements Parcelable {
+ public boolean enabled;
+ public boolean snoozing; // user manually disabled this instance
+ public String name; // required for automatic (unique)
+ public int zenMode;
+ public Uri conditionId; // required for automatic
+ public Condition condition; // optional
+ public ComponentName component; // optional
+
+ public ZenRule() { }
+
+ public ZenRule(Parcel source) {
+ enabled = source.readInt() == 1;
+ snoozing = source.readInt() == 1;
+ if (source.readInt() == 1) {
+ name = source.readString();
+ }
+ zenMode = source.readInt();
+ conditionId = source.readParcelable(null);
+ condition = source.readParcelable(null);
+ component = source.readParcelable(null);
+ }
@Override
- public int hashCode() {
+ public int describeContents() {
return 0;
}
@Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(enabled ? 1 : 0);
+ dest.writeInt(snoozing ? 1 : 0);
+ if (name != null) {
+ dest.writeInt(1);
+ dest.writeString(name);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(zenMode);
+ dest.writeParcelable(conditionId, 0);
+ dest.writeParcelable(condition, 0);
+ dest.writeParcelable(component, 0);
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(ZenRule.class.getSimpleName()).append('[')
+ .append("enabled=").append(enabled)
+ .append(",snoozing=").append(snoozing)
+ .append(",name=").append(name)
+ .append(",zenMode=").append(Global.zenModeToString(zenMode))
+ .append(",conditionId=").append(conditionId)
+ .append(",condition=").append(condition)
+ .append(",component=").append(component)
+ .append(']').toString();
+ }
+
+ @Override
public boolean equals(Object o) {
- if (!(o instanceof DowntimeInfo)) return false;
- final DowntimeInfo other = (DowntimeInfo) o;
- return startHour == other.startHour
- && startMinute == other.startMinute
- && endHour == other.endHour
- && endMinute == other.endMinute
- && Objects.equals(mode, other.mode)
- && none == other.none;
+ if (!(o instanceof ZenRule)) return false;
+ if (o == this) return true;
+ final ZenRule other = (ZenRule) o;
+ return other.enabled == enabled
+ && other.snoozing == snoozing
+ && Objects.equals(other.name, name)
+ && other.zenMode == zenMode
+ && Objects.equals(other.conditionId, conditionId)
+ && Objects.equals(other.condition, condition)
+ && Objects.equals(other.component, component);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
+ component);
+ }
+
+ public boolean isTrueOrUnknown() {
+ return condition == null || condition.state == Condition.STATE_TRUE
+ || condition.state == Condition.STATE_UNKNOWN;
+ }
+
+ public static final Parcelable.Creator<ZenRule> CREATOR
+ = new Parcelable.Creator<ZenRule>() {
+ @Override
+ public ZenRule createFromParcel(Parcel source) {
+ return new ZenRule(source);
+ }
+ @Override
+ public ZenRule[] newArray(int size) {
+ return new ZenRule[size];
+ }
+ };
+ }
+
+ // Legacy config
+ public static final class XmlV1 {
+ public static final String SLEEP_MODE_NIGHTS = "nights";
+ public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
+ public static final String SLEEP_MODE_DAYS_PREFIX = "days:";
+
+ private static final String EXIT_CONDITION_TAG = "exitCondition";
+ private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
+ private static final String SLEEP_TAG = "sleep";
+ private static final String SLEEP_ATT_MODE = "mode";
+ private static final String SLEEP_ATT_NONE = "none";
+
+ private static final String SLEEP_ATT_START_HR = "startHour";
+ private static final String SLEEP_ATT_START_MIN = "startMin";
+ private static final String SLEEP_ATT_END_HR = "endHour";
+ private static final String SLEEP_ATT_END_MIN = "endMin";
+
+ public boolean allowCalls;
+ public boolean allowMessages;
+ public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
+ public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
+ public int allowFrom = SOURCE_ANYONE;
+
+ public String sleepMode; // nights, weeknights, days:1,2,3 Calendar.days
+ public int sleepStartHour; // 0-23
+ public int sleepStartMinute; // 0-59
+ public int sleepEndHour;
+ public int sleepEndMinute;
+ public boolean sleepNone; // false = priority, true = none
+ public ComponentName[] conditionComponents;
+ public Uri[] conditionIds;
+ public Condition exitCondition; // manual exit condition
+ public ComponentName exitConditionComponent; // manual exit condition component
+
+ private static boolean isValidSleepMode(String sleepMode) {
+ return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
+ || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null;
+ }
+
+ public static int[] tryParseDays(String sleepMode) {
+ if (sleepMode == null) return null;
+ sleepMode = sleepMode.trim();
+ if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS;
+ if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS;
+ if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null;
+ if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null;
+ return tryParseDayList(sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()), ",");
+ }
+
+ public static XmlV1 readXml(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ String tag;
+ XmlV1 rt = new XmlV1();
+ final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
+ final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ tag = parser.getName();
+ if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
+ if (!conditionComponents.isEmpty()) {
+ rt.conditionComponents = conditionComponents
+ .toArray(new ComponentName[conditionComponents.size()]);
+ rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
+ }
+ return rt;
+ }
+ if (type == XmlPullParser.START_TAG) {
+ if (ALLOW_TAG.equals(tag)) {
+ rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
+ rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
+ rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
+ DEFAULT_ALLOW_REMINDERS);
+ rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS,
+ DEFAULT_ALLOW_EVENTS);
+ rt.allowFrom = safeInt(parser, ALLOW_ATT_FROM, SOURCE_ANYONE);
+ if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) {
+ throw new IndexOutOfBoundsException("bad source in config:"
+ + rt.allowFrom);
+ }
+ } else if (SLEEP_TAG.equals(tag)) {
+ final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
+ rt.sleepMode = isValidSleepMode(mode)? mode : null;
+ rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
+ final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
+ final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
+ final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
+ final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
+ rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
+ rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
+ rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
+ rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
+ } else if (CONDITION_TAG.equals(tag)) {
+ final ComponentName component =
+ safeComponentName(parser, CONDITION_ATT_COMPONENT);
+ final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
+ if (component != null && conditionId != null) {
+ conditionComponents.add(component);
+ conditionIds.add(conditionId);
+ }
+ } else if (EXIT_CONDITION_TAG.equals(tag)) {
+ rt.exitCondition = readConditionXml(parser);
+ if (rt.exitCondition != null) {
+ rt.exitConditionComponent =
+ safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+ }
+ }
+ }
+ }
+ throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
}
- // built-in next alarm conditions
- public static final String NEXT_ALARM_PATH = "next_alarm";
+ public interface Migration {
+ ZenModeConfig migrate(XmlV1 v1);
+ }
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 0d5db77..f38229a 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,7 +26,9 @@
*/
public class MetricsLogger implements MetricsConstants {
// These constants are temporary, they should migrate to MetricsConstants.
- // next value is 144;
+ // next value is 145;
+
+ public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e879244..1b9d133 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2044,16 +2044,9 @@
<!-- Enabled built-in zen mode condition providers -->
<string-array translatable="false" name="config_system_condition_providers">
<item>countdown</item>
- <item>downtime</item>
- <item>next_alarm</item>
+ <item>schedule</item>
</string-array>
- <!-- Show the next-alarm as a zen exit condition if it occurs in the next n hours. -->
- <integer name="config_next_alarm_condition_lookahead_threshold_hrs">12</integer>
-
- <!-- Show downtime as a zen exit condition if it starts in the next n hours. -->
- <integer name="config_downtime_condition_lookahead_threshold_hrs">4</integer>
-
<!-- Flags enabling default window features. See Window.java -->
<bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
<bool name="config_defaultWindowFeatureContextMenu">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a48e964..4285ea1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5170,12 +5170,6 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
- <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
- <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
-
- <!-- [CHAR_LIMIT=NONE] Zen mode: Condition line one for built-in downtime condition, if active -->
- <string name="downtime_condition_line_one">Until your downtime ends</string>
-
<!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes_summary">
<item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
@@ -5206,14 +5200,23 @@
<!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
<string name="zen_mode_forever">Until you turn this off</string>
+ <!-- Zen mode active automatic rule name separator. [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_rule_name_combination"><xliff:g id="first" example="Weeknights">%1$s</xliff:g> / <xliff:g id="rest" example="Meetings">%2$s</xliff:g></string>
+
<!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
<string name="toolbar_collapse_description">Collapse</string>
- <!-- Zen mode condition - summary: until next alarm. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_next_alarm_summary">Until next alarm at <xliff:g id="formattedTime" example="7:30 AM">%1$s</xliff:g></string>
+ <!-- Zen mode - feature name. [CHAR LIMIT=40] -->
+ <string name="zen_mode_feature_name">Block interruptions</string>
- <!-- Zen mode condition - line one: until next alarm. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_next_alarm_line_one">Until next alarm</string>
+ <!-- Zen mode - downtime legacy feature name. [CHAR LIMIT=40] -->
+ <string name="zen_mode_downtime_feature_name">Downtime</string>
+
+ <!-- Zen mode - name of default automatic schedule for weeknights. [CHAR LIMIT=40] -->
+ <string name="zen_mode_default_weeknights_name">Weeknights</string>
+
+ <!-- Zen mode - name of default automatic schedule for weekends. [CHAR LIMIT=40] -->
+ <string name="zen_mode_default_weekends_name">Weekends</string>
<!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
<string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c2c00b5..524a8c3 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2037,19 +2037,18 @@
<java-symbol type="dimen" name="timepicker_text_size_normal" />
<java-symbol type="dimen" name="timepicker_text_size_inner" />
<java-symbol type="string" name="battery_saver_description" />
- <java-symbol type="string" name="downtime_condition_summary" />
- <java-symbol type="string" name="downtime_condition_line_one" />
<java-symbol type="string" name="zen_mode_forever" />
+ <java-symbol type="string" name="zen_mode_rule_name_combination" />
<java-symbol type="plurals" name="zen_mode_duration_minutes" />
<java-symbol type="plurals" name="zen_mode_duration_hours" />
<java-symbol type="plurals" name="zen_mode_duration_minutes_summary" />
<java-symbol type="plurals" name="zen_mode_duration_hours_summary" />
<java-symbol type="string" name="zen_mode_until" />
- <java-symbol type="string" name="zen_mode_next_alarm_summary" />
- <java-symbol type="string" name="zen_mode_next_alarm_line_one" />
+ <java-symbol type="string" name="zen_mode_feature_name" />
+ <java-symbol type="string" name="zen_mode_downtime_feature_name" />
+ <java-symbol type="string" name="zen_mode_default_weeknights_name" />
+ <java-symbol type="string" name="zen_mode_default_weekends_name" />
<java-symbol type="array" name="config_system_condition_providers" />
- <java-symbol type="integer" name="config_next_alarm_condition_lookahead_threshold_hrs" />
- <java-symbol type="integer" name="config_downtime_condition_lookahead_threshold_hrs" />
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="select_day" />
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 1bdc1ec..5f4199a 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,6 @@
-->
<!-- Default configuration for zen mode. See android.service.notification.ZenModeConfig. -->
-<zen version="1">
- <allow calls="false" messages="false" />
- <sleep startHour="22" startMin="0" endHour="7" endMin="0" />
+<zen version="2">
+ <allow calls="true" messages="false" reminders="true" events="true" />
</zen>