blob: c165fc13cc5275f07df85a80397bd859cf082126 [file] [log] [blame]
John Spurlock856edeb2014-06-01 20:36:47 -04001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.server.notification;
18
19import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.net.Uri;
27import android.service.notification.Condition;
John Spurlock856edeb2014-06-01 20:36:47 -040028import android.service.notification.IConditionProvider;
29import android.service.notification.ZenModeConfig;
30import android.text.format.DateUtils;
John Spurlock4db0d982014-08-13 09:19:03 -040031import android.util.Log;
John Spurlock856edeb2014-06-01 20:36:47 -040032import android.util.Slog;
33
John Spurlock50806fc2014-07-15 10:22:02 -040034import com.android.server.notification.NotificationManagerService.DumpFilter;
35
36import java.io.PrintWriter;
John Spurlock856edeb2014-06-01 20:36:47 -040037
38/** Built-in zen condition provider for simple time-based conditions */
John Spurlockb2278d62015-04-07 12:47:12 -040039public class CountdownConditionProvider extends SystemConditionProviderService {
John Spurlock2f096ed2015-05-04 11:58:26 -040040 private static final String TAG = "ConditionProviders.CCP";
41 private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
John Spurlock856edeb2014-06-01 20:36:47 -040042
43 public static final ComponentName COMPONENT =
44 new ComponentName("android", CountdownConditionProvider.class.getName());
45
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";
49
50 private final Context mContext = this;
51 private final Receiver mReceiver = new Receiver();
52
53 private boolean mConnected;
John Spurlock50806fc2014-07-15 10:22:02 -040054 private long mTime;
Julia Reynolds7635ab02017-07-25 08:34:44 -040055 private boolean mIsAlarm;
John Spurlock856edeb2014-06-01 20:36:47 -040056
57 public CountdownConditionProvider() {
58 if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
59 }
60
John Spurlockb2278d62015-04-07 12:47:12 -040061 @Override
62 public ComponentName getComponent() {
63 return COMPONENT;
64 }
65
66 @Override
John Spurlockd60258f2015-04-30 09:30:52 -040067 public boolean isValidConditionId(Uri id) {
John Spurlockb2278d62015-04-07 12:47:12 -040068 return ZenModeConfig.isValidCountdownConditionId(id);
69 }
70
71 @Override
72 public void attachBase(Context base) {
73 attachBaseContext(base);
74 }
75
76 @Override
John Spurlock2f096ed2015-05-04 11:58:26 -040077 public void onBootComplete() {
78 // noop
79 }
80
81 @Override
John Spurlockb2278d62015-04-07 12:47:12 -040082 public IConditionProvider asInterface() {
83 return (IConditionProvider) onBind(null);
84 }
85
86 @Override
John Spurlock50806fc2014-07-15 10:22:02 -040087 public void dump(PrintWriter pw, DumpFilter filter) {
88 pw.println(" CountdownConditionProvider:");
89 pw.print(" mConnected="); pw.println(mConnected);
90 pw.print(" mTime="); pw.println(mTime);
91 }
92
John Spurlock856edeb2014-06-01 20:36:47 -040093 @Override
94 public void onConnected() {
95 if (DEBUG) Slog.d(TAG, "onConnected");
96 mContext.registerReceiver(mReceiver, new IntentFilter(ACTION));
97 mConnected = true;
98 }
99
100 @Override
101 public void onDestroy() {
102 super.onDestroy();
103 if (DEBUG) Slog.d(TAG, "onDestroy");
104 if (mConnected) {
105 mContext.unregisterReceiver(mReceiver);
106 }
107 mConnected = false;
108 }
109
110 @Override
John Spurlock856edeb2014-06-01 20:36:47 -0400111 public void onSubscribe(Uri conditionId) {
112 if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
John Spurlock50806fc2014-07-15 10:22:02 -0400113 mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
Julia Reynolds7635ab02017-07-25 08:34:44 -0400114 mIsAlarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId);
John Spurlock856edeb2014-06-01 20:36:47 -0400115 final AlarmManager alarms = (AlarmManager)
116 mContext.getSystemService(Context.ALARM_SERVICE);
Julia Reynolds7635ab02017-07-25 08:34:44 -0400117 final Intent intent = new Intent(ACTION)
118 .putExtra(EXTRA_CONDITION_ID, conditionId)
John Spurlock856edeb2014-06-01 20:36:47 -0400119 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
120 final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
121 intent, PendingIntent.FLAG_UPDATE_CURRENT);
122 alarms.cancel(pendingIntent);
John Spurlock50806fc2014-07-15 10:22:02 -0400123 if (mTime > 0) {
John Spurlock856edeb2014-06-01 20:36:47 -0400124 final long now = System.currentTimeMillis();
125 final CharSequence span =
John Spurlock50806fc2014-07-15 10:22:02 -0400126 DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS);
127 if (mTime <= now) {
128 // in the past, already false
Julia Reynolds7635ab02017-07-25 08:34:44 -0400129 notifyCondition(newCondition(mTime, mIsAlarm, Condition.STATE_FALSE));
John Spurlock50806fc2014-07-15 10:22:02 -0400130 } else {
131 // in the future, set an alarm
132 alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent);
133 }
John Spurlock856edeb2014-06-01 20:36:47 -0400134 if (DEBUG) Slog.d(TAG, String.format(
John Spurlock50806fc2014-07-15 10:22:02 -0400135 "%s %s for %s, %s in the future (%s), now=%s",
136 (mTime <= now ? "Not scheduling" : "Scheduling"),
137 ACTION, ts(mTime), mTime - now, span, ts(now)));
John Spurlock856edeb2014-06-01 20:36:47 -0400138 }
139 }
140
141 @Override
142 public void onUnsubscribe(Uri conditionId) {
143 // noop
144 }
145
146 private final class Receiver extends BroadcastReceiver {
147 @Override
148 public void onReceive(Context context, Intent intent) {
149 if (ACTION.equals(intent.getAction())) {
150 final Uri conditionId = intent.getParcelableExtra(EXTRA_CONDITION_ID);
Julia Reynolds7635ab02017-07-25 08:34:44 -0400151 final boolean alarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId);
John Spurlock856edeb2014-06-01 20:36:47 -0400152 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
153 if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId);
154 if (time > 0) {
Julia Reynolds7635ab02017-07-25 08:34:44 -0400155 notifyCondition(newCondition(time, alarm, Condition.STATE_FALSE));
John Spurlock856edeb2014-06-01 20:36:47 -0400156 }
157 }
158 }
159 }
160
Julia Reynolds7635ab02017-07-25 08:34:44 -0400161 private static final Condition newCondition(long time, boolean alarm, int state) {
162 return new Condition(ZenModeConfig.toCountdownConditionId(time, alarm),
John Spurlock856edeb2014-06-01 20:36:47 -0400163 "", "", "", 0, state,Condition.FLAG_RELEVANT_NOW);
164 }
165
166 public static String tryParseDescription(Uri conditionUri) {
167 final long time = ZenModeConfig.tryParseCountdownConditionId(conditionUri);
168 if (time == 0) return null;
169 final long now = System.currentTimeMillis();
170 final CharSequence span =
171 DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
172 return String.format("Scheduled for %s, %s in the future (%s), now=%s",
173 ts(time), time - now, span, ts(now));
174 }
175
John Spurlock856edeb2014-06-01 20:36:47 -0400176}