blob: 44c3887ec35d2083d79c0c09a02e2f315be8baa7 [file] [log] [blame]
John Spurlock7340fc82014-04-24 18:50:12 -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 android.service.notification;
18
19import android.annotation.SdkConstant;
Julia Reynoldsa62496d2016-01-29 15:29:16 -050020import android.annotation.SystemApi;
John Spurlock7340fc82014-04-24 18:50:12 -040021import android.app.INotificationManager;
22import android.app.Service;
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040023import android.content.ComponentName;
John Spurlock7340fc82014-04-24 18:50:12 -040024import android.content.Context;
25import android.content.Intent;
26import android.net.Uri;
John Spurlocke86de4c2014-04-29 21:48:26 -040027import android.os.Handler;
John Spurlock7340fc82014-04-24 18:50:12 -040028import android.os.IBinder;
John Spurlocke86de4c2014-04-29 21:48:26 -040029import android.os.Message;
John Spurlock7340fc82014-04-24 18:50:12 -040030import android.os.ServiceManager;
31import android.util.Log;
32
33/**
34 * A service that provides conditions about boolean state.
35 * <p>To extend this class, you must declare the service in your manifest file with
36 * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040037 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. If you want users to be
38 * able to create and update conditions for this service to monitor, include the
Julia Reynoldsc279b992015-10-30 08:23:51 -040039 * {@link #META_DATA_RULE_TYPE} and {@link #META_DATA_CONFIGURATION_ACTIVITY} tags and request the
40 * {@link android.Manifest.permission#ACCESS_NOTIFICATION_POLICY} permission. For example:</p>
John Spurlock7340fc82014-04-24 18:50:12 -040041 * <pre>
42 * &lt;service android:name=".MyConditionProvider"
43 * android:label="&#64;string/service_name"
44 * android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
45 * &lt;intent-filter>
46 * &lt;action android:name="android.service.notification.ConditionProviderService" />
47 * &lt;/intent-filter>
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040048 * &lt;meta-data
49 * android:name="android.service.zen.automatic.ruleType"
50 * android:value="@string/my_condition_rule">
51 * &lt;/meta-data>
52 * &lt;meta-data
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040053 * android:name="android.service.zen.automatic.configurationActivity"
54 * android:value="com.my.package/.MyConditionConfigurationActivity">
55 * &lt;/meta-data>
John Spurlock7340fc82014-04-24 18:50:12 -040056 * &lt;/service></pre>
57 *
John Spurlock7340fc82014-04-24 18:50:12 -040058 */
59public abstract class ConditionProviderService extends Service {
60 private final String TAG = ConditionProviderService.class.getSimpleName()
61 + "[" + getClass().getSimpleName() + "]";
62
John Spurlocke86de4c2014-04-29 21:48:26 -040063 private final H mHandler = new H();
64
John Spurlock7340fc82014-04-24 18:50:12 -040065 private Provider mProvider;
66 private INotificationManager mNoMan;
67
68 /**
69 * The {@link Intent} that must be declared as handled by the service.
70 */
71 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
72 public static final String SERVICE_INTERFACE
73 = "android.service.notification.ConditionProviderService";
74
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040075 /**
76 * The name of the {@code meta-data} tag containing a localized name of the type of zen rules
77 * provided by this service.
78 */
79 public static final String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
80
81 /**
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040082 * The name of the {@code meta-data} tag containing the {@link ComponentName} of an activity
83 * that allows users to configure the conditions provided by this service.
84 */
85 public static final String META_DATA_CONFIGURATION_ACTIVITY =
86 "android.service.zen.automatic.configurationActivity";
87
88 /**
Julia Reynolds43b70cd2016-01-14 15:05:34 -050089 * The name of the {@code meta-data} tag containing the maximum number of rule instances that
90 * can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
91 */
92 public static final String META_DATA_RULE_INSTANCE_LIMIT =
93 "android.service.zen.automatic.ruleInstanceLimit";
94
95 /**
Julia Reynolds4fe98d62015-10-06 16:23:41 -040096 * A String rule id extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}.
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040097 */
Julia Reynolds4fe98d62015-10-06 16:23:41 -040098 public static final String EXTRA_RULE_ID = "android.content.automatic.ruleId";
Julia Reynoldsb0a773f2015-08-25 15:01:22 -040099
100 /**
101 * Called when this service is connected.
102 */
John Spurlocke77bb362014-04-26 10:24:59 -0400103 abstract public void onConnected();
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400104
Julia Reynoldsa62496d2016-01-29 15:29:16 -0500105 @SystemApi
106 public void onRequestConditions(int relevance) {}
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400107
108 /**
109 * Called by the system when there is a new {@link Condition} to be managed by this provider.
110 * @param conditionId the Uri describing the criteria of the condition.
111 */
John Spurlocke77bb362014-04-26 10:24:59 -0400112 abstract public void onSubscribe(Uri conditionId);
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400113
114 /**
115 * Called by the system when a {@link Condition} has been deleted.
116 * @param conditionId the Uri describing the criteria of the deleted condition.
117 */
John Spurlocke77bb362014-04-26 10:24:59 -0400118 abstract public void onUnsubscribe(Uri conditionId);
John Spurlock7340fc82014-04-24 18:50:12 -0400119
120 private final INotificationManager getNotificationInterface() {
121 if (mNoMan == null) {
122 mNoMan = INotificationManager.Stub.asInterface(
123 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
124 }
125 return mNoMan;
126 }
127
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400128 /**
Julia Reynoldsa62496d2016-01-29 15:29:16 -0500129 * Informs the notification manager that the state of a Condition has changed. Use this method
130 * to put the system into Do Not Disturb mode or request that it exits Do Not Disturb mode. This
131 * call will be ignored unless there is an enabled {@link android.app.AutomaticZenRule} owned by
132 * service that has an {@link android.app.AutomaticZenRule#getConditionId()} equal to this
133 * {@link Condition#id}.
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400134 * @param condition the condition that has changed.
135 */
John Spurlock1c923a32014-04-27 16:42:29 -0400136 public final void notifyCondition(Condition condition) {
137 if (condition == null) return;
138 notifyConditions(new Condition[]{ condition });
139 }
140
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400141 /**
Julia Reynoldsa62496d2016-01-29 15:29:16 -0500142 * Informs the notification manager that the state of one or more Conditions has changed. See
143 * {@link #notifyCondition(Condition)} for restrictions.
Julia Reynoldsb0a773f2015-08-25 15:01:22 -0400144 * @param conditions the changed conditions.
145 */
John Spurlock1c923a32014-04-27 16:42:29 -0400146 public final void notifyConditions(Condition... conditions) {
147 if (!isBound() || conditions == null) return;
John Spurlock7340fc82014-04-24 18:50:12 -0400148 try {
John Spurlocke77bb362014-04-26 10:24:59 -0400149 getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
John Spurlock7340fc82014-04-24 18:50:12 -0400150 } catch (android.os.RemoteException ex) {
151 Log.v(TAG, "Unable to contact notification manager", ex);
152 }
153 }
154
155 @Override
156 public IBinder onBind(Intent intent) {
157 if (mProvider == null) {
158 mProvider = new Provider();
159 }
160 return mProvider;
161 }
162
163 private boolean isBound() {
164 if (mProvider == null) {
165 Log.w(TAG, "Condition provider service not yet bound.");
166 return false;
167 }
168 return true;
169 }
170
171 private final class Provider extends IConditionProvider.Stub {
John Spurlock7340fc82014-04-24 18:50:12 -0400172 @Override
John Spurlocke77bb362014-04-26 10:24:59 -0400173 public void onConnected() {
John Spurlocke86de4c2014-04-29 21:48:26 -0400174 mHandler.obtainMessage(H.ON_CONNECTED).sendToTarget();
John Spurlock7340fc82014-04-24 18:50:12 -0400175 }
176
177 @Override
John Spurlocke77bb362014-04-26 10:24:59 -0400178 public void onSubscribe(Uri conditionId) {
John Spurlocke86de4c2014-04-29 21:48:26 -0400179 mHandler.obtainMessage(H.ON_SUBSCRIBE, conditionId).sendToTarget();
John Spurlock7340fc82014-04-24 18:50:12 -0400180 }
181
182 @Override
John Spurlocke77bb362014-04-26 10:24:59 -0400183 public void onUnsubscribe(Uri conditionId) {
John Spurlocke86de4c2014-04-29 21:48:26 -0400184 mHandler.obtainMessage(H.ON_UNSUBSCRIBE, conditionId).sendToTarget();
185 }
186 }
187
188 private final class H extends Handler {
189 private static final int ON_CONNECTED = 1;
John Spurlocke86de4c2014-04-29 21:48:26 -0400190 private static final int ON_SUBSCRIBE = 3;
191 private static final int ON_UNSUBSCRIBE = 4;
192
193 @Override
194 public void handleMessage(Message msg) {
195 String name = null;
John Spurlock7340fc82014-04-24 18:50:12 -0400196 try {
John Spurlocke86de4c2014-04-29 21:48:26 -0400197 switch(msg.what) {
198 case ON_CONNECTED:
199 name = "onConnected";
200 onConnected();
201 break;
John Spurlocke86de4c2014-04-29 21:48:26 -0400202 case ON_SUBSCRIBE:
203 name = "onSubscribe";
204 onSubscribe((Uri)msg.obj);
205 break;
206 case ON_UNSUBSCRIBE:
207 name = "onUnsubscribe";
208 onUnsubscribe((Uri)msg.obj);
209 break;
210 }
John Spurlock7340fc82014-04-24 18:50:12 -0400211 } catch (Throwable t) {
John Spurlocke86de4c2014-04-29 21:48:26 -0400212 Log.w(TAG, "Error running " + name, t);
John Spurlock7340fc82014-04-24 18:50:12 -0400213 }
214 }
215 }
216}