2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.notification;
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.net.Uri;
27 import android.service.notification.Condition;
28 import android.service.notification.IConditionProvider;
29 import android.service.notification.ZenModeConfig;
30 import android.text.format.DateUtils;
31 import android.util.Log;
32 import android.util.Slog;
34 import com.android.server.notification.NotificationManagerService.DumpFilter;
36 import java.io.PrintWriter;
38 /** Built-in zen condition provider for simple time-based conditions */
39 public class CountdownConditionProvider extends SystemConditionProviderService {
40 private static final String TAG = "ConditionProviders.CCP";
41 private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
43 public static final ComponentName COMPONENT =
44 new ComponentName("android", CountdownConditionProvider.class.getName());
46 private static final String ACTION = CountdownConditionProvider.class.getName();
47 private static final int REQUEST_CODE = 100;
48 private static final String EXTRA_CONDITION_ID = "condition_id";
50 private final Context mContext = this;
51 private final Receiver mReceiver = new Receiver();
53 private boolean mConnected;
56 public CountdownConditionProvider() {
57 if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
61 public ComponentName getComponent() {
66 public boolean isValidConditionId(Uri id) {
67 return ZenModeConfig.isValidCountdownConditionId(id);
71 public void attachBase(Context base) {
72 attachBaseContext(base);
76 public void onBootComplete() {
81 public IConditionProvider asInterface() {
82 return (IConditionProvider) onBind(null);
86 public void dump(PrintWriter pw, DumpFilter filter) {
87 pw.println(" CountdownConditionProvider:");
88 pw.print(" mConnected="); pw.println(mConnected);
89 pw.print(" mTime="); pw.println(mTime);
93 public void onConnected() {
94 if (DEBUG) Slog.d(TAG, "onConnected");
95 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
100 public void onDestroy() {
102 if (DEBUG) Slog.d(TAG, "onDestroy");
104 mContext.unregisterReceiver(mReceiver);
110 public void onRequestConditions(int relevance) {
115 public void onSubscribe(Uri conditionId) {
116 if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
117 mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
118 final AlarmManager alarms = (AlarmManager)
119 mContext.getSystemService(Context.ALARM_SERVICE);
120 final Intent intent = new Intent(ACTION).putExtra(EXTRA_CONDITION_ID, conditionId)
121 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
122 final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
123 intent, PendingIntent.FLAG_UPDATE_CURRENT);
124 alarms.cancel(pendingIntent);
126 final long now = System.currentTimeMillis();
127 final CharSequence span =
128 DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS);
130 // in the past, already false
131 notifyCondition(newCondition(mTime, Condition.STATE_FALSE));
133 // in the future, set an alarm
134 alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent);
136 if (DEBUG) Slog.d(TAG, String.format(
137 "%s %s for %s, %s in the future (%s), now=%s",
138 (mTime <= now ? "Not scheduling" : "Scheduling"),
139 ACTION, ts(mTime), mTime - now, span, ts(now)));
144 public void onUnsubscribe(Uri conditionId) {
148 private final class Receiver extends BroadcastReceiver {
150 public void onReceive(Context context, Intent intent) {
151 if (ACTION.equals(intent.getAction())) {
152 final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
153 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
154 if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
156 notifyCondition(newCondition(time, Condition.STATE_FALSE));
162 private static final Condition newCondition(long time, int state) {
163 return new Condition(ZenModeConfig.toCountdownConditionId(time),
164 "", "", "", 0, state,Condition.FLAG_RELEVANT_NOW);
167 public static String tryParseDescription(Uri conditionUri) {
168 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionUri);
169 if (time == 0) return null;
170 final long now = System.currentTimeMillis();
171 final CharSequence span =
172 DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
173 return String.format("Scheduled for %s, %s in the future (%s), now=%s",
174 ts(time), time - now, span, ts(now));