15feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler/* 25feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Copyright (C) 2013 The Android Open Source Project 35feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 45feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Licensed under the Apache License, Version 2.0 (the "License"); 55feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * you may not use this file except in compliance with the License. 65feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * You may obtain a copy of the License at 75feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 85feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * http://www.apache.org/licenses/LICENSE-2.0 95feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 105feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Unless required by applicable law or agreed to in writing, software 115feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * distributed under the License is distributed on an "AS IS" BASIS, 125feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * See the License for the specific language governing permissions and 145feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * limitations under the License. 155feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 165feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 175feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerpackage android.service.notification; 185feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 195feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.annotation.SdkConstant; 205feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.app.INotificationManager; 215feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.app.Service; 225feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.content.Context; 235feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.content.Intent; 245feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.os.IBinder; 255feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.os.ServiceManager; 265feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerimport android.util.Log; 275feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 2804667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main/** 2904667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * A service that receives calls from the system when new notifications are posted or removed. 3004667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * <p>To extend this class, you must declare the service in your manifest file with 3104667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission 3204667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> 3304667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * <pre> 3404667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * <service android:name=".NotificationListener" 3504667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * android:label="@string/service_name" 3604667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> 3704667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * <intent-filter> 3804667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * <action android:name="android.service.notification.NotificationListenerService" /> 3904667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * </intent-filter> 4004667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * </service></pre> 4104667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main */ 425feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandlerpublic abstract class NotificationListenerService extends Service { 435feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler // TAG = "NotificationListenerService[MySubclass]" 445feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler private final String TAG = NotificationListenerService.class.getSimpleName() 455feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler + "[" + getClass().getSimpleName() + "]"; 465feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 475feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler private INotificationListenerWrapper mWrapper = null; 485feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 495feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler private INotificationManager mNoMan; 505feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 515feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler /** 525feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * The {@link Intent} that must be declared as handled by the service. 535feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 545feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 555feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public static final String SERVICE_INTERFACE 565feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler = "android.service.notification.NotificationListenerService"; 575feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 585feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler /** 595feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Implement this method to learn about new notifications as they are posted by apps. 605feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 615feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * @param sbn A data structure encapsulating the original {@link android.app.Notification} 625feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * object as well as its identifying information (tag and id) and source 635feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * (package name). 645feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 655feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public abstract void onNotificationPosted(StatusBarNotification sbn); 665feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 675feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler /** 685feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Implement this method to learn when notifications are removed. 695feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * <P> 705feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * This might occur because the user has dismissed the notification using system UI (or another 715feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * notification listener) or because the app has withdrawn the notification. 721a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * <P> 731a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the 7404667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight 751a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * fields such as {@link android.app.Notification#contentView} and 761a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * {@link android.app.Notification#largeIcon}. However, all other fields on 771a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * {@link StatusBarNotification}, sufficient to match this call with a prior call to 781a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. 795feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 801a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * @param sbn A data structure encapsulating at least the original information (tag and id) 811a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * and source (package name) used to post the {@link android.app.Notification} that 821a497d3a2b1496c12949e47e55f8e46d8f585be5Daniel Sandler * was just removed. 835feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 845feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public abstract void onNotificationRemoved(StatusBarNotification sbn); 855feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 865feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler private final INotificationManager getNotificationInterface() { 875feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler if (mNoMan == null) { 885feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler mNoMan = INotificationManager.Stub.asInterface( 895feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler ServiceManager.getService(Context.NOTIFICATION_SERVICE)); 905feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 915feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler return mNoMan; 925feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 935feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 945feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler /** 955feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Inform the notification manager about dismissal of a single notification. 965feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * <p> 975feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Use this if your listener has a user interface that allows the user to dismiss individual 985feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * notifications, similar to the behavior of Android's status bar and notification panel. 995feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * It should be called after the user dismisses a single notification using your UI; 1005feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * upon being informed, the notification manager will actually remove the notification 1015feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. 1025feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * <P> 1035feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * <b>Note:</b> If your listener allows the user to fire a notification's 1045feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call 1055feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * this method at that time <i>if</i> the Notification in question has the 1065feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set. 1075feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 1085feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * @param pkg Package of the notifying app. 1095feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * @param tag Tag of the notification as specified by the notifying app in 1105feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. 1115feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * @param id ID of the notification as specified by the notifying app in 1125feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. 1135feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 114e6f7f2e3a01b8deb00e03ccfa93751c315f14ef0Daniel Sandler public final void cancelNotification(String pkg, String tag, int id) { 1155feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler try { 116e6f7f2e3a01b8deb00e03ccfa93751c315f14ef0Daniel Sandler getNotificationInterface().cancelNotificationFromListener(mWrapper, pkg, tag, id); 1175feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } catch (android.os.RemoteException ex) { 1185feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler Log.v(TAG, "Unable to contact notification manager", ex); 1195feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1205feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1215feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 1225feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler /** 1235feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Inform the notification manager about dismissal of all notifications. 1245feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * <p> 1255feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * Use this if your listener has a user interface that allows the user to dismiss all 1265feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * notifications, similar to the behavior of Android's status bar and notification panel. 1275feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * It should be called after the user invokes the "dismiss all" function of your UI; 1285feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * upon being informed, the notification manager will actually remove all active notifications 1295feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks. 1305feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler * 131e6f7f2e3a01b8deb00e03ccfa93751c315f14ef0Daniel Sandler * {@see #cancelNotification(String, String, int)} 1325feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler */ 133e6f7f2e3a01b8deb00e03ccfa93751c315f14ef0Daniel Sandler public final void cancelAllNotifications() { 1345feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler try { 135e6f7f2e3a01b8deb00e03ccfa93751c315f14ef0Daniel Sandler getNotificationInterface().cancelAllNotificationsFromListener(mWrapper); 1365feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } catch (android.os.RemoteException ex) { 1375feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler Log.v(TAG, "Unable to contact notification manager", ex); 1385feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1395feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1405feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 14125cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler /** 14225cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler * Request the list of outstanding notifications (that is, those that are visible to the 14325cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler * current user). Useful when starting up and you don't know what's already been posted. 14425cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler * 14525cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler * @return An array of active notifications. 14625cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler */ 14725cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler public StatusBarNotification[] getActiveNotifications() { 14825cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler try { 14925cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler return getNotificationInterface().getActiveNotificationsFromListener(mWrapper); 15025cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler } catch (android.os.RemoteException ex) { 15125cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler Log.v(TAG, "Unable to contact notification manager", ex); 15225cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler } 15325cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler return null; 15425cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler } 15525cf8cee6f304a286d321204e448b18ce733a60cDaniel Sandler 1565feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler @Override 1575feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public IBinder onBind(Intent intent) { 1585feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler if (mWrapper == null) { 1595feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler mWrapper = new INotificationListenerWrapper(); 1605feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1615feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler return mWrapper; 1625feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1635feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler 1645feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler private class INotificationListenerWrapper extends INotificationListener.Stub { 1655feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler @Override 1665feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public void onNotificationPosted(StatusBarNotification sbn) { 167c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock try { 168c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock NotificationListenerService.this.onNotificationPosted(sbn); 169c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock } catch (Throwable t) { 170c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock Log.w(TAG, "Error running onNotificationPosted", t); 171c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock } 1725feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1735feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler @Override 1745feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler public void onNotificationRemoved(StatusBarNotification sbn) { 175c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock try { 176c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock NotificationListenerService.this.onNotificationRemoved(sbn); 177c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock } catch (Throwable t) { 178c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock Log.w(TAG, "Error running onNotificationRemoved", t); 179c133ab8258f8e976f402d57456b1f06d11a78b03John Spurlock } 1805feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1815feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler } 1825feceebb892d4cb5777cea3c6174b206705d456bDaniel Sandler} 183