/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.service.notification; import android.annotation.SdkConstant; import android.app.INotificationManager; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.ServiceManager; import android.util.Log; /** * A service that receives calls from the system when new notifications are posted or removed. *

To extend this class, you must declare the service in your manifest file with * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:

*
 * <service android:name=".NotificationListener"
 *          android:label="@string/service_name"
 *          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
 *     <intent-filter>
 *         <action android:name="android.service.notification.NotificationListenerService" />
 *     </intent-filter>
 * </service>
*/ public abstract class NotificationListenerService extends Service { // TAG = "NotificationListenerService[MySubclass]" private final String TAG = NotificationListenerService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; private INotificationListenerWrapper mWrapper = null; private INotificationManager mNoMan; /** * The {@link Intent} that must be declared as handled by the service. */ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; /** * Implement this method to learn about new notifications as they are posted by apps. * * @param sbn A data structure encapsulating the original {@link android.app.Notification} * object as well as its identifying information (tag and id) and source * (package name). */ public abstract void onNotificationPosted(StatusBarNotification sbn); /** * Implement this method to learn when notifications are removed. *

* This might occur because the user has dismissed the notification using system UI (or another * notification listener) or because the app has withdrawn the notification. *

* NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight * fields such as {@link android.app.Notification#contentView} and * {@link android.app.Notification#largeIcon}. However, all other fields on * {@link StatusBarNotification}, sufficient to match this call with a prior call to * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. * * @param sbn A data structure encapsulating at least the original information (tag and id) * and source (package name) used to post the {@link android.app.Notification} that * was just removed. */ public abstract void onNotificationRemoved(StatusBarNotification sbn); private final INotificationManager getNotificationInterface() { if (mNoMan == null) { mNoMan = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); } return mNoMan; } /** * Inform the notification manager about dismissal of a single notification. *

* Use this if your listener has a user interface that allows the user to dismiss individual * notifications, similar to the behavior of Android's status bar and notification panel. * It should be called after the user dismisses a single notification using your UI; * upon being informed, the notification manager will actually remove the notification * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. *

* Note: If your listener allows the user to fire a notification's * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call * this method at that time if the Notification in question has the * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set. * * @param pkg Package of the notifying app. * @param tag Tag of the notification as specified by the notifying app in * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. * @param id ID of the notification as specified by the notifying app in * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. */ public final void cancelNotification(String pkg, String tag, int id) { try { getNotificationInterface().cancelNotificationFromListener(mWrapper, pkg, tag, id); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); } } /** * Inform the notification manager about dismissal of all notifications. *

* Use this if your listener has a user interface that allows the user to dismiss all * notifications, similar to the behavior of Android's status bar and notification panel. * It should be called after the user invokes the "dismiss all" function of your UI; * upon being informed, the notification manager will actually remove all active notifications * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks. * * {@see #cancelNotification(String, String, int)} */ public final void cancelAllNotifications() { try { getNotificationInterface().cancelAllNotificationsFromListener(mWrapper); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); } } /** * Request the list of outstanding notifications (that is, those that are visible to the * current user). Useful when starting up and you don't know what's already been posted. * * @return An array of active notifications. */ public StatusBarNotification[] getActiveNotifications() { try { return getNotificationInterface().getActiveNotificationsFromListener(mWrapper); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); } return null; } @Override public IBinder onBind(Intent intent) { if (mWrapper == null) { mWrapper = new INotificationListenerWrapper(); } return mWrapper; } private class INotificationListenerWrapper extends INotificationListener.Stub { @Override public void onNotificationPosted(StatusBarNotification sbn) { try { NotificationListenerService.this.onNotificationPosted(sbn); } catch (Throwable t) { Log.w(TAG, "Error running onNotificationPosted", t); } } @Override public void onNotificationRemoved(StatusBarNotification sbn) { try { NotificationListenerService.this.onNotificationRemoved(sbn); } catch (Throwable t) { Log.w(TAG, "Error running onNotificationRemoved", t); } } } }