John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 1 | /* |
| 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 | |
| 17 | package com.android.server.notification; |
| 18 | |
| 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; |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 28 | import android.service.notification.IConditionProvider; |
| 29 | import android.service.notification.ZenModeConfig; |
| 30 | import android.text.format.DateUtils; |
John Spurlock | 4db0d98 | 2014-08-13 09:19:03 -0400 | [diff] [blame] | 31 | import android.util.Log; |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 32 | import android.util.Slog; |
| 33 | |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 34 | import com.android.server.notification.NotificationManagerService.DumpFilter; |
| 35 | |
| 36 | import java.io.PrintWriter; |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 37 | |
| 38 | /** Built-in zen condition provider for simple time-based conditions */ |
John Spurlock | b2278d6 | 2015-04-07 12:47:12 -0400 | [diff] [blame] | 39 | public class CountdownConditionProvider extends SystemConditionProviderService { |
John Spurlock | 2f096ed | 2015-05-04 11:58:26 -0400 | [diff] [blame] | 40 | private static final String TAG = "ConditionProviders.CCP"; |
| 41 | private static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG); |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 42 | |
| 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 Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 54 | private long mTime; |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 55 | private boolean mIsAlarm; |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 56 | |
| 57 | public CountdownConditionProvider() { |
| 58 | if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()"); |
| 59 | } |
| 60 | |
John Spurlock | b2278d6 | 2015-04-07 12:47:12 -0400 | [diff] [blame] | 61 | @Override |
| 62 | public ComponentName getComponent() { |
| 63 | return COMPONENT; |
| 64 | } |
| 65 | |
| 66 | @Override |
John Spurlock | d60258f | 2015-04-30 09:30:52 -0400 | [diff] [blame] | 67 | public boolean isValidConditionId(Uri id) { |
John Spurlock | b2278d6 | 2015-04-07 12:47:12 -0400 | [diff] [blame] | 68 | return ZenModeConfig.isValidCountdownConditionId(id); |
| 69 | } |
| 70 | |
| 71 | @Override |
| 72 | public void attachBase(Context base) { |
| 73 | attachBaseContext(base); |
| 74 | } |
| 75 | |
| 76 | @Override |
John Spurlock | 2f096ed | 2015-05-04 11:58:26 -0400 | [diff] [blame] | 77 | public void onBootComplete() { |
| 78 | // noop |
| 79 | } |
| 80 | |
| 81 | @Override |
John Spurlock | b2278d6 | 2015-04-07 12:47:12 -0400 | [diff] [blame] | 82 | public IConditionProvider asInterface() { |
| 83 | return (IConditionProvider) onBind(null); |
| 84 | } |
| 85 | |
| 86 | @Override |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 87 | 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 Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 93 | @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 Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 111 | public void onSubscribe(Uri conditionId) { |
| 112 | if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId); |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 113 | mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId); |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 114 | mIsAlarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId); |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 115 | final AlarmManager alarms = (AlarmManager) |
| 116 | mContext.getSystemService(Context.ALARM_SERVICE); |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 117 | final Intent intent = new Intent(ACTION) |
| 118 | .putExtra(EXTRA_CONDITION_ID, conditionId) |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 119 | .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 Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 123 | if (mTime > 0) { |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 124 | final long now = System.currentTimeMillis(); |
| 125 | final CharSequence span = |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 126 | DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS); |
| 127 | if (mTime <= now) { |
| 128 | // in the past, already false |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 129 | notifyCondition(newCondition(mTime, mIsAlarm, Condition.STATE_FALSE)); |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 130 | } else { |
| 131 | // in the future, set an alarm |
| 132 | alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent); |
| 133 | } |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 134 | if (DEBUG) Slog.d(TAG, String.format( |
John Spurlock | 50806fc | 2014-07-15 10:22:02 -0400 | [diff] [blame] | 135 | "%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 Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 138 | } |
| 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 Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 151 | final boolean alarm = ZenModeConfig.isValidCountdownToAlarmConditionId(conditionId); |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 152 | final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId); |
| 153 | if (DEBUG) Slog.d(TAG, "Countdown condition fired: " + conditionId); |
| 154 | if (time > 0) { |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 155 | notifyCondition(newCondition(time, alarm, Condition.STATE_FALSE)); |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 156 | } |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
Julia Reynolds | 7635ab0 | 2017-07-25 08:34:44 -0400 | [diff] [blame] | 161 | private static final Condition newCondition(long time, boolean alarm, int state) { |
| 162 | return new Condition(ZenModeConfig.toCountdownConditionId(time, alarm), |
John Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 163 | "", "", "", 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 Spurlock | 856edeb | 2014-06-01 20:36:47 -0400 | [diff] [blame] | 176 | } |