NotificationAssistantService.java revision 7eadc1bf686de4df0801252263c887ed2c326090
1/* 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 19import android.annotation.SdkConstant; 20import android.annotation.SystemApi; 21import android.app.INotificationManager; 22import android.app.Notification; 23import android.content.ComponentName; 24import android.content.Context; 25import android.content.Intent; 26import android.net.Uri; 27import android.os.IBinder; 28import android.os.Parcel; 29import android.os.Parcelable; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.util.Log; 33 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 * <service android:name=".NotificationAssistant" 42 * android:label="@string/service_name" 43 * android:permission="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"> 44 * <intent-filter> 45 * <action android:name="android.service.notification.NotificationAssistantService" /> 46 * </intent-filter> 47 * </service></pre> 48 */ 49public abstract class NotificationAssistantService extends NotificationListenerService { 50 private static final String TAG = "NotificationAssistant"; 51 52 /** 53 * The {@link Intent} that must be declared as handled by the service. 54 */ 55 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 56 public static final String SERVICE_INTERFACE 57 = "android.service.notification.NotificationAssistantService"; 58 59 /** Notification was canceled by the status bar reporting a click. */ 60 public static final int REASON_DELEGATE_CLICK = 1; 61 62 /** Notification was canceled by the status bar reporting a user dismissal. */ 63 public static final int REASON_DELEGATE_CANCEL = 2; 64 65 /** Notification was canceled by the status bar reporting a user dismiss all. */ 66 public static final int REASON_DELEGATE_CANCEL_ALL = 3; 67 68 /** Notification was canceled by the status bar reporting an inflation error. */ 69 public static final int REASON_DELEGATE_ERROR = 4; 70 71 /** Notification was canceled by the package manager modifying the package. */ 72 public static final int REASON_PACKAGE_CHANGED = 5; 73 74 /** Notification was canceled by the owning user context being stopped. */ 75 public static final int REASON_USER_STOPPED = 6; 76 77 /** Notification was canceled by the user banning the package. */ 78 public static final int REASON_PACKAGE_BANNED = 7; 79 80 /** Notification was canceled by the app canceling this specific notification. */ 81 public static final int REASON_APP_CANCEL = 8; 82 83 /** Notification was canceled by the app cancelling all its notifications. */ 84 public static final int REASON_APP_CANCEL_ALL = 9; 85 86 /** Notification was canceled by a listener reporting a user dismissal. */ 87 public static final int REASON_LISTENER_CANCEL = 10; 88 89 /** Notification was canceled by a listener reporting a user dismiss all. */ 90 public static final int REASON_LISTENER_CANCEL_ALL = 11; 91 92 /** Notification was canceled because it was a member of a canceled group. */ 93 public static final int REASON_GROUP_SUMMARY_CANCELED = 12; 94 95 /** Notification was canceled because it was an invisible member of a group. */ 96 public static final int REASON_GROUP_OPTIMIZATION = 13; 97 98 /** Notification was canceled by the user banning the topic. */ 99 public static final int REASON_TOPIC_BANNED = 14; 100 101 /** Notification was canceled by the device administrator suspending the package. */ 102 public static final int REASON_PACKAGE_SUSPENDED = 15; 103 104 /** Notification was canceled by the owning managed profile being turned off. */ 105 public static final int REASON_PROFILE_TURNED_OFF = 16; 106 107 public class Adjustment { 108 int mImportance; 109 CharSequence mExplanation; 110 Uri mReference; 111 112 /** 113 * Create a notification importance adjustment. 114 * 115 * @param importance The final importance of the notification. 116 * @param explanation A human-readable justification for the adjustment. 117 * @param reference A reference to an external object that augments the 118 * explanation, such as a 119 * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, 120 * or null. 121 */ 122 public Adjustment(int importance, CharSequence explanation, Uri reference) { 123 mImportance = importance; 124 mExplanation = explanation; 125 mReference = reference; 126 } 127 } 128 129 @Override 130 public IBinder onBind(Intent intent) { 131 if (mWrapper == null) { 132 mWrapper = new NotificationAssistantWrapper(); 133 } 134 return mWrapper; 135 } 136 137 /** 138 * A notification was posted by an app. Called before alert. 139 * 140 * @param sbn the new notification 141 * @param importance the initial importance of the notification. 142 * @param user true if the initial importance reflects an explicit user preference. 143 * @return an adjustment or null to take no action, within 100ms. 144 */ 145 abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn, 146 int importance, boolean user); 147 148 /** 149 * The visibility of a notification has changed. 150 * 151 * @param key the notification key 152 * @param time milliseconds since midnight, January 1, 1970 UTC. 153 * @param visible true if the notification became visible, false if hidden. 154 */ 155 public void onNotificationVisibilityChanged(String key, long time, boolean visible) 156 { 157 // Do nothing, Override this to collect visibility statistics. 158 } 159 160 /** 161 * The user clicked on a notification. 162 * 163 * @param key the notification key 164 * @param time milliseconds since midnight, January 1, 1970 UTC. 165 */ 166 public void onNotificationClick(String key, long time) 167 { 168 // Do nothing, Override this to collect click statistics 169 } 170 171 /** 172 * The user clicked on a notification action. 173 * 174 * @param key the notification key 175 * @param time milliseconds since midnight, January 1, 1970 UTC. 176 * @param actionIndex the index of the action button that was pressed. 177 */ 178 public void onNotificationActionClick(String key, long time, int actionIndex) 179 { 180 // Do nothing, Override this to collect action button click statistics 181 } 182 183 /** 184 * A notification was removed. 185 186 * @param key the notification key 187 * @param time milliseconds since midnight, January 1, 1970 UTC. 188 * @param reason see {@link #REASON_LISTENER_CANCEL}, etc. 189 */ 190 public void onNotificationRemoved(String key, long time, int reason) { 191 // Do nothing, Override this to collect dismissal statistics 192 } 193 194 /** 195 * Change the importance of an existing notification. N.B. this won’t cause 196 * an existing notification to alert, but might allow a future update to 197 * this notification to alert. 198 * 199 * @param key the notification key 200 * @param adjustment the new importance with an explanation 201 */ 202 public final void adjustImportance(String key, Adjustment adjustment) 203 { 204 if (!isBound()) return; 205 try { 206 getNotificationInterface().setImportanceFromAssistant(mWrapper, key, 207 adjustment.mImportance, adjustment.mExplanation); 208 } catch (android.os.RemoteException ex) { 209 Log.v(TAG, "Unable to contact notification manager", ex); 210 } 211 } 212 213 /** 214 * Add an annotation to a an existing notification. The delete intent will 215 * be fired when the host notification is deleted, or when this annotation 216 * is removed or replaced. 217 * 218 * @param key the key of the notification to be annotated 219 * @param annotation the new annotation object 220 */ 221 public final void setAnnotation(String key, Notification annotation) 222 { 223 // TODO: pack up the annotation and send it to the NotificationManager. 224 } 225 226 /** 227 * Remove the annotation from a notification. 228 * 229 * @param key the key of the notification to be cleansed of annotatons 230 */ 231 public final void clearAnnotation(String key) 232 { 233 // TODO: ask the NotificationManager to clear the annotation. 234 } 235 236 private class NotificationAssistantWrapper extends NotificationListenerWrapper { 237 @Override 238 public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder, 239 int importance, boolean user) throws RemoteException { 240 StatusBarNotification sbn; 241 try { 242 sbn = sbnHolder.get(); 243 } catch (RemoteException e) { 244 Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e); 245 return; 246 } 247 248 try { 249 Adjustment adjustment = 250 NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user); 251 if (adjustment != null) { 252 adjustImportance(sbn.getKey(), adjustment); 253 } 254 } catch (Throwable t) { 255 Log.w(TAG, "Error running onNotificationEnqueued", t); 256 } 257 } 258 259 @Override 260 public void onNotificationVisibilityChanged(String key, long time, boolean visible) 261 throws RemoteException { 262 try { 263 NotificationAssistantService.this.onNotificationVisibilityChanged(key, time, 264 visible); 265 } catch (Throwable t) { 266 Log.w(TAG, "Error running onNotificationVisibilityChanged", t); 267 } 268 } 269 270 @Override 271 public void onNotificationClick(String key, long time) throws RemoteException { 272 try { 273 NotificationAssistantService.this.onNotificationClick(key, time); 274 } catch (Throwable t) { 275 Log.w(TAG, "Error running onNotificationClick", t); 276 } 277 } 278 279 @Override 280 public void onNotificationActionClick(String key, long time, int actionIndex) 281 throws RemoteException { 282 try { 283 NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex); 284 } catch (Throwable t) { 285 Log.w(TAG, "Error running onNotificationActionClick", t); 286 } 287 } 288 289 @Override 290 public void onNotificationRemovedReason(String key, long time, int reason) 291 throws RemoteException { 292 try { 293 NotificationAssistantService.this.onNotificationRemoved(key, time, reason); 294 } catch (Throwable t) { 295 Log.w(TAG, "Error running onNotificationRemoved", t); 296 } 297 } 298 } 299} 300