NotificationListenerService.java revision 0efdb88ccc9d650e7a644b9be8f63792f2c66841
1894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman/*
2894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * Copyright (C) 2013 The Android Open Source Project
3894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *
4894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * Licensed under the Apache License, Version 2.0 (the "License");
5894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * you may not use this file except in compliance with the License.
6894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * You may obtain a copy of the License at
7894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *
8894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *      http://www.apache.org/licenses/LICENSE-2.0
9894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *
10894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * Unless required by applicable law or agreed to in writing, software
11894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * distributed under the License is distributed on an "AS IS" BASIS,
12894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * See the License for the specific language governing permissions and
14894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * limitations under the License.
15894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman */
16894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanpackage android.service.notification;
1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanimport android.os.Handler;
20894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Looper;
21894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Message;
22894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
23894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.annotation.IntDef;
24894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.annotation.SystemApi;
25894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.annotation.SdkConstant;
26894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.app.INotificationManager;
27894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.app.Notification;
28894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.app.Notification.Builder;
29894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.app.NotificationManager;
30894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.app.Service;
31894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.content.ComponentName;
32894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.content.Context;
33894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.content.Intent;
34894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.content.pm.ParceledListSlice;
35894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.graphics.drawable.BitmapDrawable;
36894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.graphics.drawable.Drawable;
37894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.graphics.drawable.Icon;
38894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.graphics.Bitmap;
39894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Build;
40894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Bundle;
41894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.IBinder;
42894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Parcel;
43894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.Parcelable;
44894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.os.RemoteException;
4519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanimport android.os.ServiceManager;
4619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanimport android.util.ArrayMap;
47894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.util.ArraySet;
48894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.util.Log;
49894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport android.widget.RemoteViews;
50894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport com.android.internal.annotations.GuardedBy;
51894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport com.android.internal.os.SomeArgs;
52894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.lang.annotation.Retention;
53894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.lang.annotation.RetentionPolicy;
54894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.util.ArrayList;
55894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.util.Collections;
56894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanimport java.util.List;
57894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
58894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman/**
59894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * A service that receives calls from the system when new notifications are
60894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * posted or removed, or their ranking changed.
61894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * <p>To extend this class, you must declare the service in your manifest file with
62894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
63894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
64894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * <pre>
65894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * &lt;service android:name=".NotificationListener"
66894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *          android:label="&#64;string/service_name"
67894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *          android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
68894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *     &lt;intent-filter>
69894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *         &lt;action android:name="android.service.notification.NotificationListenerService" />
70894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *     &lt;/intent-filter>
71894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * &lt;/service></pre>
72894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * <p> Typically, while enabled in user settings, this service will be bound on boot or when a
73894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * settings change occurs that could affect whether this service should run.  However, for some
74894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * system usage modes, the you may instead specify that this service is instead bound and unbound
75894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * in response to mode changes by including a category in the intent filter.  Currently
76894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * supported categories are:
77894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * <ul>
78894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *   <li>{@link #CATEGORY_VR_NOTIFICATIONS} - this service is bound when an Activity has enabled
79894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman *   VR mode. {@see android.app.Activity#setVrMode(boolean)}.</li>
80894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * </ul>
81894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman * </p>
82894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman */
83894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Baumanpublic abstract class NotificationListenerService extends Service {
84894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    // TAG = "NotificationListenerService[MySubclass]"
85894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private final String TAG = NotificationListenerService.class.getSimpleName()
86894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            + "[" + getClass().getSimpleName() + "]";
87894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
88894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
89894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
90894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     Normal interruption filter.
91894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
92894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int INTERRUPTION_FILTER_ALL
93894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = NotificationManager.INTERRUPTION_FILTER_ALL;
94894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
95894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
96894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
97894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     Priority interruption filter.
98894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
99894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int INTERRUPTION_FILTER_PRIORITY
100894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = NotificationManager.INTERRUPTION_FILTER_PRIORITY;
101894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
102894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
103894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
104894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     No interruptions filter.
105894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
106894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int INTERRUPTION_FILTER_NONE
107894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = NotificationManager.INTERRUPTION_FILTER_NONE;
108894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
109894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
110894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
111894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     Alarms only interruption filter.
112894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
113894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int INTERRUPTION_FILTER_ALARMS
114894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = NotificationManager.INTERRUPTION_FILTER_ALARMS;
115894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
116894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
117894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * the value is unavailable for any reason.  For example, before the notification listener
118894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * is connected.
119894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
120894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@see #onListenerConnected()}
121894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
122894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int INTERRUPTION_FILTER_UNKNOWN
123894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
124894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
125894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
12619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * should disable notification sound, vibrating and other visual or aural effects.
12719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * This does not change the interruption filter, only the effects. **/
128894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int HINT_HOST_DISABLE_EFFECTS = 1;
129894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
130894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
13119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * Whether notification suppressed by DND should not interruption visually when the screen is
132894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * off.
133894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
134894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int SUPPRESSED_EFFECT_SCREEN_OFF =
13519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
13619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    /**
13719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * Whether notification suppressed by DND should not interruption visually when the screen is
138894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * on.
139894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
140894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int SUPPRESSED_EFFECT_SCREEN_ON =
141894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
142894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
143894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
144894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The full trim of the StatusBarNotification including all its features.
145894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
146894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
147894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
148894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
149894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int TRIM_FULL = 0;
150894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
151894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
152894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * A light trim of the StatusBarNotification excluding the following features:
153894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
154894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <ol>
155894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#tickerView tickerView}</li>
156894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#contentView contentView}</li>
157894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#largeIcon largeIcon}</li>
158894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#bigContentView bigContentView}</li>
159894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#headsUpContentView headsUpContentView}</li>
160894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li>
161894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li>
162894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li>
163894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li>
164894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * </ol>
165894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
166894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
167894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
168894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
169894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final int TRIM_LIGHT = 1;
170894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
171894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private final Object mLock = new Object();
172894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
173894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private Handler mHandler;
174894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
175894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** @hide */
176894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected NotificationListenerWrapper mWrapper = null;
177894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
178894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @GuardedBy("mLock")
179894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private RankingMap mRankingMap;
180894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
181894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private INotificationManager mNoMan;
182894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
183894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
184894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Only valid after a successful call to (@link registerAsService}.
185894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
186894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
187894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected int mCurrentUser;
188894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
189894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
190894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * This context is required for system services since NotificationListenerService isn't
191894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * started as a real Service and hence no context is available..
192894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
193894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
194894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected Context mSystemContext;
195894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
196894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
197894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The {@link Intent} that must be declared as handled by the service.
198894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
199894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
200894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final String SERVICE_INTERFACE
201894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            = "android.service.notification.NotificationListenerService";
202894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
203894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
204894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * If this category is declared in the application manifest for a service of this type, this
205894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * service will be bound when VR mode is enabled, and unbound when VR mode is disabled rather
206894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * than the normal lifecycle for a notification service.
207894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
208894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@see android.app.Activity#setVrMode(boolean)}
209894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
210894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
211894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static final String CATEGORY_VR_NOTIFICATIONS =
212894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        "android.intent.category.vr.notifications";
213894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
214894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @Override
215894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected void attachBaseContext(Context base) {
216894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        super.attachBaseContext(base);
217894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        mHandler = new MyHandler(getMainLooper());
218894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
219894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
220894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
221894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to learn about new notifications as they are posted by apps.
222894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
223894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
224894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            object as well as its identifying information (tag and id) and source
225894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            (package name).
226894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
227894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onNotificationPosted(StatusBarNotification sbn) {
228894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // optional
229894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
230894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
231894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
232894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to learn about new notifications as they are posted by apps.
233894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
234894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param sbn A data structure encapsulating the original {@link android.app.Notification}
235894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            object as well as its identifying information (tag and id) and source
236894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            (package name).
237894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param rankingMap The current ranking map that can be used to retrieve ranking information
238894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *                   for active notifications, including the newly posted one.
239894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
240894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
241894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        onNotificationPosted(sbn);
242894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
243894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
244894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
245894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to learn when notifications are removed.
246894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
247894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * This might occur because the user has dismissed the notification using system UI (or another
248894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notification listener) or because the app has withdrawn the notification.
249894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
250894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
251894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
252894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * fields such as {@link android.app.Notification#contentView} and
253894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#largeIcon}. However, all other fields on
254894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
255894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
256894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
257894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param sbn A data structure encapsulating at least the original information (tag and id)
258894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            and source (package name) used to post the {@link android.app.Notification} that
259894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            was just removed.
260894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
261894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onNotificationRemoved(StatusBarNotification sbn) {
262894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // optional
263894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
264894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
265894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
266894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to learn when notifications are removed.
267894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
268894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * This might occur because the user has dismissed the notification using system UI (or another
269894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notification listener) or because the app has withdrawn the notification.
270894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
271894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the
272894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight
273894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * fields such as {@link android.app.Notification#contentView} and
274894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#largeIcon}. However, all other fields on
275894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link StatusBarNotification}, sufficient to match this call with a prior call to
276894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #onNotificationPosted(StatusBarNotification)}, will be intact.
277894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
278894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param sbn A data structure encapsulating at least the original information (tag and id)
279894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            and source (package name) used to post the {@link android.app.Notification} that
280894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *            was just removed.
281894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param rankingMap The current ranking map that can be used to retrieve ranking information
282894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *                   for active notifications.
283894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
284894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
285894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
286894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        onNotificationRemoved(sbn);
287894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
288894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
289894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
290894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to learn about when the listener is enabled and connected to
291894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * the notification manager.  You are safe to call {@link #getActiveNotifications()}
292894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * at this time.
293894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
294894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onListenerConnected() {
295894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // optional
296894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
297894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
298894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
299894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to be notified when the notification ranking changes.
300894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
301894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param rankingMap The current ranking map that can be used to retrieve ranking information
302894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *                   for active notifications.
303894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
304894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onNotificationRankingUpdate(RankingMap rankingMap) {
305894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // optional
306894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
307894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
308894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
309894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to be notified when the
310894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentListenerHints() Listener hints} change.
311894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
312894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param hints The current {@link #getCurrentListenerHints() listener hints}.
313894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
314894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void onListenerHintsChanged(int hints) {
315894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // optional
316894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
317894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
318894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
319894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Implement this method to be notified when the
320894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #getCurrentInterruptionFilter() interruption filter} changed.
321894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
322894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param interruptionFilter The current
323894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     {@link #getCurrentInterruptionFilter() interruption filter}.
32419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     */
32519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    public void onInterruptionFilterChanged(int interruptionFilter) {
32619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        // optional
32719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    }
32819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
32919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    /** @hide */
330894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected final INotificationManager getNotificationInterface() {
331894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mNoMan == null) {
332894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mNoMan = INotificationManager.Stub.asInterface(
333894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
334894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
335894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return mNoMan;
336894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
337894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
338894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
339894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Inform the notification manager about dismissal of a single notification.
340894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
341894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Use this if your listener has a user interface that allows the user to dismiss individual
342894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications, similar to the behavior of Android's status bar and notification panel.
343894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * It should be called after the user dismisses a single notification using your UI;
344894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * upon being informed, the notification manager will actually remove the notification
345894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
346894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
347894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <b>Note:</b> If your listener allows the user to fire a notification's
348894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
349894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * this method at that time <i>if</i> the Notification in question has the
350894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
351894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
352894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param pkg Package of the notifying app.
353894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param tag Tag of the notification as specified by the notifying app in
354894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
355894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param id  ID of the notification as specified by the notifying app in
356894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
357894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
358894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @deprecated Use {@link #cancelNotification(String key)}
359894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * instead. Beginning with {@link android.os.Build.VERSION_CODES#LOLLIPOP} this method will no longer
360894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * cancel the notification. It will continue to cancel the notification for applications
361894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * whose {@code targetSdkVersion} is earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}.
362894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
363894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void cancelNotification(String pkg, String tag, int id) {
364894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
365894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
366894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().cancelNotificationFromListener(
367894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    mWrapper, pkg, tag, id);
368894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
369894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
370894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
371894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
372894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
373894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
37419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * Inform the notification manager about dismissal of a single notification.
37519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * <p>
37619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * Use this if your listener has a user interface that allows the user to dismiss individual
37719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * notifications, similar to the behavior of Android's status bar and notification panel.
37819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * It should be called after the user dismisses a single notification using your UI;
37919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * upon being informed, the notification manager will actually remove the notification
38019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
381894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>
382894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <b>Note:</b> If your listener allows the user to fire a notification's
383894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
384894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * this method at that time <i>if</i> the Notification in question has the
385894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
386894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
387894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param key Notification to dismiss from {@link StatusBarNotification#getKey()}.
388894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
389894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void cancelNotification(String key) {
390894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
391894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
392894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().cancelNotificationsFromListener(mWrapper,
393894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    new String[] { key });
394894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
395894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
396894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
397894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
398894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
399894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
400894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Inform the notification manager about dismissal of all notifications.
401894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
402894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Use this if your listener has a user interface that allows the user to dismiss all
403894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications, similar to the behavior of Android's status bar and notification panel.
404894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * It should be called after the user invokes the "dismiss all" function of your UI;
405894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * upon being informed, the notification manager will actually remove all active notifications
406894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks.
407894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
408894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@see #cancelNotification(String, String, int)}
409894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
410894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void cancelAllNotifications() {
411894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        cancelNotifications(null /*all*/);
412894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
413894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
414894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
415894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Inform the notification manager about dismissal of specific notifications.
416894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
417894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Use this if your listener has a user interface that allows the user to dismiss
418894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * multiple notifications at once.
419894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
420894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param keys Notifications to dismiss, or {@code null} to dismiss all.
421894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
422894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@see #cancelNotification(String, String, int)}
423894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
424894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void cancelNotifications(String[] keys) {
425894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
426894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
427894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
428894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
429894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
430894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
431894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
432894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
433894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
434894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Inform the notification manager that these notifications have been viewed by the
435894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * user. This should only be called when there is sufficient confidence that the user is
436894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * looking at the notifications, such as when the notifications appear on the screen due to
437894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * an explicit user interaction.
438894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param keys Notifications to mark as seen.
439894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
440894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void setNotificationsShown(String[] keys) {
441894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
442894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
443894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().setNotificationsShownFromListener(mWrapper, keys);
444894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
445894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
446894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
447894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
448894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
449894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
450894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Sets the notification trim that will be received via {@link #onNotificationPosted}.
451894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
452894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
453894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the
454894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * full notification features right away to reduce their memory footprint. Full notifications
455894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * can be requested on-demand via {@link #getActiveNotifications(int)}.
456894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
457894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
458894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Set to {@link #TRIM_FULL} initially.
459894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
460894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
461894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
462894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}.
463894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *             See <code>TRIM_*</code> constants.
464894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
465894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
466894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void setOnNotificationPostedTrim(int trim) {
46719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        if (!isBound()) return;
468894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
469894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim);
470894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (RemoteException ex) {
471894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
472894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
473894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
474894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
475894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
476894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request the list of outstanding notifications (that is, those that are visible to the
477894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * current user). Useful when you don't know what's already been posted.
478894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
479894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return An array of active notifications, sorted in natural order.
480894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
481894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public StatusBarNotification[] getActiveNotifications() {
482894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return getActiveNotifications(null, TRIM_FULL);
483894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
484894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
485894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
486894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request the list of outstanding notifications (that is, those that are visible to the
487894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * current user). Useful when you don't know what's already been posted.
488894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
489894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
490894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
491894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
492894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return An array of active notifications, sorted in natural order.
493894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
494894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
495894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public StatusBarNotification[] getActiveNotifications(int trim) {
496894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return getActiveNotifications(null, trim);
497894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
498894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
499894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
500894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request one or more notifications by key. Useful if you have been keeping track of
501894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications but didn't want to retain the bits, and now need to go back and extract
502894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * more data out of those notifications.
503894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
504894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param keys the keys of the notifications to request
505894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return An array of notifications corresponding to the requested keys, in the
506894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * same order as the key list.
507894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
508894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public StatusBarNotification[] getActiveNotifications(String[] keys) {
509894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return getActiveNotifications(keys, TRIM_FULL);
510894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
511894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
512894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
513894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request one or more notifications by key. Useful if you have been keeping track of
514894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications but didn't want to retain the bits, and now need to go back and extract
515894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * more data out of those notifications.
516894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
517894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
518894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
519894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param keys the keys of the notifications to request
520894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants.
521894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return An array of notifications corresponding to the requested keys, in the
522894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * same order as the key list.
523894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
524894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
525894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) {
526894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound())
527894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return null;
528894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
529894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
530894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    .getActiveNotificationsFromListener(mWrapper, keys, trim);
531894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            List<StatusBarNotification> list = parceledList.getList();
532894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            ArrayList<StatusBarNotification> corruptNotifications = null;
533894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            int N = list.size();
534894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (int i = 0; i < N; i++) {
535894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                StatusBarNotification sbn = list.get(i);
536894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                Notification notification = sbn.getNotification();
537894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                try {
538894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    // convert icon metadata to legacy format for older clients
539894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    createLegacyIconExtras(notification);
540894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    // populate remote views for older clients.
541894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    maybePopulateRemoteViews(notification);
542894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                } catch (IllegalArgumentException e) {
543894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    if (corruptNotifications == null) {
544894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                        corruptNotifications = new ArrayList<>(N);
545894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    }
546894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    corruptNotifications.add(sbn);
547894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
548894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                            sbn.getPackageName());
549894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
550894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
551894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if (corruptNotifications != null) {
552894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                list.removeAll(corruptNotifications);
553894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
554894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return list.toArray(new StatusBarNotification[list.size()]);
555894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
556894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
557894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
558894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return null;
559894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
560894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
561894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
562894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Gets the set of hints representing current state.
563894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
564894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
565894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The current state may differ from the requested state if the hint represents state
566894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * shared across all listeners or a feature the notification host does not support or refuses
567894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * to grant.
568894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
569894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return Zero or more of the HINT_ constants.
570894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
571894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final int getCurrentListenerHints() {
572894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return 0;
573894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
574894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return getNotificationInterface().getHintsFromListener(mWrapper);
575894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
576894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
577894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return 0;
578894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
579894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
580894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
581894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
582894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Gets the current notification interruption filter active on the host.
583894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
584894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
585894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The interruption filter defines which notifications are allowed to interrupt the user
586894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * (e.g. via sound &amp; vibration) and is applied globally. Listeners can find out whether
587894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * a specific notification matched the interruption filter via
588894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link Ranking#matchesInterruptionFilter()}.
589894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
590894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The current filter may differ from the previously requested filter if the notification host
591894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * does not support or refuses to apply the requested filter, or if another component changed
592894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * the filter in the meantime.
593894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
594894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
595894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
596894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
597894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * unavailable.
598894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
599894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final int getCurrentInterruptionFilter() {
600894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return INTERRUPTION_FILTER_UNKNOWN;
601894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
602894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return getNotificationInterface().getInterruptionFilterFromListener(mWrapper);
603894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
604894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
605894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return INTERRUPTION_FILTER_UNKNOWN;
606894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
607894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
608894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
609894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
610894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Sets the desired {@link #getCurrentListenerHints() listener hints}.
611894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
612894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
613894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * This is merely a request, the host may or may not choose to take action depending
614894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * on other listener requests or other global state.
615894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
616894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Listen for updates using {@link #onListenerHintsChanged(int)}.
617894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
618894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param hints One or more of the HINT_ constants.
619894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
620894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void requestListenerHints(int hints) {
621894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
622894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
623894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface().requestHintsFromListener(mWrapper, hints);
624894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
625894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
626894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
627894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
628894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
629894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
630894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Sets the desired {@link #getCurrentInterruptionFilter() interruption filter}.
631894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
632894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
633894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * This is merely a request, the host may or may not choose to apply the requested
634894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * interruption filter depending on other listener requests or other global state.
635894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
636894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Listen for updates using {@link #onInterruptionFilterChanged(int)}.
637894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
638894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants.
639894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
640894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void requestInterruptionFilter(int interruptionFilter) {
641894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (!isBound()) return;
642894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        try {
643894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            getNotificationInterface()
644894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    .requestInterruptionFilterFromListener(mWrapper, interruptionFilter);
645894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        } catch (android.os.RemoteException ex) {
646894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.v(TAG, "Unable to contact notification manager", ex);
647894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
648894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
64919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
650894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
651894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Returns current ranking information.
652894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
653894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
654894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The returned object represents the current ranking snapshot and only
655894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * applies for currently active notifications.
656894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
657894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Generally you should use the RankingMap that is passed with events such
658894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)},
659894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and
660894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * so on. This method should only be used when needing access outside of
661894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * such events, for example to retrieve the RankingMap right after
662894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * initialization.
66319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     *
66419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     * @return A {@link RankingMap} object providing access to ranking information
665894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
666894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public RankingMap getCurrentRanking() {
667894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        synchronized (mLock) {
668894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mRankingMap;
669894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
670894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
67119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
672894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @Override
673894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public IBinder onBind(Intent intent) {
674894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mWrapper == null) {
675894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mWrapper = new NotificationListenerWrapper();
676894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
677894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return mWrapper;
678894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
679894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
680894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** @hide */
681894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected boolean isBound() {
682894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mWrapper == null) {
683894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Log.w(TAG, "Notification listener service not yet bound.");
684894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return false;
685894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
686894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return true;
687894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
688894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
689894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
690894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Directly register this service with the Notification Manager.
691894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
692894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>Only system services may use this call. It will fail for non-system callers.
693894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Apps should ask the user to add their listener in Settings.
694894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
695894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param context Context required for accessing resources. Since this service isn't
696894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *    launched as a real Service when using this method, a context has to be passed in.
697894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param componentName the component that will consume the notification information
698894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @param currentUser the user to use as the stream filter
699894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
700894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
701894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
702894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void registerAsSystemService(Context context, ComponentName componentName,
703894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            int currentUser) throws RemoteException {
704894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mWrapper == null) {
705894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mWrapper = new NotificationListenerWrapper();
706894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
707894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        mSystemContext = context;
708894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        INotificationManager noMan = getNotificationInterface();
709894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        noMan.registerListener(mWrapper, componentName, currentUser);
710894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        mCurrentUser = currentUser;
711894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        mHandler = new MyHandler(context.getMainLooper());
712894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
713894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
714894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
715894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Directly unregister this service from the Notification Manager.
716894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
717894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>This method will fail for listeners that were not registered
718894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * with (@link registerAsService).
719894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * @hide
720894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
721894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    @SystemApi
722894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public void unregisterAsSystemService() throws RemoteException {
723894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mWrapper != null) {
724894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            INotificationManager noMan = getNotificationInterface();
725894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            noMan.unregisterListener(mWrapper, mCurrentUser);
726894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
727894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
728894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
729894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
730894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request that the listener be rebound, after a previous call to (@link requestUnbind).
731894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
732894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>This method will fail for listeners that have
733894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * not been granted the permission by the user.
734894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
735894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>The service should wait for the {@link #onListenerConnected()} event
736894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * before performing any operations.
737894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
738894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static void requestRebind(ComponentName componentName)
739894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            throws RemoteException {
740894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        INotificationManager noMan = INotificationManager.Stub.asInterface(
741894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
742894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        noMan.requestBindListener(componentName);
743894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
744894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
745894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
746894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Request that the service be unbound.
747894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
748894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <P>This will no longer receive updates until
749894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * {@link #requestRebind(ComponentName)} is called.
750894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * The service will likely be kiled by the system after this call.
75119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman     */
752894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public final void requestUnbind() throws RemoteException {
753894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mWrapper != null) {
754894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            INotificationManager noMan = getNotificationInterface();
755894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            noMan.requestUnbindListener(mWrapper);
756894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
757894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
758894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
759894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** Convert new-style Icons to legacy representations for pre-M clients. */
760894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private void createLegacyIconExtras(Notification n) {
761894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        Icon smallIcon = n.getSmallIcon();
762894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        Icon largeIcon = n.getLargeIcon();
763894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (smallIcon != null && smallIcon.getType() == Icon.TYPE_RESOURCE) {
764894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId());
765894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            n.icon = smallIcon.getResId();
766894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
767894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (largeIcon != null) {
768894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Drawable d = largeIcon.loadDrawable(getContext());
769894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if (d != null && d instanceof BitmapDrawable) {
770894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                final Bitmap largeIconBits = ((BitmapDrawable) d).getBitmap();
771894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, largeIconBits);
772894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                n.largeIcon = largeIconBits;
773894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
77419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        }
775894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
776894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
777894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
778894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Populates remote views for pre-N targeting apps.
779894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
780894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private void maybePopulateRemoteViews(Notification notification) {
781894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
782894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Builder builder = Builder.recoverBuilder(getContext(), notification);
783894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
784894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // Some styles wrap Notification's contentView, bigContentView and headsUpContentView.
785894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // First inflate them all, only then set them to avoid recursive wrapping.
786894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            RemoteViews content = builder.createContentView();
78719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            RemoteViews big = builder.createBigContentView();
788894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            RemoteViews headsUp = builder.createHeadsUpContentView();
789894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
790894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            notification.contentView = content;
791894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            notification.bigContentView = big;
792894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            notification.headsUpContentView = headsUp;
793894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
794894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
795894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
796894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** @hide */
797894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected class NotificationListenerWrapper extends INotificationListener.Stub {
798894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
799894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
800894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                NotificationRankingUpdate update) {
801894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            StatusBarNotification sbn;
802894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            try {
803894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                sbn = sbnHolder.get();
804894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            } catch (RemoteException e) {
805894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e);
806894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return;
807894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
808894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
809894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            try {
810894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                // convert icon metadata to legacy format for older clients
811894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                createLegacyIconExtras(sbn.getNotification());
812894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                maybePopulateRemoteViews(sbn.getNotification());
813894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            } catch (IllegalArgumentException e) {
814894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                // warn and drop corrupt notification
815894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
816894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                        sbn.getPackageName());
817894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                sbn = null;
818894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
819894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
820894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
821894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (mLock) {
822894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                applyUpdateLocked(update);
823894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (sbn != null) {
824894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    SomeArgs args = SomeArgs.obtain();
825894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    args.arg1 = sbn;
826894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    args.arg2 = mRankingMap;
827894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
828894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                            args).sendToTarget();
829894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                } else {
830894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    // still pass along the ranking map, it may contain other information
831894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
832894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                            mRankingMap).sendToTarget();
833894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
834894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
835894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
836894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
837894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
838894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
839894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
840894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                NotificationRankingUpdate update) {
841894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            StatusBarNotification sbn;
842894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            try {
843894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                sbn = sbnHolder.get();
844894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            } catch (RemoteException e) {
845894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e);
846894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return;
847894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
848894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
849894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (mLock) {
850894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                applyUpdateLocked(update);
851894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                SomeArgs args = SomeArgs.obtain();
852894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                args.arg1 = sbn;
853894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                args.arg2 = mRankingMap;
854894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
855894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                        args).sendToTarget();
856894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
857894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
858894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
859894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
860894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
861894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onListenerConnected(NotificationRankingUpdate update) {
862894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
863894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (mLock) {
864894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                applyUpdateLocked(update);
86519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            }
86619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget();
867894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
868894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
869894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
870894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationRankingUpdate(NotificationRankingUpdate update)
871894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                throws RemoteException {
872894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
873894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (mLock) {
874894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                applyUpdateLocked(update);
875894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
876894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                        mRankingMap).sendToTarget();
877894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
878894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
879894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
880894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
881894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
882894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onListenerHintsChanged(int hints) throws RemoteException {
883894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_HINTS_CHANGED,
884894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    hints, 0).sendToTarget();
885894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
886894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
887894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
888894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {
889894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mHandler.obtainMessage(MyHandler.MSG_ON_INTERRUPTION_FILTER_CHANGED,
890894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    interruptionFilter, 0).sendToTarget();
891894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
892894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
893894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
894894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
895894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                                           int importance, boolean user) throws RemoteException {
896894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // no-op in the listener
897894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
898894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
899894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
900894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
901894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                throws RemoteException {
902894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // no-op in the listener
903894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
904894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
905894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
906894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationClick(String key, long time) throws RemoteException {
907894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // no-op in the listener
908894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
909894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
910894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
911894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationActionClick(String key, long time, int actionIndex)
912894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                throws RemoteException {
913894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // no-op in the listener
914894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
915894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
916894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
917894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void onNotificationRemovedReason(String key, long time, int reason)
918894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                throws RemoteException {
919894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            // no-op in the listener
920894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
921894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
922894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
923894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    private void applyUpdateLocked(NotificationRankingUpdate update) {
924894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        mRankingMap = new RankingMap(update);
925894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
926894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
927894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /** @hide */
928894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    protected Context getContext() {
929894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        if (mSystemContext != null) {
930894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mSystemContext;
931894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
932894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        return this;
933894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
934894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
935894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
936894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Stores ranking related information on a currently active notification.
937894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
938894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
939894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Ranking objects aren't automatically updated as notification events
940894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * occur. Instead, ranking information has to be retrieved again via the
941894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * current {@link RankingMap}.
942894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
943894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static class Ranking {
944894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
945894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /** @hide */
946894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @IntDef({VISIBILITY_NO_OVERRIDE, IMPORTANCE_UNSPECIFIED, IMPORTANCE_NONE,
947894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT, IMPORTANCE_HIGH,
948894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                IMPORTANCE_MAX})
949894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Retention(RetentionPolicy.SOURCE)
950894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public @interface Importance {}
951894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
952894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /** Value signifying that the user has not expressed a per-app visibility override value.
953894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @hide */
954894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public static final int VISIBILITY_NO_OVERRIDE = -1000;
955894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
956894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
957894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Value signifying that the user has not expressed an importance.
958894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
959894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * This value is for persisting preferences, and should never be associated with
960894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * an actual notification.
961894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
962894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public static final int IMPORTANCE_UNSPECIFIED = -1000;
963894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
964894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
965894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * A notification with no importance: shows nowhere, is blocked.
966894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
967894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public static final int IMPORTANCE_NONE = 0;
968894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
969894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
970894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Min notification importance: only shows in the shade, below the fold.
97119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
97219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public static final int IMPORTANCE_MIN = 1;
97319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
97419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        /**
97519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * Low notification importance: shows everywhere, but is not intrusive.
97619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
97719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public static final int IMPORTANCE_LOW = 2;
97819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
97919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        /**
98019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * Default notification importance: shows everywhere, allowed to makes noise,
98119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * but does not visually intrude.
98219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
98319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public static final int IMPORTANCE_DEFAULT = 3;
98419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
98519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        /**
98619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * Higher notification importance: shows everywhere, allowed to makes noise and peek.
98719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
98819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public static final int IMPORTANCE_HIGH = 4;
98919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
99019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        /**
99119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * Highest notification importance: shows everywhere, allowed to makes noise, peek, and
99219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * use full screen intents.
99319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
99419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public static final int IMPORTANCE_MAX = 5;
99519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
99619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private String mKey;
99719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private int mRank = -1;
99819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private boolean mIsAmbient;
99919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private boolean mMatchesInterruptionFilter;
100019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private int mVisibilityOverride;
100119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private int mSuppressedVisualEffects;
100219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private @Importance int mImportance;
100319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private CharSequence mImportanceExplanation;
100419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1005894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public Ranking() {}
1006894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1007894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1008894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns the key of the notification this Ranking applies to.
1009894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1010894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public String getKey() {
1011894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mKey;
1012894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1013894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1014894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1015894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns the rank of the notification.
1016894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1017894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return the rank of the notification, that is the 0-based index in
1018894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *     the list of active notifications.
1019894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1020894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public int getRank() {
1021894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mRank;
1022894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1023894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1024894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1025894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns whether the notification is an ambient notification, that is
1026894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * a notification that doesn't require the user's immediate attention.
1027894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1028894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public boolean isAmbient() {
1029894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mIsAmbient;
1030894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1031894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1032894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1033894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns the user specificed visibility for the package that posted
1034894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * this notification, or
1035894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if
1036894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * no such preference has been expressed.
1037894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @hide
1038894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
103919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        public int getVisibilityOverride() {
104019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            return mVisibilityOverride;
104119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        }
104219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
104319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        /**
104419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * Returns the type(s) of visual effects that should be suppressed for this notification.
104519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         * See {@link #SUPPRESSED_EFFECT_SCREEN_OFF}, {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
104619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
1047894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public int getSuppressedVisualEffects() {
1048894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mSuppressedVisualEffects;
1049894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1050894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1051894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1052894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns whether the notification matches the user's interruption
1053894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * filter.
1054894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1055894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return {@code true} if the notification is allowed by the filter, or
1056894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * {@code false} if it is blocked.
1057894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1058894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public boolean matchesInterruptionFilter() {
1059894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mMatchesInterruptionFilter;
1060894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1061894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1062894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1063894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Returns the importance of the notification, which dictates its
1064894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * modes of presentation, see: {@link #IMPORTANCE_DEFAULT}, etc.
1065894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1066894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return the rank of the notification
1067894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1068894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public @Importance int getImportance() {
1069894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mImportance;
1070894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1071894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1072894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1073894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * If the importance has been overriden by user preference, then this will be non-null,
1074894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * and should be displayed to the user.
1075894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1076894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return the explanation for the importance, or null if it is the natural importance
1077894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1078894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public CharSequence getImportanceExplanation() {
1079894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mImportanceExplanation;
1080894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1081894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1082894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void populate(String key, int rank, boolean matchesInterruptionFilter,
1083894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                int visibilityOverride, int suppressedVisualEffects, int importance,
1084894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                CharSequence explanation) {
1085894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mKey = key;
1086894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mRank = rank;
1087894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mIsAmbient = importance < IMPORTANCE_LOW;
1088894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mMatchesInterruptionFilter = matchesInterruptionFilter;
1089894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mVisibilityOverride = visibilityOverride;
1090894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mSuppressedVisualEffects = suppressedVisualEffects;
1091894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mImportance = importance;
1092894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mImportanceExplanation = explanation;
1093894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1094894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1095894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1096894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * {@hide}
1097894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1098894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public static String importanceToString(int importance) {
1099894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            switch (importance) {
1100894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_UNSPECIFIED:
1101894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "UNSPECIFIED";
110219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                case IMPORTANCE_NONE:
1103894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "NONE";
1104894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_MIN:
1105894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "MIN";
1106894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_LOW:
1107894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "LOW";
1108894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_DEFAULT:
1109894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "DEFAULT";
1110894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_HIGH:
1111894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "HIGH";
1112894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                case IMPORTANCE_MAX:
1113894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "MAX";
1114894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                default:
1115894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    return "UNKNOWN(" + String.valueOf(importance) + ")";
1116894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1117894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1118894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    }
1119894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1120894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    /**
1121894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Provides access to ranking information on currently active
1122894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications.
1123894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     *
1124894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * <p>
1125894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * Note that this object represents a ranking snapshot that only applies to
1126894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     * notifications active at the time of retrieval.
1127894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman     */
1128894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman    public static class RankingMap implements Parcelable {
1129894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private final NotificationRankingUpdate mRankingUpdate;
1130894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArrayMap<String,Integer> mRanks;
1131894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArraySet<Object> mIntercepted;
1132894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArrayMap<String, Integer> mVisibilityOverrides;
1133894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArrayMap<String, Integer> mSuppressedVisualEffects;
1134894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArrayMap<String, Integer> mImportance;
1135894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private ArrayMap<String, String> mImportanceExplanation;
1136894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
113719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman        private RankingMap(NotificationRankingUpdate rankingUpdate) {
1138894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mRankingUpdate = rankingUpdate;
1139894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1140894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1141894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1142894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Request the list of notification keys in their current ranking
1143894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * order.
1144894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1145894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return An array of active notification keys, in their ranking order.
114619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman         */
1147894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public String[] getOrderedKeys() {
1148894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mRankingUpdate.getOrderedKeys();
1149894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
115019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1151894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        /**
1152894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * Populates outRanking with ranking information for the notification
1153894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * with the given key.
1154894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *
1155894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         * @return true if a valid key has been passed and outRanking has
1156894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         *     been populated; false otherwise
1157894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman         */
1158894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public boolean getRanking(String key, Ranking outRanking) {
1159894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            int rank = getRank(key);
116019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman            outRanking.populate(key, rank, !isIntercepted(key),
1161894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    getVisibilityOverride(key), getSuppressedVisualEffects(key),
1162894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    getImportance(key), getImportanceExplanation(key));
1163894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return rank >= 0;
1164894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1165894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1166894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private int getRank(String key) {
1167894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1168894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mRanks == null) {
1169894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildRanksLocked();
1170894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1171894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1172894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Integer rank = mRanks.get(key);
1173894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return rank != null ? rank : -1;
1174894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1175894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1176894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private boolean isIntercepted(String key) {
1177894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1178894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mIntercepted == null) {
1179894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildInterceptedSetLocked();
1180894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1181894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1182894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mIntercepted.contains(key);
1183894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1184894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1185894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private int getVisibilityOverride(String key) {
1186894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1187894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mVisibilityOverrides == null) {
1188894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildVisibilityOverridesLocked();
1189894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1190894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1191894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Integer override = mVisibilityOverrides.get(key);
1192894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if (override == null) {
1193894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return Ranking.VISIBILITY_NO_OVERRIDE;
1194894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1195894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return override.intValue();
1196894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1197894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1198894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private int getSuppressedVisualEffects(String key) {
1199894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1200894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mSuppressedVisualEffects == null) {
1201894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildSuppressedVisualEffectsLocked();
1202894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1203894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1204894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Integer suppressed = mSuppressedVisualEffects.get(key);
1205894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if (suppressed == null) {
1206894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return 0;
1207894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1208894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return suppressed.intValue();
1209894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1210894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1211894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private int getImportance(String key) {
1212894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1213894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mImportance == null) {
1214894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildImportanceLocked();
1215894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1216894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1217894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Integer importance = mImportance.get(key);
1218894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            if (importance == null) {
1219894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return Ranking.IMPORTANCE_DEFAULT;
1220894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1221894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return importance.intValue();
1222894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1223894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1224894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private String getImportanceExplanation(String key) {
1225894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            synchronized (this) {
1226894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                if (mImportanceExplanation == null) {
1227894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                    buildImportanceExplanationLocked();
1228894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                }
1229894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1230894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return mImportanceExplanation.get(key);
1231894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1232894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1233894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1234894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildRanksLocked() {
1235894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
1236894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mRanks = new ArrayMap<>(orderedKeys.length);
1237894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (int i = 0; i < orderedKeys.length; i++) {
1238894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                String key = orderedKeys[i];
1239894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mRanks.put(key, i);
1240894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1241894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1242894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1243894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1244894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildInterceptedSetLocked() {
1245894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            String[] dndInterceptedKeys = mRankingUpdate.getInterceptedKeys();
1246894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mIntercepted = new ArraySet<>(dndInterceptedKeys.length);
1247894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Collections.addAll(mIntercepted, dndInterceptedKeys);
1248894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1249894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1250894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1251894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildVisibilityOverridesLocked() {
1252894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Bundle visibilityBundle = mRankingUpdate.getVisibilityOverrides();
1253894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mVisibilityOverrides = new ArrayMap<>(visibilityBundle.size());
1254894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (String key: visibilityBundle.keySet()) {
1255894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman               mVisibilityOverrides.put(key, visibilityBundle.getInt(key));
1256894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1257894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1258894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1259894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1260894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildSuppressedVisualEffectsLocked() {
1261894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Bundle suppressedBundle = mRankingUpdate.getSuppressedVisualEffects();
1262894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mSuppressedVisualEffects = new ArrayMap<>(suppressedBundle.size());
1263894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (String key: suppressedBundle.keySet()) {
1264894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mSuppressedVisualEffects.put(key, suppressedBundle.getInt(key));
1265894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1266894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1267894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1268894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildImportanceLocked() {
1269894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
1270894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            int[] importance = mRankingUpdate.getImportance();
1271894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mImportance = new ArrayMap<>(orderedKeys.length);
1272894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (int i = 0; i < orderedKeys.length; i++) {
1273894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                String key = orderedKeys[i];
1274894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mImportance.put(key, importance[i]);
1275894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1276894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1277894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1278894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // Locked by 'this'
1279894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        private void buildImportanceExplanationLocked() {
1280894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            Bundle explanationBundle = mRankingUpdate.getImportanceExplanation();
1281894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            mImportanceExplanation = new ArrayMap<>(explanationBundle.size());
1282894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            for (String key: explanationBundle.keySet()) {
1283894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                mImportanceExplanation.put(key, explanationBundle.getString(key));
1284894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1285894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1286894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1287894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        // ----------- Parcelable
1288894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1289894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
1290894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public int describeContents() {
1291894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            return 0;
1292894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1293894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1294894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        @Override
1295894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public void writeToParcel(Parcel dest, int flags) {
1296894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            dest.writeParcelable(mRankingUpdate, flags);
1297894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        }
1298894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1299894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman        public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() {
1300894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            @Override
1301894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            public RankingMap createFromParcel(Parcel source) {
1302894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
1303894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return new RankingMap(rankingUpdate);
1304894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1305894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman
1306894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            @Override
1307894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            public RankingMap[] newArray(int size) {
1308894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman                return new RankingMap[size];
1309894018228b0e0bdbd7aa7e8f47d4a9458789ca82John Bauman            }
1310        };
1311    }
1312
1313    private final class MyHandler extends Handler {
1314        public static final int MSG_ON_NOTIFICATION_POSTED = 1;
1315        public static final int MSG_ON_NOTIFICATION_REMOVED = 2;
1316        public static final int MSG_ON_LISTENER_CONNECTED = 3;
1317        public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
1318        public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5;
1319        public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
1320
1321        public MyHandler(Looper looper) {
1322            super(looper, null, false);
1323        }
1324
1325        @Override
1326        public void handleMessage(Message msg) {
1327            switch (msg.what) {
1328                case MSG_ON_NOTIFICATION_POSTED: {
1329                    SomeArgs args = (SomeArgs) msg.obj;
1330                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
1331                    RankingMap rankingMap = (RankingMap) args.arg2;
1332                    args.recycle();
1333                    onNotificationPosted(sbn, rankingMap);
1334                } break;
1335
1336                case MSG_ON_NOTIFICATION_REMOVED: {
1337                    SomeArgs args = (SomeArgs) msg.obj;
1338                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
1339                    RankingMap rankingMap = (RankingMap) args.arg2;
1340                    args.recycle();
1341                    onNotificationRemoved(sbn, rankingMap);
1342                } break;
1343
1344                case MSG_ON_LISTENER_CONNECTED: {
1345                    onListenerConnected();
1346                } break;
1347
1348                case MSG_ON_NOTIFICATION_RANKING_UPDATE: {
1349                    RankingMap rankingMap = (RankingMap) msg.obj;
1350                    onNotificationRankingUpdate(rankingMap);
1351                } break;
1352
1353                case MSG_ON_LISTENER_HINTS_CHANGED: {
1354                    final int hints = msg.arg1;
1355                    onListenerHintsChanged(hints);
1356                } break;
1357
1358                case MSG_ON_INTERRUPTION_FILTER_CHANGED: {
1359                    final int interruptionFilter = msg.arg1;
1360                    onInterruptionFilterChanged(interruptionFilter);
1361                } break;
1362            }
1363        }
1364    }
1365}
1366