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