NotificationListenerService.java revision 3aa5f1eec08e6c3233f13935ea45c833433a2d27
108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller/*
208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * Copyright (C) 2013 The Android Open Source Project
308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller *
408fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * Licensed under the Apache License, Version 2.0 (the "License");
508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * you may not use this file except in compliance with the License.
608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * You may obtain a copy of the License at
708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller *
808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller *      http://www.apache.org/licenses/LICENSE-2.0
908fa40c5cb5229b7969b2a5146855a337870f45aJim Miller *
1008fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * Unless required by applicable law or agreed to in writing, software
1108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * distributed under the License is distributed on an "AS IS" BASIS,
1208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * See the License for the specific language governing permissions and
1408fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * limitations under the License.
1508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller */
1608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller
17ebbf205bc6e8292f74d8fc4652c70274a445f907Jim Millerpackage android.service.notification;
1808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller
19ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.os.Handler;
20ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.os.Looper;
21f501b58de8f467a80fef49c704555781bc61ea6fJim Millerimport android.os.Message;
2208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller
2308fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.annotation.IntDef;
24a7596147b43940cad3f76c53ed154ef088b9269bJim Millerimport android.annotation.SystemApi;
259f0753f5a378fc80da86305b33244acc6fc53f01Jim Millerimport android.annotation.SdkConstant;
26ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.app.INotificationManager;
2708fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.app.Notification;
2808fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.app.Notification.Builder;
29f501b58de8f467a80fef49c704555781bc61ea6fJim Millerimport android.app.NotificationManager;
3008fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.app.Service;
3108fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.content.ComponentName;
32dcdaf87ed0aa99073638bcfe645949f130f0c7adAlex Klyubinimport android.content.Context;
3308fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.content.Intent;
34a7596147b43940cad3f76c53ed154ef088b9269bJim Millerimport android.content.pm.ParceledListSlice;
3508fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.graphics.drawable.BitmapDrawable;
369f0753f5a378fc80da86305b33244acc6fc53f01Jim Millerimport android.graphics.drawable.Drawable;
37ba67aee02cf864793129976cd8a8a46e60c60577Jim Millerimport android.graphics.drawable.Icon;
38ba67aee02cf864793129976cd8a8a46e60c60577Jim Millerimport android.graphics.Bitmap;
399f0753f5a378fc80da86305b33244acc6fc53f01Jim Millerimport android.os.Build;
40b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Millerimport android.os.Bundle;
419f0753f5a378fc80da86305b33244acc6fc53f01Jim Millerimport android.os.IBinder;
42f501b58de8f467a80fef49c704555781bc61ea6fJim Millerimport android.os.Parcel;
43f501b58de8f467a80fef49c704555781bc61ea6fJim Millerimport android.os.Parcelable;
44f501b58de8f467a80fef49c704555781bc61ea6fJim Millerimport android.os.RemoteException;
4508fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.os.ServiceManager;
4608fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport android.util.ArrayMap;
47ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.util.ArraySet;
48ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.util.Log;
49ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport android.widget.RemoteViews;
50ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerimport com.android.internal.annotations.GuardedBy;
5108fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport com.android.internal.os.SomeArgs;
5208fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport java.lang.annotation.Retention;
5308fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport java.lang.annotation.RetentionPolicy;
5408fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport java.util.ArrayList;
55d08c2aceb238b02d8348518a2c87693054c6ce37Jim Millerimport java.util.Collections;
5608fa40c5cb5229b7969b2a5146855a337870f45aJim Millerimport java.util.List;
57a7596147b43940cad3f76c53ed154ef088b9269bJim Miller
58f501b58de8f467a80fef49c704555781bc61ea6fJim Miller/**
59f501b58de8f467a80fef49c704555781bc61ea6fJim Miller * A service that receives calls from the system when new notifications are
60f501b58de8f467a80fef49c704555781bc61ea6fJim Miller * posted or removed, or their ranking changed.
61f501b58de8f467a80fef49c704555781bc61ea6fJim Miller * <p>To extend this class, you must declare the service in your manifest file with
6208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
63ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
64ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * <pre>
65ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * &lt;service android:name=".NotificationListener"
66ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller *          android:label="&#64;string/service_name"
6708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller *          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
68ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller *     &lt;intent-filter>
69ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller *         &lt;action android:name="android.service.notification.NotificationListenerService" />
70ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller *     &lt;/intent-filter>
7108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller * &lt;/service></pre>
72ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller *
73ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * <p>The service should wait for the {@link #onListenerConnected()} event
74ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * before performing any operations. The {@link #requestRebind(ComponentName)}
75ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * method is the <i>only</i> one that is safe to call before {@link #onListenerConnected()}
76a7596147b43940cad3f76c53ed154ef088b9269bJim Miller * or after {@link #onListenerDisconnected()}.
77ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller * </p>
78ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller */
79ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Millerpublic abstract class NotificationListenerService extends Service {
80ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
81ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    // TAG = "NotificationListenerService[MySubclass]"
82ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    private final String TAG = NotificationListenerService.class.getSimpleName()
8308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            + "[" + getClass().getSimpleName() + "]";
84ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
85ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
86ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
87ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     Normal interruption filter.
88ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
8908fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    public static final int INTERRUPTION_FILTER_ALL
90ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            = NotificationManager.INTERRUPTION_FILTER_ALL;
91ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
92ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
93ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
94ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     Priority interruption filter.
95ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
969f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public static final int INTERRUPTION_FILTER_PRIORITY
97ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            = NotificationManager.INTERRUPTION_FILTER_PRIORITY;
98ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
99ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
100ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
101ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     No interruptions filter.
102ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
103ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int INTERRUPTION_FILTER_NONE
104ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            = NotificationManager.INTERRUPTION_FILTER_NONE;
105ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
106fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller    /**
107fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
108fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     *     Alarms only interruption filter.
109fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     */
110fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller    public static final int INTERRUPTION_FILTER_ALARMS
111ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            = NotificationManager.INTERRUPTION_FILTER_ALARMS;
112ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
113ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
114f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * the value is unavailable for any reason.  For example, before the notification listener
115ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * is connected.
1169f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
11708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * {@see #onListenerConnected()}
118ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
119ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int INTERRUPTION_FILTER_UNKNOWN
120ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            = NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
121ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
122ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
123ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * should disable notification sound, vibrating and other visual or aural effects.
124ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This does not change the interruption filter, only the effects. **/
125a7596147b43940cad3f76c53ed154ef088b9269bJim Miller    public static final int HINT_HOST_DISABLE_EFFECTS = 1;
126ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
127ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
128ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * should disable notification sound, but not phone calls.
129ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This does not change the interruption filter, only the effects. **/
130ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 1 << 1;
131a7596147b43940cad3f76c53ed154ef088b9269bJim Miller
132ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
133ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * should disable phone call sounds, buyt not notification sound.
134ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This does not change the interruption filter, only the effects. **/
135ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 1 << 2;
136ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
137a7596147b43940cad3f76c53ed154ef088b9269bJim Miller    /**
138ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Whether notification suppressed by DND should not interruption visually when the screen is
139ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * off.
140ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
141ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int SUPPRESSED_EFFECT_SCREEN_OFF =
142ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
143ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
144ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Whether notification suppressed by DND should not interruption visually when the screen is
145ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * on.
1469f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
147ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int SUPPRESSED_EFFECT_SCREEN_ON =
148ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
149ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
150ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
151ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    // Notification cancellation reasons
1529f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
153ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the status bar reporting a click. */
154ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_DELEGATE_CLICK = 1;
155ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the status bar reporting a user dismissal. */
156ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_DELEGATE_CANCEL = 2;
157ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the status bar reporting a user dismiss all. */
158ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_DELEGATE_CANCEL_ALL = 3;
159ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the status bar reporting an inflation error. */
1609f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public static final int REASON_DELEGATE_ERROR = 4;
161ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the package manager modifying the package. */
162ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_PACKAGE_CHANGED = 5;
163ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the owning user context being stopped. */
164ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_USER_STOPPED = 6;
165f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /** Notification was canceled by the user banning the package. */
166ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_PACKAGE_BANNED = 7;
1679f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /** Notification was canceled by the app canceling this specific notification. */
168a7596147b43940cad3f76c53ed154ef088b9269bJim Miller    public static final int REASON_APP_CANCEL = 8;
16908fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    /** Notification was canceled by the app cancelling all its notifications. */
170d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller    public static final int REASON_APP_CANCEL_ALL = 9;
171a7596147b43940cad3f76c53ed154ef088b9269bJim Miller    /** Notification was canceled by a listener reporting a user dismissal. */
1729f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public static final int REASON_LISTENER_CANCEL = 10;
1739f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /** Notification was canceled by a listener reporting a user dismiss all. */
1749f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public static final int REASON_LISTENER_CANCEL_ALL = 11;
1759f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /** Notification was canceled because it was a member of a canceled group. */
1769f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public static final int REASON_GROUP_SUMMARY_CANCELED = 12;
177f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /** Notification was canceled because it was an invisible member of a group. */
178ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_GROUP_OPTIMIZATION = 13;
179ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the device administrator suspending the package. */
180ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_PACKAGE_SUSPENDED = 14;
181ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the owning managed profile being turned off. */
182fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller    public static final int REASON_PROFILE_TURNED_OFF = 15;
183ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Autobundled summary notification was canceled because its group was unbundled */
184ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_UNAUTOBUNDLED = 16;
185ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was canceled by the user banning the channel. */
186ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_CHANNEL_BANNED = 17;
187ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification was snoozed. */
188ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_SNOOZED = 18;
189ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** Notification no longer visible because of user switch */
190ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int REASON_USER_SWITCH = 19;
191ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
192ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
193ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * The full trim of the StatusBarNotification including all its features.
194ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
195ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @hide
196ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
197ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    @SystemApi
19808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    public static final int TRIM_FULL = 0;
1999f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
200ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
201b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * A light trim of the StatusBarNotification excluding the following features:
2029f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
203f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * <ol>
204ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     <li>{@link Notification#tickerView tickerView}</li>
205b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     *     <li>{@link Notification#contentView contentView}</li>
206f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *     <li>{@link Notification#largeIcon largeIcon}</li>
207ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     <li>{@link Notification#bigContentView bigContentView}</li>
208ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     <li>{@link Notification#headsUpContentView headsUpContentView}</li>
209b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     *     <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
210f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *     <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
211b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     *     <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
212b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     *     <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li>
213b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * </ol>
214f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *
215ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @hide
216ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
217ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    @SystemApi
218ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public static final int TRIM_LIGHT = 1;
219ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
220ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    private final Object mLock = new Object();
221f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
222f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    private Handler mHandler;
223f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
224ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** @hide */
225ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    protected NotificationListenerWrapper mWrapper = null;
226ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    private boolean isConnected = false;
227ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
228ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    @GuardedBy("mLock")
229f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    private RankingMap mRankingMap;
230f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
231f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    private INotificationManager mNoMan;
232ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
233ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
234b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * Only valid after a successful call to (@link registerAsService}.
235b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * @hide
236b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     */
237f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    protected int mCurrentUser;
238f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
239f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /**
240b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * This context is required for system services since NotificationListenerService isn't
241b62dc82b0c7208f106077b46fc7118da6baa6e13Jim Miller     * started as a real Service and hence no context is available..
242ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @hide
243ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
244ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    protected Context mSystemContext;
245ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
246f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /**
247f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * The {@link Intent} that must be declared as handled by the service.
248ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
249ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
250f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public static final String SERVICE_INTERFACE
25108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            = "android.service.notification.NotificationListenerService";
25208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller
2539f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    @Override
2549f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    protected void attachBaseContext(Context base) {
255f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        super.attachBaseContext(base);
2569f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        mHandler = new MyHandler(getMainLooper());
2579f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
2589f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
2599f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
2609f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Implement this method to learn about new notifications as they are posted by apps.
261f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *
262f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
263f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *            object as well as its identifying information (tag and id) and source
264f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *            (package name).
265f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     */
266f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public void onNotificationPosted(StatusBarNotification sbn) {
267f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        // optional
2689f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
2699f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
2709f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
271ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     * Implement this method to learn about new notifications as they are posted by apps.
2729f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
2739f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
2749f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *            object as well as its identifying information (tag and id) and source
2759f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *            (package name).
276f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @param rankingMap The current ranking map that can be used to retrieve ranking information
2779f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *                   for active notifications, including the newly posted one.
2789f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
2799f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
2809f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        onNotificationPosted(sbn);
281ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
282ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
283ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
2849f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Implement this method to learn when notifications are removed.
2859f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
2869f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * This might occur because the user has dismissed the notification using system UI (or another
2879f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * notification listener) or because the app has withdrawn the notification.
288ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     * <p>
28906e658f324a937bec1c5ddbe9c3100c3d2fec371Jim Miller     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
2909f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
291f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * fields such as {@link android.app.Notification#contentView} and
292ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link android.app.Notification#largeIcon}. However, all other fields on
293f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
294ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
29506e658f324a937bec1c5ddbe9c3100c3d2fec371Jim Miller     *
2969f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param sbn A data structure encapsulating at least the original information (tag and id)
2979f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *            and source (package name) used to post the {@link android.app.Notification} that
2989f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *            was just removed.
2999f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
300f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public void onNotificationRemoved(StatusBarNotification sbn) {
301ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        // optional
3029f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
303f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
30408fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    /**
3059f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Implement this method to learn when notifications are removed.
306ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
3079f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * This might occur because the user has dismissed the notification using system UI (or another
3089f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * notification listener) or because the app has withdrawn the notification.
309f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * <p>
310ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
3119f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
312f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * fields such as {@link android.app.Notification#contentView} and
31308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * {@link android.app.Notification#largeIcon}. However, all other fields on
3149f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
3159f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
316ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
3179f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param sbn A data structure encapsulating at least the original information (tag and id)
318ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *            and source (package name) used to post the {@link android.app.Notification} that
319ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *            was just removed.
320ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param rankingMap The current ranking map that can be used to retrieve ranking information
321ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *                   for active notifications.
322ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
323ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
3249f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
32508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        onNotificationRemoved(sbn);
3269f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
3279f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3289f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3299f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
330f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Implement this method to learn when notifications are removed and why.
331ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
332ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This might occur because the user has dismissed the notification using system UI (or another
3339f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * notification listener) or because the app has withdrawn the notification.
3349f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
3359f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
3369f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
3379f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * fields such as {@link android.app.Notification#contentView} and
338ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link android.app.Notification#largeIcon}. However, all other fields on
339ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
3409f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
341ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
342a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     ** @param sbn A data structure encapsulating at least the original information (tag and id)
3439f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *            and source (package name) used to post the {@link android.app.Notification} that
344ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *            was just removed.
3459f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param rankingMap The current ranking map that can be used to retrieve ranking information
3469f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *                   for active notifications.
3479f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param reason see {@link #REASON_LISTENER_CANCEL}, etc.
348ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
349ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
3509f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            int reason) {
351ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        onNotificationRemoved(sbn, rankingMap);
35208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    }
3539f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3549f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
355ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Implement this method to learn about when the listener is enabled and connected to
3569f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * the notification manager.  You are safe to call {@link #getActiveNotifications()}
357ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * at this time.
3589f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
359ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public void onListenerConnected() {
3609f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        // optional
36108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    }
3629f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3639f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
3649f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Implement this method to learn about when the listener is disconnected from the
3659f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * notification manager.You will not receive any events after this call, and may only
3669f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * call {@link #requestRebind(ComponentName)} at this time.
367ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
368ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public void onListenerDisconnected() {
3699f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        // optional
3709f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
3719f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3729f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
373ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Implement this method to be notified when the notification ranking changes.
374ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
375ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param rankingMap The current ranking map that can be used to retrieve ranking information
3769f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *                   for active notifications.
377ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
3789f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public void onNotificationRankingUpdate(RankingMap rankingMap) {
3799f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        // optional
3809f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
3819f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3829f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
383ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Implement this method to be notified when the
38408fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * {@link #getCurrentListenerHints() Listener hints} change.
38508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     *
38608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * @param hints The current {@link #getCurrentListenerHints() listener hints}.
387ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
388ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public void onListenerHintsChanged(int hints) {
3899f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        // optional
3909f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
3919f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
3929f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
393d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller     * Implement this method to be notified when the
3949f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link #getCurrentInterruptionFilter() interruption filter} changed.
3959f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
396ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param interruptionFilter The current
397f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *     {@link #getCurrentInterruptionFilter() interruption filter}.
398f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     */
399d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller    public void onInterruptionFilterChanged(int interruptionFilter) {
400f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        // optional
401ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
402f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
403f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /** @hide */
404ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi    protected final INotificationManager getNotificationInterface() {
405ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi        if (mNoMan == null) {
406ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi            mNoMan = INotificationManager.Stub.asInterface(
407f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
408f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        }
409f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        return mNoMan;
410f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    }
411f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
412f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    /**
413f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Inform the notification manager about dismissal of a single notification.
414f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * <p>
415f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Use this if your listener has a user interface that allows the user to dismiss individual
416f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * notifications, similar to the behavior of Android's status bar and notification panel.
417f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * It should be called after the user dismisses a single notification using your UI;
418f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * upon being informed, the notification manager will actually remove the notification
419f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
420ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi     * <p>
421ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi     * <b>Note:</b> If your listener allows the user to fire a notification's
422f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
423ccdfa93f609d3f306a35902df323939e266a7ab3Jorim Jaggi     * this method at that time <i>if</i> the Notification in question has the
424f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
4259f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
4269f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
4279f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * before performing this operation.
4289f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
429ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param pkg Package of the notifying app.
430ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param tag Tag of the notification as specified by the notifying app in
431ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
432ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param id  ID of the notification as specified by the notifying app in
433ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
434ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
435ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @deprecated Use {@link #cancelNotification(String key)}
436ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * instead. Beginning with {@link android.os.Build.VERSION_CODES#LOLLIPOP} this method will no longer
4379f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * cancel the notification. It will continue to cancel the notification for applications
4389f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * whose {@code targetSdkVersion} is earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
439f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     */
4409f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    @Deprecated
4419f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public final void cancelNotification(String pkg, String tag, int id) {
442ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (!isBound()) return;
4434af76a51d5082c740609563e07cf35f30bc2224eSvetoslav        try {
4444af76a51d5082c740609563e07cf35f30bc2224eSvetoslav            getNotificationInterface().cancelNotificationFromListener(
4459f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    mWrapper, pkg, tag, id);
446ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        } catch (android.os.RemoteException ex) {
447ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
448ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        }
449ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
450ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
451ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
452ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Inform the notification manager about dismissal of a single notification.
4539f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
454d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller     * Use this if your listener has a user interface that allows the user to dismiss individual
455d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller     * notifications, similar to the behavior of Android's status bar and notification panel.
456d08c2aceb238b02d8348518a2c87693054c6ce37Jim Miller     * It should be called after the user dismisses a single notification using your UI;
4579f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * upon being informed, the notification manager will actually remove the notification
4589f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
4599f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
4609f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <b>Note:</b> If your listener allows the user to fire a notification's
4619f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
4629f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * this method at that time <i>if</i> the Notification in question has the
4639f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
464fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     * <p>
465fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     *
4669f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
4679f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * before performing this operation.
468f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *
469ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param key Notification to dismiss from {@link StatusBarNotification#getKey()}.
47008fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     */
471f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public final void cancelNotification(String key) {
472f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        if (!isBound()) return;
473f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        try {
4749f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            getNotificationInterface().cancelNotificationsFromListener(mWrapper,
4759f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    new String[] { key });
47608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        } catch (android.os.RemoteException ex) {
4779f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
478ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        }
479ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
480ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
481ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
482ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Inform the notification manager about dismissal of all notifications.
483fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     * <p>
484ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Use this if your listener has a user interface that allows the user to dismiss all
485ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * notifications, similar to the behavior of Android's status bar and notification panel.
4869f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * It should be called after the user invokes the "dismiss all" function of your UI;
48708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * upon being informed, the notification manager will actually remove all active notifications
4889f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks.
489fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller     *
490ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
491ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * before performing this operation.
492ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
493ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@see #cancelNotification(String, String, int)}
494ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
495ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public final void cancelAllNotifications() {
496ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        cancelNotifications(null /*all*/);
497ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
498ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
499ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
500ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Inform the notification manager about dismissal of specific notifications.
501ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
502ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Use this if your listener has a user interface that allows the user to dismiss
503ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * multiple notifications at once.
504ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
505ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
506f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * before performing this operation.
507ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
508ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param keys Notifications to dismiss, or {@code null} to dismiss all.
509ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
510ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@see #cancelNotification(String, String, int)}
51108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     */
512ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public final void cancelNotifications(String[] keys) {
51308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        if (!isBound()) return;
514ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        try {
51508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
51608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        } catch (android.os.RemoteException ex) {
51708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
5189f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
5199f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
5209f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
521ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
522ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Inform the notification manager about snoozing a specific notification.
5239f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
52408fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * Use this if your listener has a user interface that allows the user to snooze a notification
525f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * until a given time.  It should be called after the user snoozes a single notification using
5269f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * your UI; upon being informed, the notification manager will actually remove the notification
5279f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
5289f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * snoozing period expires, you will get a
5299f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
530ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * notification.
5319f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param key The key of the notification to snooze
532ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param snoozeUntil A time in the future, in milliseconds.
533ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
534ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public final void snoozeNotification(String key, long snoozeUntil) {
535ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (!isBound()) return;
536ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        try {
53708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            getNotificationInterface().snoozeNotificationFromListener(mWrapper, key, snoozeUntil);
53808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        } catch (android.os.RemoteException ex) {
53908fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
54008fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        }
5419f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
5429f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
5439f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
544ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Inform the notification manager that these notifications have been viewed by the
5459f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * user. This should only be called when there is sufficient confidence that the user is
54608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * looking at the notifications, such as when the notifications appear on the screen due to
547f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * an explicit user interaction.
5489f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
5499f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
55008fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * before performing this operation.
55108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     *
5529f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @param keys Notifications to mark as seen.
55308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     */
5549f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public final void setNotificationsShown(String[] keys) {
55508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        if (!isBound()) return;
556a7596147b43940cad3f76c53ed154ef088b9269bJim Miller        try {
5579f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            getNotificationInterface().setNotificationsShownFromListener(mWrapper, keys);
55808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        } catch (android.os.RemoteException ex) {
55908fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
56008fa40c5cb5229b7969b2a5146855a337870f45aJim Miller        }
5619f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
5629f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
5639f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
564ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Sets the notification trim that will be received via {@link #onNotificationPosted}.
565ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
5669f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
567f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
5682aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * full notification features right away to reduce their memory footprint. Full notifications
5699f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * can be requested on-demand via {@link #getActiveNotifications(int)}.
5704af76a51d5082c740609563e07cf35f30bc2224eSvetoslav     *
57108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * <p>
5729f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Set to {@link #TRIM_FULL} initially.
57308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     *
5749f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
57508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * before performing this operation.
57608fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     *
57708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * @hide
5782aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     *
5792aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
580ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *             See <code>TRIM_*</code> constants.
5819f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
58208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    @SystemApi
583f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public final void setOnNotificationPostedTrim(int trim) {
5842aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi        if (!isBound()) return;
5852aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi        try {
5862aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi            getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
5872aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi        } catch (RemoteException ex) {
5882aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi            Log.v(TAG, "Unable to contact notification manager", ex);
5892aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi        }
5902aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi    }
5912aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi
5922aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi    /**
593f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Request the list of outstanding notifications (that is, those that are visible to the
5942aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * current user). Useful when you don't know what's already been posted.
5952aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     *
5964af76a51d5082c740609563e07cf35f30bc2224eSvetoslav     * <p>The service should wait for the {@link #onListenerConnected()} event
5974af76a51d5082c740609563e07cf35f30bc2224eSvetoslav     * before performing this operation.
5982aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     *
5992aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * @return An array of active notifications, sorted in natural order.
6002aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     */
6012aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi    public StatusBarNotification[] getActiveNotifications() {
6022aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi        return getActiveNotifications(null, TRIM_FULL);
6032aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi    }
6042aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi
6052aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi    /**
6062aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * Request the list of outstanding notifications (that is, those that are visible to the
6072aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     * current user). Useful when you don't know what's already been posted.
6082aad7ee245857a46aae305fefc4e3c1bcdd4a586Jorim Jaggi     *
609f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @hide
6109f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
61108fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
61208fa40c5cb5229b7969b2a5146855a337870f45aJim Miller     * @return An array of active notifications, sorted in natural order.
6139f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
6144af76a51d5082c740609563e07cf35f30bc2224eSvetoslav    @SystemApi
61508fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    public StatusBarNotification[] getActiveNotifications(int trim) {
6169f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        return getActiveNotifications(null, trim);
61708fa40c5cb5229b7969b2a5146855a337870f45aJim Miller    }
61808fa40c5cb5229b7969b2a5146855a337870f45aJim Miller
6199f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
620a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     * Request one or more notifications by key. Useful if you have been keeping track of
6219f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * notifications but didn't want to retain the bits, and now need to go back and extract
622a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     * more data out of those notifications.
623a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     *
6244d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * <p>The service should wait for the {@link #onListenerConnected()} event
6254d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * before performing this operation.
6264d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     *
6274d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * @param keys the keys of the notifications to request
6284d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * @return An array of notifications corresponding to the requested keys, in the
6294d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * same order as the key list.
6304d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     */
6314d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales    public StatusBarNotification[] getActiveNotifications(String[] keys) {
6324d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales        return getActiveNotifications(keys, TRIM_FULL);
6334af76a51d5082c740609563e07cf35f30bc2224eSvetoslav    }
6344d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales
6354d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales    /**
6364d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * Request one or more notifications by key. Useful if you have been keeping track of
6374d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * notifications but didn't want to retain the bits, and now need to go back and extract
6384d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * more data out of those notifications.
6394d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     *
6404d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * @hide
6414d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     *
6424d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * @param keys the keys of the notifications to request
64324e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin     * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
64424e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin     * @return An array of notifications corresponding to the requested keys, in the
64524e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin     * same order as the key list.
64624e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin     */
64724e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin    @SystemApi
648f501b58de8f467a80fef49c704555781bc61ea6fJim Miller    public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
649f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        if (!isBound())
650f501b58de8f467a80fef49c704555781bc61ea6fJim Miller            return null;
651f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        try {
6529f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
6539f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    .getActiveNotificationsFromListener(mWrapper, keys, trim);
6549f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            List<StatusBarNotification> list = parceledList.getList();
6559f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            ArrayList<StatusBarNotification> corruptNotifications = null;
6569f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            int N = list.size();
6579f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            for (int i = 0; i < N; i++) {
6589f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                StatusBarNotification sbn = list.get(i);
6599f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                Notification notification = sbn.getNotification();
660f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                try {
661f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                    // convert icon metadata to legacy format for older clients
662f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                    createLegacyIconExtras(notification);
663f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                    // populate remote views for older clients.
664f501b58de8f467a80fef49c704555781bc61ea6fJim Miller                    maybePopulateRemoteViews(notification);
6659f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                } catch (IllegalArgumentException e) {
6669f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    if (corruptNotifications == null) {
6679f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                        corruptNotifications = new ArrayList<>(N);
6689f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    }
6699f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    corruptNotifications.add(sbn);
6709f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                    Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
6719f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                            sbn.getPackageName());
6729f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                }
67308fa40c5cb5229b7969b2a5146855a337870f45aJim Miller            }
6749f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            if (corruptNotifications != null) {
6759f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller                list.removeAll(corruptNotifications);
6769f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            }
6779f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            return list.toArray(new StatusBarNotification[list.size()]);
6789f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        } catch (android.os.RemoteException ex) {
6799f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
6809f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
6819f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        return null;
6829f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
6839f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
6849f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
6859f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Gets the set of hints representing current state.
686a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     *
687a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     * <p>
688a7596147b43940cad3f76c53ed154ef088b9269bJim Miller     * The current state may differ from the requested state if the hint represents state
6899f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * shared across all listeners or a feature the notification host does not support or refuses
6909f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * to grant.
6919f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
6929f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
6939f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * before performing this operation.
6949f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
6959f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @return Zero or more of the HINT_ constants.
6969f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
6979f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public final int getCurrentListenerHints() {
6989f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        if (!isBound()) return 0;
6999f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        try {
7009f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            return getNotificationInterface().getHintsFromListener(mWrapper);
7019f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        } catch (android.os.RemoteException ex) {
7029f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
7039f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            return 0;
7049f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
7059f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
706f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
7079f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
708f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Gets the current notification interruption filter active on the host.
709f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *
710f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * <p>
711f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * The interruption filter defines which notifications are allowed to interrupt the user
712f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * (e.g. via sound &amp; vibration) and is applied globally. Listeners can find out whether
713f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * a specific notification matched the interruption filter via
714f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * {@link Ranking#matchesInterruptionFilter()}.
715f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * <p>
7169f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * The current filter may differ from the previously requested filter if the notification host
7179f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * does not support or refuses to apply the requested filter, or if another component changed
7189f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * the filter in the meantime.
7199f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
7209f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
7219f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
7229f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
7239f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * before performing this operation.
7249f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
7259f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
7269f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * unavailable.
7279f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     */
7289f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public final int getCurrentInterruptionFilter() {
7299f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        if (!isBound()) return INTERRUPTION_FILTER_UNKNOWN;
730ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller        try {
731ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller            return getNotificationInterface().getInterruptionFilterFromListener(mWrapper);
732ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller        } catch (android.os.RemoteException ex) {
733ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
7349f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            return INTERRUPTION_FILTER_UNKNOWN;
7359f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
7369f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
7379f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
7389f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
7399f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Sets the desired {@link #getCurrentListenerHints() listener hints}.
74024e9e966a85c416a94482fcd10dbdd10ceeb9e6cAlex Klyubin     *
7419f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
7429f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * This is merely a request, the host may or may not choose to take action depending
7439f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * on other listener requests or other global state.
7449f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>
7459f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Listen for updates using {@link #onListenerHintsChanged(int)}.
7469f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
7479f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
7489f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * before performing this operation.
749ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     *
750ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     * @param hints One or more of the HINT_ constants.
751ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     */
752fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller    public final void requestListenerHints(int hints) {
753ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (!isBound()) return;
754ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        try {
755ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            getNotificationInterface().requestHintsFromListener(mWrapper, hints);
756ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        } catch (android.os.RemoteException ex) {
757ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
758ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        }
759ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
760ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
761ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
7624af76a51d5082c740609563e07cf35f30bc2224eSvetoslav     * Sets the desired {@link #getCurrentInterruptionFilter() interruption filter}.
763ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
764ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
765ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This is merely a request, the host may or may not choose to apply the requested
766ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * interruption filter depending on other listener requests or other global state.
767ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
768ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
769ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
770ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
771ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * before performing this operation.
772ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
773ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants.
774ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
775ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public final void requestInterruptionFilter(int interruptionFilter) {
776ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (!isBound()) return;
777ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        try {
778ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            getNotificationInterface()
779ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller                    .requestInterruptionFilterFromListener(mWrapper, interruptionFilter);
780fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller        } catch (android.os.RemoteException ex) {
781fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller            Log.v(TAG, "Unable to contact notification manager", ex);
782fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller        }
783fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller    }
784fe6439f02db3a541d77a7afb27e3bca1ae7493edJim Miller
785ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
786ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Returns current ranking information.
787ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
788ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
789ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * The returned object represents the current ranking snapshot and only
790ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * applies for currently active notifications.
791ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>
792ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * Generally you should use the RankingMap that is passed with events such
7939f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
794ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
795ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     * so on. This method should only be used when needing access outside of
796ba67aee02cf864793129976cd8a8a46e60c60577Jim Miller     * such events, for example to retrieve the RankingMap right after
79799d6019bead4705b7e126e65b856d538417d4934Jim Miller     * initialization.
798ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
799ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
800ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * before performing this operation.
801ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
802ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * @return A {@link RankingMap} object providing access to ranking information
803ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
804ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public RankingMap getCurrentRanking() {
805ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        synchronized (mLock) {
806ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            return mRankingMap;
807ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        }
808ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
809ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
810ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /**
811ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * This is not the lifecycle event you are looking for.
812ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     *
813ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * <p>The service should wait for the {@link #onListenerConnected()} event
814ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     * before performing any operations.
815ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller     */
816ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    @Override
817ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    public IBinder onBind(Intent intent) {
818ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (mWrapper == null) {
819ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller            mWrapper = new NotificationListenerWrapper();
820ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        }
821ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        return mWrapper;
822ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    }
823ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller
824ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller    /** @hide */
8259f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    protected boolean isBound() {
826ce7eb6daf06a88129da365eb2112537ce0bb1b75Jim Miller        if (mWrapper == null) {
82799d6019bead4705b7e126e65b856d538417d4934Jim Miller            Log.w(TAG, "Notification listener service not yet bound.");
82899d6019bead4705b7e126e65b856d538417d4934Jim Miller            return false;
8299f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
8309f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        return true;
8319f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
832f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
8339f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    @Override
8349f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public void onDestroy() {
8359f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        onListenerDisconnected();
8369f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        super.onDestroy();
8379f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
838f501b58de8f467a80fef49c704555781bc61ea6fJim Miller
8399f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    /**
8409f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * Directly register this service with the Notification Manager.
8419f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     *
8429f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller     * <p>Only system services may use this call. It will fail for non-system callers.
843f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * Apps should ask the user to add their listener in Settings.
844f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *
845f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @param context Context required for accessing resources. Since this service isn't
846f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     *    launched as a real Service when using this method, a context has to be passed in.
847f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @param componentName the component that will consume the notification information
848f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @param currentUser the user to use as the stream filter
849f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     * @hide
850f501b58de8f467a80fef49c704555781bc61ea6fJim Miller     */
8519f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    @SystemApi
8529f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    public void registerAsSystemService(Context context, ComponentName componentName,
853f501b58de8f467a80fef49c704555781bc61ea6fJim Miller            int currentUser) throws RemoteException {
8549f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        if (mWrapper == null) {
8559f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller            mWrapper = new NotificationListenerWrapper();
8569f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        }
8579f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        mSystemContext = context;
858f501b58de8f467a80fef49c704555781bc61ea6fJim Miller        INotificationManager noMan = getNotificationInterface();
8599f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        mHandler = new MyHandler(context.getMainLooper());
8609f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        mCurrentUser = currentUser;
8619f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller        noMan.registerListener(mWrapper, componentName, currentUser);
8629f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller    }
8639f0753f5a378fc80da86305b33244acc6fc53f01Jim Miller
8644d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales    /**
8654d41a203a08c55b3f3190519535ccee6557ea4feAndres Morales     * Directly unregister this service from the Notification Manager.
866     *
867     * <p>This method will fail for listeners that were not registered
868     * with (@link registerAsService).
869     * @hide
870     */
871    @SystemApi
872    public void unregisterAsSystemService() throws RemoteException {
873        if (mWrapper != null) {
874            INotificationManager noMan = getNotificationInterface();
875            noMan.unregisterListener(mWrapper, mCurrentUser);
876        }
877    }
878
879    /**
880     * Request that the listener be rebound, after a previous call to (@link requestUnbind).
881     *
882     * <p>This method will fail for listeners that have
883     * not been granted the permission by the user.
884     */
885    public static void requestRebind(ComponentName componentName) {
886        INotificationManager noMan = INotificationManager.Stub.asInterface(
887                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
888        try {
889            noMan.requestBindListener(componentName);
890        } catch (RemoteException ex) {
891            throw ex.rethrowFromSystemServer();
892        }
893    }
894
895    /**
896     * Request that the service be unbound.
897     *
898     * <p>This will no longer receive updates until
899     * {@link #requestRebind(ComponentName)} is called.
900     * The service will likely be kiled by the system after this call.
901     *
902     * <p>The service should wait for the {@link #onListenerConnected()} event
903     * before performing this operation. I know it's tempting, but you must wait.
904     */
905    public final void requestUnbind() {
906        if (mWrapper != null) {
907            INotificationManager noMan = getNotificationInterface();
908            try {
909                noMan.requestUnbindListener(mWrapper);
910                // Disable future messages.
911                isConnected = false;
912            } catch (RemoteException ex) {
913                throw ex.rethrowFromSystemServer();
914            }
915        }
916    }
917
918    /** Convert new-style Icons to legacy representations for pre-M clients. */
919    private void createLegacyIconExtras(Notification n) {
920        Icon smallIcon = n.getSmallIcon();
921        Icon largeIcon = n.getLargeIcon();
922        if (smallIcon != null && smallIcon.getType() == Icon.TYPE_RESOURCE) {
923            n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId());
924            n.icon = smallIcon.getResId();
925        }
926        if (largeIcon != null) {
927            Drawable d = largeIcon.loadDrawable(getContext());
928            if (d != null && d instanceof BitmapDrawable) {
929                final Bitmap largeIconBits = ((BitmapDrawable) d).getBitmap();
930                n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, largeIconBits);
931                n.largeIcon = largeIconBits;
932            }
933        }
934    }
935
936    /**
937     * Populates remote views for pre-N targeting apps.
938     */
939    private void maybePopulateRemoteViews(Notification notification) {
940        if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
941            Builder builder = Builder.recoverBuilder(getContext(), notification);
942
943            // Some styles wrap Notification's contentView, bigContentView and headsUpContentView.
944            // First inflate them all, only then set them to avoid recursive wrapping.
945            RemoteViews content = builder.createContentView();
946            RemoteViews big = builder.createBigContentView();
947            RemoteViews headsUp = builder.createHeadsUpContentView();
948
949            notification.contentView = content;
950            notification.bigContentView = big;
951            notification.headsUpContentView = headsUp;
952        }
953    }
954
955    /** @hide */
956    protected class NotificationListenerWrapper extends INotificationListener.Stub {
957        @Override
958        public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
959                NotificationRankingUpdate update) {
960            StatusBarNotification sbn;
961            try {
962                sbn = sbnHolder.get();
963            } catch (RemoteException e) {
964                Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
965                return;
966            }
967
968            try {
969                // convert icon metadata to legacy format for older clients
970                createLegacyIconExtras(sbn.getNotification());
971                maybePopulateRemoteViews(sbn.getNotification());
972            } catch (IllegalArgumentException e) {
973                // warn and drop corrupt notification
974                Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
975                        sbn.getPackageName());
976                sbn = null;
977            }
978
979            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
980            synchronized (mLock) {
981                applyUpdateLocked(update);
982                if (sbn != null) {
983                    SomeArgs args = SomeArgs.obtain();
984                    args.arg1 = sbn;
985                    args.arg2 = mRankingMap;
986                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
987                            args).sendToTarget();
988                } else {
989                    // still pass along the ranking map, it may contain other information
990                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
991                            mRankingMap).sendToTarget();
992                }
993            }
994
995        }
996
997        @Override
998        public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
999                NotificationRankingUpdate update, int reason) {
1000            StatusBarNotification sbn;
1001            try {
1002                sbn = sbnHolder.get();
1003            } catch (RemoteException e) {
1004                Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
1005                return;
1006            }
1007            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1008            synchronized (mLock) {
1009                applyUpdateLocked(update);
1010                SomeArgs args = SomeArgs.obtain();
1011                args.arg1 = sbn;
1012                args.arg2 = mRankingMap;
1013                args.arg3 = reason;
1014                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
1015                        args).sendToTarget();
1016            }
1017
1018        }
1019
1020        @Override
1021        public void onListenerConnected(NotificationRankingUpdate update) {
1022            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1023            synchronized (mLock) {
1024                applyUpdateLocked(update);
1025            }
1026            isConnected = true;
1027            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget();
1028        }
1029
1030        @Override
1031        public void onNotificationRankingUpdate(NotificationRankingUpdate update)
1032                throws RemoteException {
1033            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
1034            synchronized (mLock) {
1035                applyUpdateLocked(update);
1036                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
1037                        mRankingMap).sendToTarget();
1038            }
1039
1040        }
1041
1042        @Override
1043        public void onListenerHintsChanged(int hints) throws RemoteException {
1044            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_HINTS_CHANGED,
1045                    hints, 0).sendToTarget();
1046        }
1047
1048        @Override
1049        public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {
1050            mHandler.obtainMessage(MyHandler.MSG_ON_INTERRUPTION_FILTER_CHANGED,
1051                    interruptionFilter, 0).sendToTarget();
1052        }
1053
1054        @Override
1055        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
1056                                           int importance, boolean user) throws RemoteException {
1057            // no-op in the listener
1058        }
1059
1060        @Override
1061        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
1062                throws RemoteException {
1063            // no-op in the listener
1064        }
1065
1066        @Override
1067        public void onNotificationClick(String key, long time) throws RemoteException {
1068            // no-op in the listener
1069        }
1070
1071        @Override
1072        public void onNotificationActionClick(String key, long time, int actionIndex)
1073                throws RemoteException {
1074            // no-op in the listener
1075        }
1076    }
1077
1078    private void applyUpdateLocked(NotificationRankingUpdate update) {
1079        mRankingMap = new RankingMap(update);
1080    }
1081
1082    /** @hide */
1083    protected Context getContext() {
1084        if (mSystemContext != null) {
1085            return mSystemContext;
1086        }
1087        return this;
1088    }
1089
1090    /**
1091     * Stores ranking related information on a currently active notification.
1092     *
1093     * <p>
1094     * Ranking objects aren't automatically updated as notification events
1095     * occur. Instead, ranking information has to be retrieved again via the
1096     * current {@link RankingMap}.
1097     */
1098    public static class Ranking {
1099
1100        /** Value signifying that the user has not expressed a per-app visibility override value.
1101         * @hide */
1102        public static final int VISIBILITY_NO_OVERRIDE = NotificationManager.VISIBILITY_NO_OVERRIDE;
1103
1104        private String mKey;
1105        private int mRank = -1;
1106        private boolean mIsAmbient;
1107        private boolean mMatchesInterruptionFilter;
1108        private int mVisibilityOverride;
1109        private int mSuppressedVisualEffects;
1110        private @NotificationManager.Importance int mImportance;
1111        private CharSequence mImportanceExplanation;
1112        // System specified group key.
1113        private String mOverrideGroupKey;
1114
1115        public Ranking() {}
1116
1117        /**
1118         * Returns the key of the notification this Ranking applies to.
1119         */
1120        public String getKey() {
1121            return mKey;
1122        }
1123
1124        /**
1125         * Returns the rank of the notification.
1126         *
1127         * @return the rank of the notification, that is the 0-based index in
1128         *     the list of active notifications.
1129         */
1130        public int getRank() {
1131            return mRank;
1132        }
1133
1134        /**
1135         * Returns whether the notification is an ambient notification, that is
1136         * a notification that doesn't require the user's immediate attention.
1137         */
1138        public boolean isAmbient() {
1139            return mIsAmbient;
1140        }
1141
1142        /**
1143         * Returns the user specificed visibility for the package that posted
1144         * this notification, or
1145         * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
1146         * no such preference has been expressed.
1147         * @hide
1148         */
1149        public int getVisibilityOverride() {
1150            return mVisibilityOverride;
1151        }
1152
1153        /**
1154         * Returns the type(s) of visual effects that should be suppressed for this notification.
1155         * See {@link #SUPPRESSED_EFFECT_SCREEN_OFF}, {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
1156         */
1157        public int getSuppressedVisualEffects() {
1158            return mSuppressedVisualEffects;
1159        }
1160
1161        /**
1162         * Returns whether the notification matches the user's interruption
1163         * filter.
1164         *
1165         * @return {@code true} if the notification is allowed by the filter, or
1166         * {@code false} if it is blocked.
1167         */
1168        public boolean matchesInterruptionFilter() {
1169            return mMatchesInterruptionFilter;
1170        }
1171
1172        /**
1173         * Returns the importance of the notification, which dictates its
1174         * modes of presentation, see: {@link NotificationManager#IMPORTANCE_DEFAULT}, etc.
1175         *
1176         * @return the rank of the notification
1177         */
1178        public @NotificationManager.Importance int getImportance() {
1179            return mImportance;
1180        }
1181
1182        /**
1183         * If the importance has been overriden by user preference, then this will be non-null,
1184         * and should be displayed to the user.
1185         *
1186         * @return the explanation for the importance, or null if it is the natural importance
1187         */
1188        public CharSequence getImportanceExplanation() {
1189            return mImportanceExplanation;
1190        }
1191
1192        /**
1193         * If the system has overriden the group key, then this will be non-null, and this
1194         * key should be used to bundle notifications.
1195         */
1196        public String getOverrideGroupKey() {
1197            return mOverrideGroupKey;
1198        }
1199
1200        private void populate(String key, int rank, boolean matchesInterruptionFilter,
1201                int visibilityOverride, int suppressedVisualEffects, int importance,
1202                CharSequence explanation, String overrideGroupKey) {
1203            mKey = key;
1204            mRank = rank;
1205            mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
1206            mMatchesInterruptionFilter = matchesInterruptionFilter;
1207            mVisibilityOverride = visibilityOverride;
1208            mSuppressedVisualEffects = suppressedVisualEffects;
1209            mImportance = importance;
1210            mImportanceExplanation = explanation;
1211            mOverrideGroupKey = overrideGroupKey;
1212        }
1213
1214        /**
1215         * {@hide}
1216         */
1217        public static String importanceToString(int importance) {
1218            switch (importance) {
1219                case NotificationManager.IMPORTANCE_UNSPECIFIED:
1220                    return "UNSPECIFIED";
1221                case NotificationManager.IMPORTANCE_NONE:
1222                    return "NONE";
1223                case NotificationManager.IMPORTANCE_MIN:
1224                    return "MIN";
1225                case NotificationManager.IMPORTANCE_LOW:
1226                    return "LOW";
1227                case NotificationManager.IMPORTANCE_DEFAULT:
1228                    return "DEFAULT";
1229                case NotificationManager.IMPORTANCE_HIGH:
1230                case NotificationManager.IMPORTANCE_MAX:
1231                    return "HIGH";
1232                default:
1233                    return "UNKNOWN(" + String.valueOf(importance) + ")";
1234            }
1235        }
1236    }
1237
1238    /**
1239     * Provides access to ranking information on currently active
1240     * notifications.
1241     *
1242     * <p>
1243     * Note that this object represents a ranking snapshot that only applies to
1244     * notifications active at the time of retrieval.
1245     */
1246    public static class RankingMap implements Parcelable {
1247        private final NotificationRankingUpdate mRankingUpdate;
1248        private ArrayMap<String,Integer> mRanks;
1249        private ArraySet<Object> mIntercepted;
1250        private ArrayMap<String, Integer> mVisibilityOverrides;
1251        private ArrayMap<String, Integer> mSuppressedVisualEffects;
1252        private ArrayMap<String, Integer> mImportance;
1253        private ArrayMap<String, String> mImportanceExplanation;
1254        private ArrayMap<String, String> mOverrideGroupKeys;
1255
1256        private RankingMap(NotificationRankingUpdate rankingUpdate) {
1257            mRankingUpdate = rankingUpdate;
1258        }
1259
1260        /**
1261         * Request the list of notification keys in their current ranking
1262         * order.
1263         *
1264         * @return An array of active notification keys, in their ranking order.
1265         */
1266        public String[] getOrderedKeys() {
1267            return mRankingUpdate.getOrderedKeys();
1268        }
1269
1270        /**
1271         * Populates outRanking with ranking information for the notification
1272         * with the given key.
1273         *
1274         * @return true if a valid key has been passed and outRanking has
1275         *     been populated; false otherwise
1276         */
1277        public boolean getRanking(String key, Ranking outRanking) {
1278            int rank = getRank(key);
1279            outRanking.populate(key, rank, !isIntercepted(key),
1280                    getVisibilityOverride(key), getSuppressedVisualEffects(key),
1281                    getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key));
1282            return rank >= 0;
1283        }
1284
1285        private int getRank(String key) {
1286            synchronized (this) {
1287                if (mRanks == null) {
1288                    buildRanksLocked();
1289                }
1290            }
1291            Integer rank = mRanks.get(key);
1292            return rank != null ? rank : -1;
1293        }
1294
1295        private boolean isIntercepted(String key) {
1296            synchronized (this) {
1297                if (mIntercepted == null) {
1298                    buildInterceptedSetLocked();
1299                }
1300            }
1301            return mIntercepted.contains(key);
1302        }
1303
1304        private int getVisibilityOverride(String key) {
1305            synchronized (this) {
1306                if (mVisibilityOverrides == null) {
1307                    buildVisibilityOverridesLocked();
1308                }
1309            }
1310            Integer override = mVisibilityOverrides.get(key);
1311            if (override == null) {
1312                return Ranking.VISIBILITY_NO_OVERRIDE;
1313            }
1314            return override.intValue();
1315        }
1316
1317        private int getSuppressedVisualEffects(String key) {
1318            synchronized (this) {
1319                if (mSuppressedVisualEffects == null) {
1320                    buildSuppressedVisualEffectsLocked();
1321                }
1322            }
1323            Integer suppressed = mSuppressedVisualEffects.get(key);
1324            if (suppressed == null) {
1325                return 0;
1326            }
1327            return suppressed.intValue();
1328        }
1329
1330        private int getImportance(String key) {
1331            synchronized (this) {
1332                if (mImportance == null) {
1333                    buildImportanceLocked();
1334                }
1335            }
1336            Integer importance = mImportance.get(key);
1337            if (importance == null) {
1338                return NotificationManager.IMPORTANCE_DEFAULT;
1339            }
1340            return importance.intValue();
1341        }
1342
1343        private String getImportanceExplanation(String key) {
1344            synchronized (this) {
1345                if (mImportanceExplanation == null) {
1346                    buildImportanceExplanationLocked();
1347                }
1348            }
1349            return mImportanceExplanation.get(key);
1350        }
1351
1352        private String getOverrideGroupKey(String key) {
1353            synchronized (this) {
1354                if (mOverrideGroupKeys == null) {
1355                    buildOverrideGroupKeys();
1356                }
1357            }
1358            return mOverrideGroupKeys.get(key);
1359        }
1360
1361        // Locked by 'this'
1362        private void buildRanksLocked() {
1363            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
1364            mRanks = new ArrayMap<>(orderedKeys.length);
1365            for (int i = 0; i < orderedKeys.length; i++) {
1366                String key = orderedKeys[i];
1367                mRanks.put(key, i);
1368            }
1369        }
1370
1371        // Locked by 'this'
1372        private void buildInterceptedSetLocked() {
1373            String[] dndInterceptedKeys = mRankingUpdate.getInterceptedKeys();
1374            mIntercepted = new ArraySet<>(dndInterceptedKeys.length);
1375            Collections.addAll(mIntercepted, dndInterceptedKeys);
1376        }
1377
1378        // Locked by 'this'
1379        private void buildVisibilityOverridesLocked() {
1380            Bundle visibilityBundle = mRankingUpdate.getVisibilityOverrides();
1381            mVisibilityOverrides = new ArrayMap<>(visibilityBundle.size());
1382            for (String key: visibilityBundle.keySet()) {
1383               mVisibilityOverrides.put(key, visibilityBundle.getInt(key));
1384            }
1385        }
1386
1387        // Locked by 'this'
1388        private void buildSuppressedVisualEffectsLocked() {
1389            Bundle suppressedBundle = mRankingUpdate.getSuppressedVisualEffects();
1390            mSuppressedVisualEffects = new ArrayMap<>(suppressedBundle.size());
1391            for (String key: suppressedBundle.keySet()) {
1392                mSuppressedVisualEffects.put(key, suppressedBundle.getInt(key));
1393            }
1394        }
1395        // Locked by 'this'
1396        private void buildImportanceLocked() {
1397            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
1398            int[] importance = mRankingUpdate.getImportance();
1399            mImportance = new ArrayMap<>(orderedKeys.length);
1400            for (int i = 0; i < orderedKeys.length; i++) {
1401                String key = orderedKeys[i];
1402                mImportance.put(key, importance[i]);
1403            }
1404        }
1405
1406        // Locked by 'this'
1407        private void buildImportanceExplanationLocked() {
1408            Bundle explanationBundle = mRankingUpdate.getImportanceExplanation();
1409            mImportanceExplanation = new ArrayMap<>(explanationBundle.size());
1410            for (String key: explanationBundle.keySet()) {
1411                mImportanceExplanation.put(key, explanationBundle.getString(key));
1412            }
1413        }
1414
1415        // Locked by 'this'
1416        private void buildOverrideGroupKeys() {
1417            Bundle overrideGroupKeys = mRankingUpdate.getOverrideGroupKeys();
1418            mOverrideGroupKeys = new ArrayMap<>(overrideGroupKeys.size());
1419            for (String key: overrideGroupKeys.keySet()) {
1420                mOverrideGroupKeys.put(key, overrideGroupKeys.getString(key));
1421            }
1422        }
1423
1424        // ----------- Parcelable
1425
1426        @Override
1427        public int describeContents() {
1428            return 0;
1429        }
1430
1431        @Override
1432        public void writeToParcel(Parcel dest, int flags) {
1433            dest.writeParcelable(mRankingUpdate, flags);
1434        }
1435
1436        public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
1437            @Override
1438            public RankingMap createFromParcel(Parcel source) {
1439                NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
1440                return new RankingMap(rankingUpdate);
1441            }
1442
1443            @Override
1444            public RankingMap[] newArray(int size) {
1445                return new RankingMap[size];
1446            }
1447        };
1448    }
1449
1450    private final class MyHandler extends Handler {
1451        public static final int MSG_ON_NOTIFICATION_POSTED = 1;
1452        public static final int MSG_ON_NOTIFICATION_REMOVED = 2;
1453        public static final int MSG_ON_LISTENER_CONNECTED = 3;
1454        public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
1455        public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5;
1456        public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
1457
1458        public MyHandler(Looper looper) {
1459            super(looper, null, false);
1460        }
1461
1462        @Override
1463        public void handleMessage(Message msg) {
1464            if (!isConnected) {
1465                return;
1466            }
1467            switch (msg.what) {
1468                case MSG_ON_NOTIFICATION_POSTED: {
1469                    SomeArgs args = (SomeArgs) msg.obj;
1470                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
1471                    RankingMap rankingMap = (RankingMap) args.arg2;
1472                    args.recycle();
1473                    onNotificationPosted(sbn, rankingMap);
1474                } break;
1475
1476                case MSG_ON_NOTIFICATION_REMOVED: {
1477                    SomeArgs args = (SomeArgs) msg.obj;
1478                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
1479                    RankingMap rankingMap = (RankingMap) args.arg2;
1480                    int reason = (int) args.arg3;
1481                    args.recycle();
1482                    onNotificationRemoved(sbn, rankingMap, reason);
1483                } break;
1484
1485                case MSG_ON_LISTENER_CONNECTED: {
1486                    onListenerConnected();
1487                } break;
1488
1489                case MSG_ON_NOTIFICATION_RANKING_UPDATE: {
1490                    RankingMap rankingMap = (RankingMap) msg.obj;
1491                    onNotificationRankingUpdate(rankingMap);
1492                } break;
1493
1494                case MSG_ON_LISTENER_HINTS_CHANGED: {
1495                    final int hints = msg.arg1;
1496                    onListenerHintsChanged(hints);
1497                } break;
1498
1499                case MSG_ON_INTERRUPTION_FILTER_CHANGED: {
1500                    final int interruptionFilter = msg.arg1;
1501                    onInterruptionFilterChanged(interruptionFilter);
1502                } break;
1503            }
1504        }
1505    }
1506}
1507