blob: b5387f14e40c111a28539bded5d2b415818833f3 [file] [log] [blame]
Chris Wren9fa689f2015-11-20 16:44:53 -05001/*
2 * Copyright (C) 2015 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
Julia Reynolds7eba5932015-12-11 16:40:39 -050019import android.annotation.SdkConstant;
Chris Wrenab41eec2016-01-04 18:01:27 -050020import android.annotation.SystemApi;
21import android.app.INotificationManager;
Chris Wren9fa689f2015-11-20 16:44:53 -050022import android.app.Notification;
Chris Wrenab41eec2016-01-04 18:01:27 -050023import android.content.ComponentName;
24import android.content.Context;
Julia Reynolds7eba5932015-12-11 16:40:39 -050025import android.content.Intent;
Chris Wren9fa689f2015-11-20 16:44:53 -050026import android.net.Uri;
Chris Wren51017d02015-12-15 15:34:46 -050027import android.os.IBinder;
Julia Reynolds7eba5932015-12-11 16:40:39 -050028import android.os.Parcel;
29import android.os.Parcelable;
Chris Wren51017d02015-12-15 15:34:46 -050030import android.os.RemoteException;
Chris Wrenab41eec2016-01-04 18:01:27 -050031import android.os.ServiceManager;
Chris Wren51017d02015-12-15 15:34:46 -050032import android.util.Log;
Chris Wren9fa689f2015-11-20 16:44:53 -050033
34/**
35 * A service that helps the user manage notifications by modifying the
36 * relative importance of notifications.
37 * <p>To extend this class, you must declare the service in your manifest file with
38 * the {@link android.Manifest.permission#BIND_NOTIFICATION_ASSISTANT_SERVICE} permission
39 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
40 * <pre>
41 * &lt;service android:name=".NotificationAssistant"
42 * android:label="&#64;string/service_name"
43 * android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE">
44 * &lt;intent-filter>
45 * &lt;action android:name="android.service.notification.NotificationAssistantService" />
46 * &lt;/intent-filter>
47 * &lt;/service></pre>
Chris Wren10c63d82016-02-05 14:55:35 -050048 * @hide
Chris Wren9fa689f2015-11-20 16:44:53 -050049 */
Chris Wren10c63d82016-02-05 14:55:35 -050050@SystemApi
Chris Wren9fa689f2015-11-20 16:44:53 -050051public abstract class NotificationAssistantService extends NotificationListenerService {
Chris Wren51017d02015-12-15 15:34:46 -050052 private static final String TAG = "NotificationAssistant";
53
Julia Reynolds7eba5932015-12-11 16:40:39 -050054 /**
55 * The {@link Intent} that must be declared as handled by the service.
56 */
57 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
58 public static final String SERVICE_INTERFACE
59 = "android.service.notification.NotificationAssistantService";
60
Chris Wren9fa689f2015-11-20 16:44:53 -050061 /** Notification was canceled by the status bar reporting a click. */
62 public static final int REASON_DELEGATE_CLICK = 1;
63
64 /** Notification was canceled by the status bar reporting a user dismissal. */
65 public static final int REASON_DELEGATE_CANCEL = 2;
66
67 /** Notification was canceled by the status bar reporting a user dismiss all. */
68 public static final int REASON_DELEGATE_CANCEL_ALL = 3;
69
70 /** Notification was canceled by the status bar reporting an inflation error. */
71 public static final int REASON_DELEGATE_ERROR = 4;
72
73 /** Notification was canceled by the package manager modifying the package. */
74 public static final int REASON_PACKAGE_CHANGED = 5;
75
76 /** Notification was canceled by the owning user context being stopped. */
77 public static final int REASON_USER_STOPPED = 6;
78
79 /** Notification was canceled by the user banning the package. */
80 public static final int REASON_PACKAGE_BANNED = 7;
81
82 /** Notification was canceled by the app canceling this specific notification. */
83 public static final int REASON_APP_CANCEL = 8;
84
85 /** Notification was canceled by the app cancelling all its notifications. */
86 public static final int REASON_APP_CANCEL_ALL = 9;
87
88 /** Notification was canceled by a listener reporting a user dismissal. */
89 public static final int REASON_LISTENER_CANCEL = 10;
90
91 /** Notification was canceled by a listener reporting a user dismiss all. */
92 public static final int REASON_LISTENER_CANCEL_ALL = 11;
93
94 /** Notification was canceled because it was a member of a canceled group. */
95 public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
96
97 /** Notification was canceled because it was an invisible member of a group. */
98 public static final int REASON_GROUP_OPTIMIZATION = 13;
99
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000100 /** Notification was canceled by the device administrator suspending the package. */
Julia Reynoldsef37f282016-02-12 09:11:27 -0500101 public static final int REASON_PACKAGE_SUSPENDED = 14;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000102
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000103 /** Notification was canceled by the owning managed profile being turned off. */
Julia Reynoldsef37f282016-02-12 09:11:27 -0500104 public static final int REASON_PROFILE_TURNED_OFF = 15;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000105
Chris Wren51017d02015-12-15 15:34:46 -0500106 public class Adjustment {
107 int mImportance;
108 CharSequence mExplanation;
109 Uri mReference;
110
111 /**
112 * Create a notification importance adjustment.
113 *
114 * @param importance The final importance of the notification.
115 * @param explanation A human-readable justification for the adjustment.
116 * @param reference A reference to an external object that augments the
117 * explanation, such as a
118 * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
119 * or null.
120 */
121 public Adjustment(int importance, CharSequence explanation, Uri reference) {
122 mImportance = importance;
123 mExplanation = explanation;
124 mReference = reference;
125 }
126 }
127
128 @Override
129 public IBinder onBind(Intent intent) {
130 if (mWrapper == null) {
131 mWrapper = new NotificationAssistantWrapper();
132 }
133 return mWrapper;
134 }
135
Chris Wren9fa689f2015-11-20 16:44:53 -0500136 /**
137 * A notification was posted by an app. Called before alert.
138 *
139 * @param sbn the new notification
140 * @param importance the initial importance of the notification.
141 * @param user true if the initial importance reflects an explicit user preference.
142 * @return an adjustment or null to take no action, within 100ms.
143 */
Chris Wren51017d02015-12-15 15:34:46 -0500144 abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
Chris Wren9fa689f2015-11-20 16:44:53 -0500145 int importance, boolean user);
146
147 /**
148 * The visibility of a notification has changed.
149 *
150 * @param key the notification key
151 * @param time milliseconds since midnight, January 1, 1970 UTC.
152 * @param visible true if the notification became visible, false if hidden.
153 */
154 public void onNotificationVisibilityChanged(String key, long time, boolean visible)
155 {
156 // Do nothing, Override this to collect visibility statistics.
157 }
158
159 /**
160 * The user clicked on a notification.
161 *
162 * @param key the notification key
163 * @param time milliseconds since midnight, January 1, 1970 UTC.
164 */
165 public void onNotificationClick(String key, long time)
166 {
167 // Do nothing, Override this to collect click statistics
168 }
169
170 /**
171 * The user clicked on a notification action.
172 *
173 * @param key the notification key
174 * @param time milliseconds since midnight, January 1, 1970 UTC.
175 * @param actionIndex the index of the action button that was pressed.
176 */
177 public void onNotificationActionClick(String key, long time, int actionIndex)
178 {
179 // Do nothing, Override this to collect action button click statistics
180 }
181
182 /**
183 * A notification was removed.
184
185 * @param key the notification key
186 * @param time milliseconds since midnight, January 1, 1970 UTC.
187 * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
188 */
189 public void onNotificationRemoved(String key, long time, int reason) {
190 // Do nothing, Override this to collect dismissal statistics
191 }
192
193 /**
194 * Change the importance of an existing notification. N.B. this won’t cause
195 * an existing notification to alert, but might allow a future update to
196 * this notification to alert.
197 *
198 * @param key the notification key
199 * @param adjustment the new importance with an explanation
200 */
Chris Wren51017d02015-12-15 15:34:46 -0500201 public final void adjustImportance(String key, Adjustment adjustment)
Chris Wren9fa689f2015-11-20 16:44:53 -0500202 {
Chris Wren51017d02015-12-15 15:34:46 -0500203 if (!isBound()) return;
204 try {
205 getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
206 adjustment.mImportance, adjustment.mExplanation);
207 } catch (android.os.RemoteException ex) {
208 Log.v(TAG, "Unable to contact notification manager", ex);
209 }
Chris Wren9fa689f2015-11-20 16:44:53 -0500210 }
211
Chris Wren51017d02015-12-15 15:34:46 -0500212 private class NotificationAssistantWrapper extends NotificationListenerWrapper {
213 @Override
214 public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
215 int importance, boolean user) throws RemoteException {
216 StatusBarNotification sbn;
217 try {
218 sbn = sbnHolder.get();
219 } catch (RemoteException e) {
220 Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
221 return;
222 }
223
224 try {
225 Adjustment adjustment =
226 NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
227 if (adjustment != null) {
228 adjustImportance(sbn.getKey(), adjustment);
229 }
230 } catch (Throwable t) {
231 Log.w(TAG, "Error running onNotificationEnqueued", t);
232 }
233 }
234
235 @Override
236 public void onNotificationVisibilityChanged(String key, long time, boolean visible)
237 throws RemoteException {
238 try {
239 NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
240 visible);
241 } catch (Throwable t) {
242 Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
243 }
244 }
245
246 @Override
247 public void onNotificationClick(String key, long time) throws RemoteException {
248 try {
249 NotificationAssistantService.this.onNotificationClick(key, time);
250 } catch (Throwable t) {
251 Log.w(TAG, "Error running onNotificationClick", t);
252 }
253 }
254
255 @Override
256 public void onNotificationActionClick(String key, long time, int actionIndex)
257 throws RemoteException {
258 try {
259 NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
260 } catch (Throwable t) {
261 Log.w(TAG, "Error running onNotificationActionClick", t);
262 }
263 }
264
265 @Override
266 public void onNotificationRemovedReason(String key, long time, int reason)
267 throws RemoteException {
268 try {
269 NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
270 } catch (Throwable t) {
271 Log.w(TAG, "Error running onNotificationRemoved", t);
272 }
273 }
274 }
Chris Wren9fa689f2015-11-20 16:44:53 -0500275}