am 1642e354: am 8f72b403: Merge "Zen: New event condition data model." into mnc-dev

* commit '1642e354ed10bc606f403ac6f529392f3f25dd2d':
  Zen: New event condition data model.
This commit is contained in:
John Spurlock
2015-04-30 16:16:13 +00:00
committed by Android Git Automerger
9 changed files with 270 additions and 36 deletions

View File

@@ -918,6 +918,15 @@ public final class Settings {
public static final String ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS
= "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
/**
* Activity Action: Show Zen Mode event rule configuration settings.
*
* @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ZEN_MODE_EVENT_RULE_SETTINGS
= "android.settings.ZEN_MODE_EVENT_RULE_SETTINGS";
/**
* Activity Action: Show Zen Mode external rule configuration settings.
*

View File

@@ -95,7 +95,7 @@ public class ZenModeConfig implements Parcelable {
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_ID = "ruleId";
private static final String RULE_ATT_ENABLED = "enabled";
private static final String RULE_ATT_SNOOZING = "snoozing";
private static final String RULE_ATT_NAME = "name";
@@ -279,6 +279,15 @@ public class ZenModeConfig implements Parcelable {
}
}
private static long tryParseLong(String value, long defValue) {
if (TextUtils.isEmpty(value)) return defValue;
try {
return Long.valueOf(value);
} catch (NumberFormatException e) {
return defValue;
}
}
public static ZenModeConfig readXml(XmlPullParser parser, Migration migration)
throws XmlPullParserException, IOException {
int type = parser.getEventType();
@@ -367,7 +376,7 @@ public class ZenModeConfig implements Parcelable {
rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
rt.condition = readConditionXml(parser);
return rt.condition != null || !conditionRequired ? rt : null;
return rt;
}
public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
@@ -568,10 +577,12 @@ public class ZenModeConfig implements Parcelable {
Condition.FLAG_RELEVANT_NOW);
}
// For built-in conditions
// ==== Built-in system conditions ====
public static final String SYSTEM_AUTHORITY = "android";
// Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
// ==== Built-in system condition: countdown ====
public static final String COUNTDOWN_PATH = "countdown";
public static Uri toCountdownConditionId(long time) {
@@ -598,9 +609,43 @@ public class ZenModeConfig implements Parcelable {
return tryParseCountdownConditionId(conditionId) != 0;
}
// built-in schedule conditions
// ==== Built-in system condition: schedule ====
public static final String SCHEDULE_PATH = "schedule";
public static Uri toScheduleConditionId(ScheduleInfo schedule) {
return new Uri.Builder().scheme(Condition.SCHEME)
.authority(SYSTEM_AUTHORITY)
.appendPath(SCHEDULE_PATH)
.appendQueryParameter("days", toDayList(schedule.days))
.appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
.appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
.build();
}
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 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;
}
public static class ScheduleInfo {
public int[] days;
public int startHour;
@@ -638,39 +683,76 @@ public class ZenModeConfig implements Parcelable {
}
}
public static Uri toScheduleConditionId(ScheduleInfo schedule) {
// ==== Built-in system condition: event ====
public static final String EVENT_PATH = "event";
public static Uri toEventConditionId(EventInfo event) {
return new Uri.Builder().scheme(Condition.SCHEME)
.authority(SYSTEM_AUTHORITY)
.appendPath(SCHEDULE_PATH)
.appendQueryParameter("days", toDayList(schedule.days))
.appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
.appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
.appendPath(EVENT_PATH)
.appendQueryParameter("calendar", Long.toString(event.calendar))
.appendQueryParameter("attendance", Integer.toString(event.attendance))
.appendQueryParameter("reply", Integer.toString(event.reply))
.build();
}
public static boolean isValidScheduleConditionId(Uri conditionId) {
return tryParseScheduleConditionId(conditionId) != null;
public static boolean isValidEventConditionId(Uri conditionId) {
return tryParseEventConditionId(conditionId) != null;
}
public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
final boolean isSchedule = conditionId != null
public static EventInfo tryParseEventConditionId(Uri conditionId) {
final boolean isEvent = 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 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];
&& conditionId.getPathSegments().get(0).equals(EVENT_PATH);
if (!isEvent) return null;
final EventInfo rt = new EventInfo();
rt.calendar = tryParseLong(conditionId.getQueryParameter("calendar"), 0L);
rt.attendance = tryParseInt(conditionId.getQueryParameter("attendance"), 0);
rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0);
return rt;
}
public static class EventInfo {
public static final int ATTENDANCE_REQUIRED_OR_OPTIONAL = 0;
public static final int ATTENDANCE_REQUIRED = 1;
public static final int ATTENDANCE_OPTIONAL = 2;
public static final int REPLY_ANY = 0;
public static final int REPLY_ANY_EXCEPT_NO = 1;
public static final int REPLY_YES = 2;
public long calendar; // CalendarContract.Calendars._ID, or 0 for any
public int attendance;
public int reply;
@Override
public int hashCode() {
return 0;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof EventInfo)) return false;
final EventInfo other = (EventInfo) o;
return calendar == other.calendar
&& attendance == other.attendance
&& reply == other.reply;
}
public EventInfo copy() {
final EventInfo rt = new EventInfo();
rt.calendar = calendar;
rt.attendance = attendance;
rt.reply = reply;
return rt;
}
}
// ==== End built-in system conditions ====
private static int[] tryParseHourAndMinute(String value) {
if (TextUtils.isEmpty(value)) return null;
final int i = value.indexOf('.');

View File

@@ -26,11 +26,12 @@ import android.os.Build;
*/
public class MetricsLogger implements MetricsConstants {
// These constants are temporary, they should migrate to MetricsConstants.
// next value is 146;
// next value is 148;
public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
public static final int ACTION_BAN_APP_NOTES = 146;
public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 147;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {

View File

@@ -2054,6 +2054,7 @@
<string-array translatable="false" name="config_system_condition_providers">
<item>countdown</item>
<item>schedule</item>
<item>event</item>
</string-array>
<!-- Priority repeat caller threshold, in minutes -->

View File

@@ -64,7 +64,7 @@ public class CountdownConditionProvider extends SystemConditionProviderService {
}
@Override
public boolean isValidConditionid(Uri id) {
public boolean isValidConditionId(Uri id) {
return ZenModeConfig.isValidCountdownConditionId(id);
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2015 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.server.notification;
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService.DumpFilter;
import java.io.PrintWriter;
/**
* Built-in zen condition provider for calendar event-based conditions.
*/
public class EventConditionProvider extends SystemConditionProviderService {
private static final String TAG = "ConditionProviders";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
new ComponentName("android", EventConditionProvider.class.getName());
private static final String NOT_SHOWN = "...";
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
private boolean mConnected;
private boolean mRegistered;
public EventConditionProvider() {
if (DEBUG) Slog.d(TAG, "new EventConditionProvider()");
}
@Override
public ComponentName getComponent() {
return COMPONENT;
}
@Override
public boolean isValidConditionId(Uri id) {
return ZenModeConfig.isValidEventConditionId(id);
}
@Override
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" EventConditionProvider:");
pw.print(" mConnected="); pw.println(mConnected);
pw.print(" mRegistered="); pw.println(mRegistered);
pw.println(" mSubscriptions=");
for (Uri conditionId : mSubscriptions) {
pw.print(" ");
pw.println(conditionId);
}
}
@Override
public void onConnected() {
if (DEBUG) Slog.d(TAG, "onConnected");
mConnected = true;
}
@Override
public void onDestroy() {
super.onDestroy();
if (DEBUG) Slog.d(TAG, "onDestroy");
mConnected = false;
}
@Override
public void onRequestConditions(int relevance) {
if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
// does not advertise conditions
}
@Override
public void onSubscribe(Uri conditionId) {
if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
if (!ZenModeConfig.isValidEventConditionId(conditionId)) {
notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
return;
}
mSubscriptions.add(conditionId);
evaluateSubscriptions();
}
@Override
public void onUnsubscribe(Uri conditionId) {
if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
if (mSubscriptions.remove(conditionId)) {
evaluateSubscriptions();
}
}
@Override
public void attachBase(Context base) {
attachBaseContext(base);
}
@Override
public IConditionProvider asInterface() {
return (IConditionProvider) onBind(null);
}
private void evaluateSubscriptions() {
for (Uri conditionId : mSubscriptions) {
notifyCondition(conditionId, Condition.STATE_FALSE, "notImplemented");
}
}
private void notifyCondition(Uri conditionId, int state, String reason) {
if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
+ " reason=" + reason);
notifyCondition(createCondition(conditionId, state));
}
private Condition createCondition(Uri id, int state) {
final String summary = NOT_SHOWN;
final String line1 = NOT_SHOWN;
final String line2 = NOT_SHOWN;
return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS);
}
}

View File

@@ -69,7 +69,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
}
@Override
public boolean isValidConditionid(Uri id) {
public boolean isValidConditionId(Uri id) {
return ZenModeConfig.isValidScheduleConditionId(id);
}

View File

@@ -32,5 +32,5 @@ public abstract class SystemConditionProviderService extends ConditionProviderSe
abstract public void attachBase(Context context);
abstract public IConditionProvider asInterface();
abstract public ComponentName getComponent();
abstract public boolean isValidConditionid(Uri id);
abstract public boolean isValidConditionId(Uri id);
}

View File

@@ -38,20 +38,19 @@ public class ZenModeConditions implements ConditionProviders.Callback {
private final ConditionProviders mConditionProviders;
private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
private CountdownConditionProvider mCountdown;
private ScheduleConditionProvider mSchedule;
private boolean mFirstEvaluation = true;
public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
mHelper = helper;
mConditionProviders = conditionProviders;
if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) {
mCountdown = new CountdownConditionProvider();
mConditionProviders.addSystemProvider(mCountdown);
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
}
if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) {
mSchedule = new ScheduleConditionProvider();
mConditionProviders.addSystemProvider(mSchedule);
mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
}
if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.EVENT_PATH)) {
mConditionProviders.addSystemProvider(new EventConditionProvider());
}
mConditionProviders.setCallback(this);
}
@@ -128,7 +127,7 @@ public class ZenModeConditions implements ConditionProviders.Callback {
final Uri id = rule.conditionId;
boolean isSystemCondition = false;
for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
if (sp.isValidConditionid(id)) {
if (sp.isValidConditionId(id)) {
mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
rule.component = sp.getComponent();
isSystemCondition = true;