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 * &lt;service android:name=".NotificationListener"
3504667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main *          android:label="&#64;string/service_name"
3604667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main *          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
3704667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main *     &lt;intent-filter>
3804667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main *         &lt;action android:name="android.service.notification.NotificationListenerService" />
3904667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main *     &lt;/intent-filter>
4004667dae3a5e45257c12d11dbcb4fc353a18d842Scott Main * &lt;/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