am ad2399f3: Merge "Zen: Implement calendar event system condition provider." into mnc-dev
* commit 'ad2399f3be4861d0f5acf072460d98fafc951c57': Zen: Implement calendar event system condition provider.
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* 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.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import android.provider.CalendarContract.Attendees;
|
||||
import android.provider.CalendarContract.Instances;
|
||||
import android.service.notification.ZenModeConfig.EventInfo;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
public class CalendarTracker {
|
||||
private static final String TAG = "ConditionProviders.CT";
|
||||
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
|
||||
private static final boolean DEBUG_ATTENDEES = false;
|
||||
|
||||
private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
|
||||
|
||||
private static final String[] INSTANCE_PROJECTION = {
|
||||
Instances.BEGIN,
|
||||
Instances.END,
|
||||
Instances.TITLE,
|
||||
Instances.VISIBLE,
|
||||
Instances.EVENT_ID,
|
||||
Instances.OWNER_ACCOUNT,
|
||||
Instances.CALENDAR_ID,
|
||||
};
|
||||
|
||||
private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
|
||||
|
||||
private static final String[] ATTENDEE_PROJECTION = {
|
||||
Attendees.EVENT_ID,
|
||||
Attendees.ATTENDEE_EMAIL,
|
||||
Attendees.ATTENDEE_STATUS,
|
||||
Attendees.ATTENDEE_TYPE,
|
||||
};
|
||||
|
||||
private static final String ATTENDEE_SELECTION = Attendees.EVENT_ID + " = ? AND "
|
||||
+ Attendees.ATTENDEE_EMAIL + " = ?";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private Callback mCallback;
|
||||
private boolean mRegistered;
|
||||
|
||||
public CalendarTracker(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
if (mCallback == callback) return;
|
||||
mCallback = callback;
|
||||
setRegistered(mCallback != null);
|
||||
}
|
||||
|
||||
public void dump(String prefix, PrintWriter pw) {
|
||||
pw.print(prefix); pw.print("mCallback="); pw.println(mCallback);
|
||||
pw.print(prefix); pw.print("mRegistered="); pw.println(mRegistered);
|
||||
}
|
||||
|
||||
public void dumpContent(Uri uri) {
|
||||
Log.d(TAG, "dumpContent: " + uri);
|
||||
final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
|
||||
try {
|
||||
int r = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
Log.d(TAG, "Row " + (++r) + ": id="
|
||||
+ cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)));
|
||||
for (int i = 0; i < cursor.getColumnCount(); i++) {
|
||||
final String name = cursor.getColumnName(i);
|
||||
final int type = cursor.getType(i);
|
||||
Object o = null;
|
||||
String typeName = null;
|
||||
switch (type) {
|
||||
case Cursor.FIELD_TYPE_INTEGER:
|
||||
o = cursor.getLong(i);
|
||||
typeName = "INTEGER";
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_STRING:
|
||||
o = cursor.getString(i);
|
||||
typeName = "STRING";
|
||||
break;
|
||||
case Cursor.FIELD_TYPE_NULL:
|
||||
o = null;
|
||||
typeName = "NULL";
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("type: " + type);
|
||||
}
|
||||
if (name.equals(BaseColumns._ID)
|
||||
|| name.toLowerCase().contains("sync")
|
||||
|| o == null) {
|
||||
continue;
|
||||
}
|
||||
Log.d(TAG, " " + name + "(" + typeName + ")=" + o);
|
||||
}
|
||||
}
|
||||
Log.d(TAG, " " + uri + " " + r + " rows");
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public CheckEventResult checkEvent(EventInfo filter, long time) {
|
||||
final Uri.Builder uriBuilder = Instances.CONTENT_URI.buildUpon();
|
||||
ContentUris.appendId(uriBuilder, time);
|
||||
ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
|
||||
final Uri uri = uriBuilder.build();
|
||||
final Cursor cursor = mContext.getContentResolver().query(uri, INSTANCE_PROJECTION, null,
|
||||
null, INSTANCE_ORDER_BY);
|
||||
final CheckEventResult result = new CheckEventResult();
|
||||
result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
final long begin = cursor.getLong(0);
|
||||
final long end = cursor.getLong(1);
|
||||
final String title = cursor.getString(2);
|
||||
final boolean visible = cursor.getInt(3) == 1;
|
||||
final int eventId = cursor.getInt(4);
|
||||
final String owner = cursor.getString(5);
|
||||
final long calendarId = cursor.getLong(6);
|
||||
if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s eid=%s o=%s cid=%s", title,
|
||||
new Date(begin), new Date(end), visible, eventId, owner, calendarId));
|
||||
final boolean meetsTime = time >= begin && time < end;
|
||||
final boolean meetsCalendar = visible
|
||||
&& (filter.calendar == 0 || filter.calendar == calendarId);
|
||||
if (meetsCalendar) {
|
||||
if (DEBUG) Log.d(TAG, " MEETS CALENDAR");
|
||||
final boolean meetsAttendee = meetsAttendee(filter, eventId, owner);
|
||||
if (meetsAttendee) {
|
||||
if (DEBUG) Log.d(TAG, " MEETS ATTENDEE");
|
||||
if (meetsTime) {
|
||||
if (DEBUG) Log.d(TAG, " MEETS TIME");
|
||||
result.inEvent = true;
|
||||
}
|
||||
if (begin > time && begin < result.recheckAt) {
|
||||
result.recheckAt = begin;
|
||||
} else if (end > time && end < result.recheckAt) {
|
||||
result.recheckAt = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean meetsAttendee(EventInfo filter, int eventId, String email) {
|
||||
String selection = ATTENDEE_SELECTION;
|
||||
String[] selectionArgs = { Integer.toString(eventId), email };
|
||||
if (DEBUG_ATTENDEES) {
|
||||
selection = null;
|
||||
selectionArgs = null;
|
||||
}
|
||||
final Cursor cursor = mContext.getContentResolver().query(Attendees.CONTENT_URI,
|
||||
ATTENDEE_PROJECTION, selection, selectionArgs, null);
|
||||
try {
|
||||
if (cursor.getCount() == 0) {
|
||||
if (DEBUG) Log.d(TAG, "No attendees found");
|
||||
return true;
|
||||
}
|
||||
boolean rt = false;
|
||||
while (cursor.moveToNext()) {
|
||||
final long rowEventId = cursor.getLong(0);
|
||||
final String rowEmail = cursor.getString(1);
|
||||
final int status = cursor.getInt(2);
|
||||
final int type = cursor.getInt(3);
|
||||
final boolean meetsReply = meetsReply(filter.reply, status);
|
||||
final boolean meetsAttendance = meetsAttendance(filter.attendance, type);
|
||||
if (DEBUG) Log.d(TAG, (DEBUG_ATTENDEES ? String.format(
|
||||
"rowEventId=%s, rowEmail=%s, ", rowEventId, rowEmail) : "") +
|
||||
String.format("status=%s, type=%s, meetsReply=%s, meetsAttendance=%s",
|
||||
attendeeStatusToString(status), attendeeTypeToString(type), meetsReply,
|
||||
meetsAttendance));
|
||||
final boolean eventMeets = rowEventId == eventId && Objects.equals(rowEmail, email)
|
||||
&& meetsReply && meetsAttendance;
|
||||
rt |= eventMeets;
|
||||
}
|
||||
return rt;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void setRegistered(boolean registered) {
|
||||
if (mRegistered == registered) return;
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
if (mRegistered) {
|
||||
cr.unregisterContentObserver(mObserver);
|
||||
}
|
||||
mRegistered = registered;
|
||||
if (mRegistered) {
|
||||
cr.registerContentObserver(Instances.CONTENT_URI, false, mObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private static String attendeeStatusToString(int status) {
|
||||
switch (status) {
|
||||
case Attendees.ATTENDEE_STATUS_NONE: return "ATTENDEE_STATUS_NONE";
|
||||
case Attendees.ATTENDEE_STATUS_ACCEPTED: return "ATTENDEE_STATUS_ACCEPTED";
|
||||
case Attendees.ATTENDEE_STATUS_DECLINED: return "ATTENDEE_STATUS_DECLINED";
|
||||
case Attendees.ATTENDEE_STATUS_INVITED: return "ATTENDEE_STATUS_INVITED";
|
||||
case Attendees.ATTENDEE_STATUS_TENTATIVE: return "ATTENDEE_STATUS_TENTATIVE";
|
||||
default: return "ATTENDEE_STATUS_UNKNOWN_" + status;
|
||||
}
|
||||
}
|
||||
|
||||
private static String attendeeTypeToString(int type) {
|
||||
switch (type) {
|
||||
case Attendees.TYPE_NONE: return "TYPE_NONE";
|
||||
case Attendees.TYPE_REQUIRED: return "TYPE_REQUIRED";
|
||||
case Attendees.TYPE_OPTIONAL: return "TYPE_OPTIONAL";
|
||||
case Attendees.TYPE_RESOURCE: return "TYPE_RESOURCE";
|
||||
default: return "TYPE_" + type;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean meetsAttendance(int attendance, int attendeeType) {
|
||||
switch (attendance) {
|
||||
case EventInfo.ATTENDANCE_OPTIONAL:
|
||||
return attendeeType == Attendees.TYPE_OPTIONAL;
|
||||
case EventInfo.ATTENDANCE_REQUIRED:
|
||||
return attendeeType == Attendees.TYPE_REQUIRED;
|
||||
default: // EventInfo.ATTENDANCE_REQUIRED_OR_OPTIONAL
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean meetsReply(int reply, int attendeeStatus) {
|
||||
switch (reply) {
|
||||
case EventInfo.REPLY_YES:
|
||||
return attendeeStatus == Attendees.ATTENDEE_STATUS_ACCEPTED;
|
||||
case EventInfo.REPLY_ANY_EXCEPT_NO:
|
||||
return attendeeStatus != Attendees.ATTENDEE_STATUS_DECLINED;
|
||||
default: // EventInfo.REPLY_ANY
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private final ContentObserver mObserver = new ContentObserver(null) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri u) {
|
||||
if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange + " uri=" + u);
|
||||
mCallback.onChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
if (DEBUG) Log.d(TAG, "onChange selfChange=" + selfChange);
|
||||
}
|
||||
};
|
||||
|
||||
public static class CheckEventResult {
|
||||
public boolean inEvent;
|
||||
public long recheckAt;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void onChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -121,6 +121,9 @@ public class ConditionProviders extends ManagedServices {
|
||||
@Override
|
||||
public void onBootPhaseAppsCanStart() {
|
||||
super.onBootPhaseAppsCanStart();
|
||||
for (int i = 0; i < mSystemConditionProviders.size(); i++) {
|
||||
mSystemConditionProviders.valueAt(i).onBootComplete();
|
||||
}
|
||||
if (mCallback != null) {
|
||||
mCallback.onBootComplete();
|
||||
}
|
||||
|
||||
@@ -34,12 +34,11 @@ import android.util.Slog;
|
||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
|
||||
/** Built-in zen condition provider for simple time-based conditions */
|
||||
public class CountdownConditionProvider extends SystemConditionProviderService {
|
||||
private static final String TAG = "ConditionProviders";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final String TAG = "ConditionProviders.CCP";
|
||||
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
|
||||
|
||||
public static final ComponentName COMPONENT =
|
||||
new ComponentName("android", CountdownConditionProvider.class.getName());
|
||||
@@ -73,6 +72,11 @@ public class CountdownConditionProvider extends SystemConditionProviderService {
|
||||
attachBaseContext(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootComplete() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public IConditionProvider asInterface() {
|
||||
return (IConditionProvider) onBind(null);
|
||||
@@ -170,8 +174,4 @@ public class CountdownConditionProvider extends SystemConditionProviderService {
|
||||
ts(time), time - now, span, ts(now));
|
||||
}
|
||||
|
||||
private static String ts(long time) {
|
||||
return new Date(time) + " (" + time + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,16 +16,23 @@
|
||||
|
||||
package com.android.server.notification;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.service.notification.Condition;
|
||||
import android.service.notification.IConditionProvider;
|
||||
import android.service.notification.ZenModeConfig;
|
||||
import android.service.notification.ZenModeConfig.EventInfo;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.notification.CalendarTracker.CheckEventResult;
|
||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -34,20 +41,27 @@ 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);
|
||||
private static final String TAG = "ConditionProviders.ECP";
|
||||
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
|
||||
|
||||
public static final ComponentName COMPONENT =
|
||||
new ComponentName("android", EventConditionProvider.class.getName());
|
||||
private static final String NOT_SHOWN = "...";
|
||||
private static final String SIMPLE_NAME = EventConditionProvider.class.getSimpleName();
|
||||
private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE";
|
||||
private static final int REQUEST_CODE_EVALUATE = 1;
|
||||
private static final String EXTRA_TIME = "time";
|
||||
|
||||
private final Context mContext = this;
|
||||
private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
|
||||
private final CalendarTracker mTracker = new CalendarTracker(mContext);
|
||||
|
||||
private boolean mConnected;
|
||||
private boolean mRegistered;
|
||||
private boolean mBootComplete; // don't hammer the calendar provider until boot completes.
|
||||
|
||||
public EventConditionProvider() {
|
||||
if (DEBUG) Slog.d(TAG, "new EventConditionProvider()");
|
||||
if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,14 +76,25 @@ public class EventConditionProvider extends SystemConditionProviderService {
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
pw.println(" EventConditionProvider:");
|
||||
pw.print(" "); pw.print(SIMPLE_NAME); pw.println(":");
|
||||
pw.print(" mConnected="); pw.println(mConnected);
|
||||
pw.print(" mRegistered="); pw.println(mRegistered);
|
||||
pw.print(" mBootComplete="); pw.println(mBootComplete);
|
||||
pw.println(" mSubscriptions=");
|
||||
for (Uri conditionId : mSubscriptions) {
|
||||
pw.print(" ");
|
||||
pw.println(conditionId);
|
||||
}
|
||||
pw.println(" mTracker=");
|
||||
mTracker.dump(" ", pw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootComplete() {
|
||||
if (DEBUG) Slog.d(TAG, "onBootComplete");
|
||||
if (mBootComplete) return;
|
||||
mBootComplete = true;
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,8 +123,9 @@ public class EventConditionProvider extends SystemConditionProviderService {
|
||||
notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
|
||||
return;
|
||||
}
|
||||
mSubscriptions.add(conditionId);
|
||||
evaluateSubscriptions();
|
||||
if (mSubscriptions.add(conditionId)) {
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,9 +147,52 @@ public class EventConditionProvider extends SystemConditionProviderService {
|
||||
}
|
||||
|
||||
private void evaluateSubscriptions() {
|
||||
for (Uri conditionId : mSubscriptions) {
|
||||
notifyCondition(conditionId, Condition.STATE_FALSE, "notImplemented");
|
||||
if (DEBUG) Log.d(TAG, "evaluateSubscriptions");
|
||||
if (!mBootComplete) {
|
||||
if (DEBUG) Log.d(TAG, "Skipping evaluate before boot complete");
|
||||
return;
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
mTracker.setCallback(mSubscriptions.isEmpty() ? null : mTrackerCallback);
|
||||
setRegistered(!mSubscriptions.isEmpty());
|
||||
long reevaluateAt = 0;
|
||||
for (Uri conditionId : mSubscriptions) {
|
||||
final EventInfo event = ZenModeConfig.tryParseEventConditionId(conditionId);
|
||||
if (event == null) {
|
||||
notifyCondition(conditionId, Condition.STATE_FALSE, "badConditionId");
|
||||
continue;
|
||||
}
|
||||
final CheckEventResult result = mTracker.checkEvent(event, now);
|
||||
if (result.recheckAt != 0 && (reevaluateAt == 0 || result.recheckAt < reevaluateAt)) {
|
||||
reevaluateAt = result.recheckAt;
|
||||
}
|
||||
if (!result.inEvent) {
|
||||
notifyCondition(conditionId, Condition.STATE_FALSE, "!inEventNow");
|
||||
continue;
|
||||
}
|
||||
notifyCondition(conditionId, Condition.STATE_TRUE, "inEventNow");
|
||||
}
|
||||
updateAlarm(now, reevaluateAt);
|
||||
if (DEBUG) Log.d(TAG, "evaluateSubscriptions took " + (System.currentTimeMillis() - now));
|
||||
}
|
||||
|
||||
private void updateAlarm(long now, long time) {
|
||||
final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
|
||||
REQUEST_CODE_EVALUATE,
|
||||
new Intent(ACTION_EVALUATE)
|
||||
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
||||
.putExtra(EXTRA_TIME, time),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarms.cancel(pendingIntent);
|
||||
if (time == 0 || time < now) {
|
||||
if (DEBUG) Slog.d(TAG, "Not scheduling evaluate: " + (time == 0 ? "no time specified"
|
||||
: "specified time in the past"));
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Slog.d(TAG, String.format("Scheduling evaluate for %s, in %s, now=%s",
|
||||
ts(time), formatDuration(time - now), ts(now)));
|
||||
alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
|
||||
}
|
||||
|
||||
private void notifyCondition(Uri conditionId, int state, String reason) {
|
||||
@@ -139,4 +208,34 @@ public class EventConditionProvider extends SystemConditionProviderService {
|
||||
return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS);
|
||||
}
|
||||
|
||||
private void setRegistered(boolean registered) {
|
||||
if (mRegistered == registered) return;
|
||||
if (DEBUG) Slog.d(TAG, "setRegistered " + registered);
|
||||
mRegistered = registered;
|
||||
if (mRegistered) {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_TIME_CHANGED);
|
||||
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
|
||||
filter.addAction(ACTION_EVALUATE);
|
||||
registerReceiver(mReceiver, filter);
|
||||
} else {
|
||||
unregisterReceiver(mReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
private final CalendarTracker.Callback mTrackerCallback = new CalendarTracker.Callback() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (DEBUG) Log.d(TAG, "mTrackerCallback.onChanged");
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction());
|
||||
evaluateSubscriptions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,25 +31,24 @@ import android.service.notification.ZenModeConfig.ScheduleInfo;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Built-in zen condition provider for daily scheduled time-based conditions.
|
||||
*/
|
||||
public class ScheduleConditionProvider extends SystemConditionProviderService {
|
||||
private static final String TAG = "ConditionProviders";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final String TAG = "ConditionProviders.SCP";
|
||||
private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
|
||||
|
||||
public static final ComponentName COMPONENT =
|
||||
new ComponentName("android", ScheduleConditionProvider.class.getName());
|
||||
private static final String NOT_SHOWN = "...";
|
||||
private static final String ACTION_EVALUATE = TAG + ".EVALUATE";
|
||||
private static final String SIMPLE_NAME = ScheduleConditionProvider.class.getSimpleName();
|
||||
private static final String ACTION_EVALUATE = SIMPLE_NAME + ".EVALUATE";
|
||||
private static final int REQUEST_CODE_EVALUATE = 1;
|
||||
private static final String EXTRA_TIME = "time";
|
||||
|
||||
@@ -60,7 +59,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
|
||||
private boolean mRegistered;
|
||||
|
||||
public ScheduleConditionProvider() {
|
||||
if (DEBUG) Slog.d(TAG, "new ScheduleConditionProvider()");
|
||||
if (DEBUG) Slog.d(TAG, "new " + SIMPLE_NAME + "()");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,7 +74,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw, DumpFilter filter) {
|
||||
pw.println(" ScheduleConditionProvider:");
|
||||
pw.print(" "); pw.print(SIMPLE_NAME); pw.println(":");
|
||||
pw.print(" mConnected="); pw.println(mConnected);
|
||||
pw.print(" mRegistered="); pw.println(mRegistered);
|
||||
pw.println(" mSubscriptions=");
|
||||
@@ -93,6 +92,11 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
|
||||
mConnected = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootComplete() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
@@ -175,16 +179,6 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
|
||||
}
|
||||
}
|
||||
|
||||
private static String ts(long time) {
|
||||
return new Date(time) + " (" + time + ")";
|
||||
}
|
||||
|
||||
private static String formatDuration(long millis) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
TimeUtils.formatDuration(millis, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static boolean meetsSchedule(Uri conditionId, long time) {
|
||||
final ScheduleCalendar cal = toScheduleCalendar(conditionId);
|
||||
return cal != null && cal.isInSchedule(time);
|
||||
|
||||
@@ -21,10 +21,12 @@ import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.service.notification.ConditionProviderService;
|
||||
import android.service.notification.IConditionProvider;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.server.notification.NotificationManagerService.DumpFilter;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class SystemConditionProviderService extends ConditionProviderService {
|
||||
|
||||
@@ -33,4 +35,15 @@ public abstract class SystemConditionProviderService extends ConditionProviderSe
|
||||
abstract public IConditionProvider asInterface();
|
||||
abstract public ComponentName getComponent();
|
||||
abstract public boolean isValidConditionId(Uri id);
|
||||
abstract public void onBootComplete();
|
||||
|
||||
protected static String ts(long time) {
|
||||
return new Date(time) + " (" + time + ")";
|
||||
}
|
||||
|
||||
protected static String formatDuration(long millis) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
TimeUtils.formatDuration(millis, sb);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user