Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package android.service.notification; |
| 18 | |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 19 | import android.annotation.IntDef; |
| 20 | import android.annotation.NonNull; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 21 | import android.annotation.SdkConstant; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 22 | import android.annotation.SystemApi; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 23 | import android.annotation.TestApi; |
Mathew Inwood | e380737 | 2018-08-10 09:51:03 +0100 | [diff] [blame] | 24 | import android.annotation.UnsupportedAppUsage; |
Julia Reynolds | 8149961 | 2017-10-11 14:43:40 -0400 | [diff] [blame] | 25 | import android.app.ActivityManager; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 26 | import android.app.INotificationManager; |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 27 | import android.app.Notification; |
| 28 | import android.app.Notification.Builder; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 29 | import android.app.NotificationChannel; |
| 30 | import android.app.NotificationChannelGroup; |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 31 | import android.app.NotificationManager; |
Selim Cinek | 9acd673 | 2018-03-23 16:39:02 -0700 | [diff] [blame] | 32 | import android.app.Person; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 33 | import android.app.Service; |
Jeff Sharkey | 67f9d50 | 2017-08-05 13:49:13 -0600 | [diff] [blame] | 34 | import android.companion.CompanionDeviceManager; |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 35 | import android.content.ComponentName; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 36 | import android.content.Context; |
| 37 | import android.content.Intent; |
Christoph Studer | cee44ba | 2014-05-20 18:36:43 +0200 | [diff] [blame] | 38 | import android.content.pm.ParceledListSlice; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 39 | import android.graphics.Bitmap; |
Daniel Sandler | f5a7838 | 2015-05-15 23:59:36 -0400 | [diff] [blame] | 40 | import android.graphics.drawable.BitmapDrawable; |
| 41 | import android.graphics.drawable.Drawable; |
| 42 | import android.graphics.drawable.Icon; |
Julia Reynolds | d9228f1 | 2015-10-20 10:37:27 -0400 | [diff] [blame] | 43 | import android.os.Build; |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 44 | import android.os.Bundle; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 45 | import android.os.Handler; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 46 | import android.os.IBinder; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 47 | import android.os.Looper; |
| 48 | import android.os.Message; |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 49 | import android.os.Parcel; |
| 50 | import android.os.Parcelable; |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 51 | import android.os.RemoteException; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 52 | import android.os.ServiceManager; |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 53 | import android.os.UserHandle; |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 54 | import android.util.ArrayMap; |
| 55 | import android.util.ArraySet; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 56 | import android.util.Log; |
Adrian Roos | 5081c0d | 2016-02-26 16:04:19 -0800 | [diff] [blame] | 57 | import android.widget.RemoteViews; |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 58 | |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 59 | import com.android.internal.annotations.GuardedBy; |
Dan Sandler | 1d958f8 | 2018-01-09 21:10:26 -0500 | [diff] [blame] | 60 | import com.android.internal.annotations.VisibleForTesting; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 61 | import com.android.internal.os.SomeArgs; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 62 | |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 63 | import java.lang.annotation.Retention; |
| 64 | import java.lang.annotation.RetentionPolicy; |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 65 | import java.util.ArrayList; |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 66 | import java.util.Collections; |
Christoph Studer | cee44ba | 2014-05-20 18:36:43 +0200 | [diff] [blame] | 67 | import java.util.List; |
| 68 | |
Scott Main | 04667da | 2013-04-25 16:57:16 -0700 | [diff] [blame] | 69 | /** |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 70 | * A service that receives calls from the system when new notifications are |
| 71 | * posted or removed, or their ranking changed. |
Scott Main | 04667da | 2013-04-25 16:57:16 -0700 | [diff] [blame] | 72 | * <p>To extend this class, you must declare the service in your manifest file with |
Jeff Sharkey | 67f9d50 | 2017-08-05 13:49:13 -0600 | [diff] [blame] | 73 | * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission |
Scott Main | 04667da | 2013-04-25 16:57:16 -0700 | [diff] [blame] | 74 | * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p> |
| 75 | * <pre> |
| 76 | * <service android:name=".NotificationListener" |
| 77 | * android:label="@string/service_name" |
| 78 | * android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"> |
| 79 | * <intent-filter> |
| 80 | * <action android:name="android.service.notification.NotificationListenerService" /> |
| 81 | * </intent-filter> |
| 82 | * </service></pre> |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 83 | * |
| 84 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 85 | * before performing any operations. The {@link #requestRebind(ComponentName)} |
| 86 | * method is the <i>only</i> one that is safe to call before {@link #onListenerConnected()} |
| 87 | * or after {@link #onListenerDisconnected()}. |
| 88 | * </p> |
Julia Reynolds | 8149961 | 2017-10-11 14:43:40 -0400 | [diff] [blame] | 89 | * <p> Notification listeners cannot get notification access or be bound by the system on |
Benjamin Miller | 604843b | 2018-02-27 11:29:16 +0000 | [diff] [blame] | 90 | * {@linkplain ActivityManager#isLowRamDevice() low-RAM} devices. The system also ignores |
| 91 | * notification listeners running in a work profile. A |
| 92 | * {@link android.app.admin.DevicePolicyManager} might block notifications originating from a work |
| 93 | * profile.</p> |
Julia Reynolds | fe99219 | 2018-09-07 10:33:19 -0400 | [diff] [blame] | 94 | * <p> |
| 95 | * From {@link Build.VERSION_CODES#N} onward all callbacks are called on the main thread. Prior |
| 96 | * to N, there is no guarantee on what thread the callback will happen. |
| 97 | * </p> |
Scott Main | 04667da | 2013-04-25 16:57:16 -0700 | [diff] [blame] | 98 | */ |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 99 | public abstract class NotificationListenerService extends Service { |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 100 | |
Mathew Inwood | 31755f9 | 2018-12-20 13:53:36 +0000 | [diff] [blame] | 101 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
Julia Reynolds | 7e1ffd7 | 2016-11-28 13:50:22 -0500 | [diff] [blame] | 102 | private final String TAG = getClass().getSimpleName(); |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 103 | |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 104 | /** |
| 105 | * {@link #getCurrentInterruptionFilter() Interruption filter} constant - |
| 106 | * Normal interruption filter. |
| 107 | */ |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 108 | public static final int INTERRUPTION_FILTER_ALL |
| 109 | = NotificationManager.INTERRUPTION_FILTER_ALL; |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 110 | |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 111 | /** |
| 112 | * {@link #getCurrentInterruptionFilter() Interruption filter} constant - |
| 113 | * Priority interruption filter. |
| 114 | */ |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 115 | public static final int INTERRUPTION_FILTER_PRIORITY |
| 116 | = NotificationManager.INTERRUPTION_FILTER_PRIORITY; |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 117 | |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 118 | /** |
| 119 | * {@link #getCurrentInterruptionFilter() Interruption filter} constant - |
| 120 | * No interruptions filter. |
| 121 | */ |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 122 | public static final int INTERRUPTION_FILTER_NONE |
| 123 | = NotificationManager.INTERRUPTION_FILTER_NONE; |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 124 | |
John Spurlock | 4f1163c | 2015-04-02 17:41:21 -0400 | [diff] [blame] | 125 | /** |
| 126 | * {@link #getCurrentInterruptionFilter() Interruption filter} constant - |
| 127 | * Alarms only interruption filter. |
| 128 | */ |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 129 | public static final int INTERRUPTION_FILTER_ALARMS |
| 130 | = NotificationManager.INTERRUPTION_FILTER_ALARMS; |
John Spurlock | 4f1163c | 2015-04-02 17:41:21 -0400 | [diff] [blame] | 131 | |
John Spurlock | 8310410 | 2015-02-12 23:25:12 -0500 | [diff] [blame] | 132 | /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when |
| 133 | * the value is unavailable for any reason. For example, before the notification listener |
| 134 | * is connected. |
| 135 | * |
| 136 | * {@see #onListenerConnected()} |
| 137 | */ |
John Spurlock | 8077493 | 2015-05-07 17:38:50 -0400 | [diff] [blame] | 138 | public static final int INTERRUPTION_FILTER_UNKNOWN |
| 139 | = NotificationManager.INTERRUPTION_FILTER_UNKNOWN; |
John Spurlock | 8310410 | 2015-02-12 23:25:12 -0500 | [diff] [blame] | 140 | |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 141 | /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI |
| 142 | * should disable notification sound, vibrating and other visual or aural effects. |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 143 | * This does not change the interruption filter, only the effects. **/ |
| 144 | public static final int HINT_HOST_DISABLE_EFFECTS = 1; |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 145 | |
Bryce Lee | 7219ada | 2016-04-08 10:54:23 -0700 | [diff] [blame] | 146 | /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI |
| 147 | * should disable notification sound, but not phone calls. |
| 148 | * This does not change the interruption filter, only the effects. **/ |
| 149 | public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 1 << 1; |
| 150 | |
| 151 | /** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI |
| 152 | * should disable phone call sounds, buyt not notification sound. |
| 153 | * This does not change the interruption filter, only the effects. **/ |
| 154 | public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 1 << 2; |
| 155 | |
Julia Reynolds | d560729 | 2016-02-05 15:25:58 -0500 | [diff] [blame] | 156 | /** |
| 157 | * Whether notification suppressed by DND should not interruption visually when the screen is |
| 158 | * off. |
Julia Reynolds | ccc6ae6 | 2018-03-01 16:24:49 -0500 | [diff] [blame] | 159 | * |
| 160 | * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}. |
Julia Reynolds | d560729 | 2016-02-05 15:25:58 -0500 | [diff] [blame] | 161 | */ |
Julia Reynolds | ccc6ae6 | 2018-03-01 16:24:49 -0500 | [diff] [blame] | 162 | @Deprecated |
Julia Reynolds | d560729 | 2016-02-05 15:25:58 -0500 | [diff] [blame] | 163 | public static final int SUPPRESSED_EFFECT_SCREEN_OFF = |
| 164 | NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; |
| 165 | /** |
| 166 | * Whether notification suppressed by DND should not interruption visually when the screen is |
| 167 | * on. |
Julia Reynolds | ccc6ae6 | 2018-03-01 16:24:49 -0500 | [diff] [blame] | 168 | * |
| 169 | * @deprecated Use the more specific visual effects in {@link NotificationManager.Policy}. |
Julia Reynolds | d560729 | 2016-02-05 15:25:58 -0500 | [diff] [blame] | 170 | */ |
Julia Reynolds | ccc6ae6 | 2018-03-01 16:24:49 -0500 | [diff] [blame] | 171 | @Deprecated |
Julia Reynolds | 6172158 | 2016-01-05 08:35:25 -0500 | [diff] [blame] | 172 | public static final int SUPPRESSED_EFFECT_SCREEN_ON = |
| 173 | NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 174 | |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 175 | |
| 176 | // Notification cancellation reasons |
| 177 | |
Julia Reynolds | a11d0b1 | 2017-02-16 15:01:36 -0500 | [diff] [blame] | 178 | /** Notification was canceled by the status bar reporting a notification click. */ |
Julia Reynolds | f619bc5 | 2017-03-17 08:32:23 -0400 | [diff] [blame] | 179 | public static final int REASON_CLICK = 1; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 180 | /** Notification was canceled by the status bar reporting a user dismissal. */ |
Julia Reynolds | f619bc5 | 2017-03-17 08:32:23 -0400 | [diff] [blame] | 181 | public static final int REASON_CANCEL = 2; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 182 | /** Notification was canceled by the status bar reporting a user dismiss all. */ |
Julia Reynolds | f619bc5 | 2017-03-17 08:32:23 -0400 | [diff] [blame] | 183 | public static final int REASON_CANCEL_ALL = 3; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 184 | /** Notification was canceled by the status bar reporting an inflation error. */ |
Julia Reynolds | f619bc5 | 2017-03-17 08:32:23 -0400 | [diff] [blame] | 185 | public static final int REASON_ERROR = 4; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 186 | /** Notification was canceled by the package manager modifying the package. */ |
| 187 | public static final int REASON_PACKAGE_CHANGED = 5; |
| 188 | /** Notification was canceled by the owning user context being stopped. */ |
| 189 | public static final int REASON_USER_STOPPED = 6; |
| 190 | /** Notification was canceled by the user banning the package. */ |
| 191 | public static final int REASON_PACKAGE_BANNED = 7; |
| 192 | /** Notification was canceled by the app canceling this specific notification. */ |
| 193 | public static final int REASON_APP_CANCEL = 8; |
| 194 | /** Notification was canceled by the app cancelling all its notifications. */ |
| 195 | public static final int REASON_APP_CANCEL_ALL = 9; |
| 196 | /** Notification was canceled by a listener reporting a user dismissal. */ |
| 197 | public static final int REASON_LISTENER_CANCEL = 10; |
| 198 | /** Notification was canceled by a listener reporting a user dismiss all. */ |
| 199 | public static final int REASON_LISTENER_CANCEL_ALL = 11; |
| 200 | /** Notification was canceled because it was a member of a canceled group. */ |
| 201 | public static final int REASON_GROUP_SUMMARY_CANCELED = 12; |
| 202 | /** Notification was canceled because it was an invisible member of a group. */ |
| 203 | public static final int REASON_GROUP_OPTIMIZATION = 13; |
| 204 | /** Notification was canceled by the device administrator suspending the package. */ |
| 205 | public static final int REASON_PACKAGE_SUSPENDED = 14; |
| 206 | /** Notification was canceled by the owning managed profile being turned off. */ |
| 207 | public static final int REASON_PROFILE_TURNED_OFF = 15; |
| 208 | /** Autobundled summary notification was canceled because its group was unbundled */ |
| 209 | public static final int REASON_UNAUTOBUNDLED = 16; |
| 210 | /** Notification was canceled by the user banning the channel. */ |
| 211 | public static final int REASON_CHANNEL_BANNED = 17; |
| 212 | /** Notification was snoozed. */ |
| 213 | public static final int REASON_SNOOZED = 18; |
Julia Reynolds | 2a12874 | 2016-11-28 14:29:25 -0500 | [diff] [blame] | 214 | /** Notification was canceled due to timeout */ |
| 215 | public static final int REASON_TIMEOUT = 19; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 216 | |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 217 | /** |
| 218 | * The full trim of the StatusBarNotification including all its features. |
| 219 | * |
| 220 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 221 | * @removed |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 222 | */ |
| 223 | @SystemApi |
| 224 | public static final int TRIM_FULL = 0; |
| 225 | |
| 226 | /** |
| 227 | * A light trim of the StatusBarNotification excluding the following features: |
| 228 | * |
| 229 | * <ol> |
| 230 | * <li>{@link Notification#tickerView tickerView}</li> |
| 231 | * <li>{@link Notification#contentView contentView}</li> |
| 232 | * <li>{@link Notification#largeIcon largeIcon}</li> |
| 233 | * <li>{@link Notification#bigContentView bigContentView}</li> |
| 234 | * <li>{@link Notification#headsUpContentView headsUpContentView}</li> |
| 235 | * <li>{@link Notification#EXTRA_LARGE_ICON extras[EXTRA_LARGE_ICON]}</li> |
| 236 | * <li>{@link Notification#EXTRA_LARGE_ICON_BIG extras[EXTRA_LARGE_ICON_BIG]}</li> |
| 237 | * <li>{@link Notification#EXTRA_PICTURE extras[EXTRA_PICTURE]}</li> |
Christoph Studer | 223f44e | 2014-09-02 14:59:32 +0200 | [diff] [blame] | 238 | * <li>{@link Notification#EXTRA_BIG_TEXT extras[EXTRA_BIG_TEXT]}</li> |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 239 | * </ol> |
| 240 | * |
| 241 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 242 | * @removed |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 243 | */ |
| 244 | @SystemApi |
| 245 | public static final int TRIM_LIGHT = 1; |
| 246 | |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 247 | |
| 248 | /** @hide */ |
Jeff Sharkey | ce8db99 | 2017-12-13 20:05:05 -0700 | [diff] [blame] | 249 | @IntDef(prefix = { "NOTIFICATION_CHANNEL_OR_GROUP_" }, value = { |
| 250 | NOTIFICATION_CHANNEL_OR_GROUP_ADDED, |
| 251 | NOTIFICATION_CHANNEL_OR_GROUP_UPDATED, |
| 252 | NOTIFICATION_CHANNEL_OR_GROUP_DELETED |
| 253 | }) |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 254 | @Retention(RetentionPolicy.SOURCE) |
| 255 | public @interface ChannelOrGroupModificationTypes {} |
| 256 | |
| 257 | /** |
| 258 | * Channel or group modification reason provided to |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 259 | * {@link #onNotificationChannelModified(String, UserHandle,NotificationChannel, int)} or |
| 260 | * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, |
| 261 | * int)}- the provided object was created. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 262 | */ |
| 263 | public static final int NOTIFICATION_CHANNEL_OR_GROUP_ADDED = 1; |
| 264 | |
| 265 | /** |
| 266 | * Channel or group modification reason provided to |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 267 | * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or |
| 268 | * {@link #onNotificationChannelGroupModified(String, UserHandle,NotificationChannelGroup, int)} |
| 269 | * - the provided object was updated. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 270 | */ |
| 271 | public static final int NOTIFICATION_CHANNEL_OR_GROUP_UPDATED = 2; |
| 272 | |
| 273 | /** |
| 274 | * Channel or group modification reason provided to |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 275 | * {@link #onNotificationChannelModified(String, UserHandle, NotificationChannel, int)} or |
| 276 | * {@link #onNotificationChannelGroupModified(String, UserHandle, NotificationChannelGroup, |
| 277 | * int)}- the provided object was deleted. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 278 | */ |
| 279 | public static final int NOTIFICATION_CHANNEL_OR_GROUP_DELETED = 3; |
| 280 | |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 281 | private final Object mLock = new Object(); |
| 282 | |
Mathew Inwood | 8c854f8 | 2018-09-14 12:35:36 +0100 | [diff] [blame] | 283 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 284 | private Handler mHandler; |
| 285 | |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 286 | /** @hide */ |
Mathew Inwood | e380737 | 2018-08-10 09:51:03 +0100 | [diff] [blame] | 287 | @UnsupportedAppUsage |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 288 | protected NotificationListenerWrapper mWrapper = null; |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 289 | private boolean isConnected = false; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 290 | |
| 291 | @GuardedBy("mLock") |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 292 | private RankingMap mRankingMap; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 293 | |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 294 | /** |
| 295 | * @hide |
| 296 | */ |
Mathew Inwood | 31755f9 | 2018-12-20 13:53:36 +0000 | [diff] [blame] | 297 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 298 | protected INotificationManager mNoMan; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 299 | |
Chris Wren | e0ba7eb | 2016-03-04 17:30:43 -0500 | [diff] [blame] | 300 | /** |
| 301 | * Only valid after a successful call to (@link registerAsService}. |
| 302 | * @hide |
| 303 | */ |
| 304 | protected int mCurrentUser; |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 305 | |
Chris Wren | e0ba7eb | 2016-03-04 17:30:43 -0500 | [diff] [blame] | 306 | /** |
| 307 | * This context is required for system services since NotificationListenerService isn't |
| 308 | * started as a real Service and hence no context is available.. |
| 309 | * @hide |
| 310 | */ |
| 311 | protected Context mSystemContext; |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 312 | |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 313 | /** |
| 314 | * The {@link Intent} that must be declared as handled by the service. |
| 315 | */ |
| 316 | @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) |
| 317 | public static final String SERVICE_INTERFACE |
| 318 | = "android.service.notification.NotificationListenerService"; |
| 319 | |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 320 | @Override |
| 321 | protected void attachBaseContext(Context base) { |
| 322 | super.attachBaseContext(base); |
| 323 | mHandler = new MyHandler(getMainLooper()); |
| 324 | } |
| 325 | |
Ruben Brunk | dd18a0b | 2015-12-04 16:16:31 -0800 | [diff] [blame] | 326 | /** |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 327 | * Implement this method to learn about new notifications as they are posted by apps. |
| 328 | * |
| 329 | * @param sbn A data structure encapsulating the original {@link android.app.Notification} |
| 330 | * object as well as its identifying information (tag and id) and source |
| 331 | * (package name). |
| 332 | */ |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 333 | public void onNotificationPosted(StatusBarNotification sbn) { |
| 334 | // optional |
| 335 | } |
| 336 | |
| 337 | /** |
| 338 | * Implement this method to learn about new notifications as they are posted by apps. |
| 339 | * |
| 340 | * @param sbn A data structure encapsulating the original {@link android.app.Notification} |
| 341 | * object as well as its identifying information (tag and id) and source |
| 342 | * (package name). |
| 343 | * @param rankingMap The current ranking map that can be used to retrieve ranking information |
| 344 | * for active notifications, including the newly posted one. |
| 345 | */ |
| 346 | public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { |
| 347 | onNotificationPosted(sbn); |
| 348 | } |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 349 | |
| 350 | /** |
| 351 | * Implement this method to learn when notifications are removed. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 352 | * <p> |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 353 | * This might occur because the user has dismissed the notification using system UI (or another |
| 354 | * notification listener) or because the app has withdrawn the notification. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 355 | * <p> |
Daniel Sandler | 1a497d3 | 2013-04-18 14:52:45 -0400 | [diff] [blame] | 356 | * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the |
Scott Main | 04667da | 2013-04-25 16:57:16 -0700 | [diff] [blame] | 357 | * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight |
Daniel Sandler | 1a497d3 | 2013-04-18 14:52:45 -0400 | [diff] [blame] | 358 | * fields such as {@link android.app.Notification#contentView} and |
| 359 | * {@link android.app.Notification#largeIcon}. However, all other fields on |
| 360 | * {@link StatusBarNotification}, sufficient to match this call with a prior call to |
| 361 | * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 362 | * |
Daniel Sandler | 1a497d3 | 2013-04-18 14:52:45 -0400 | [diff] [blame] | 363 | * @param sbn A data structure encapsulating at least the original information (tag and id) |
| 364 | * and source (package name) used to post the {@link android.app.Notification} that |
| 365 | * was just removed. |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 366 | */ |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 367 | public void onNotificationRemoved(StatusBarNotification sbn) { |
| 368 | // optional |
| 369 | } |
| 370 | |
| 371 | /** |
| 372 | * Implement this method to learn when notifications are removed. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 373 | * <p> |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 374 | * This might occur because the user has dismissed the notification using system UI (or another |
| 375 | * notification listener) or because the app has withdrawn the notification. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 376 | * <p> |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 377 | * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the |
| 378 | * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight |
| 379 | * fields such as {@link android.app.Notification#contentView} and |
| 380 | * {@link android.app.Notification#largeIcon}. However, all other fields on |
| 381 | * {@link StatusBarNotification}, sufficient to match this call with a prior call to |
| 382 | * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. |
| 383 | * |
| 384 | * @param sbn A data structure encapsulating at least the original information (tag and id) |
| 385 | * and source (package name) used to post the {@link android.app.Notification} that |
| 386 | * was just removed. |
| 387 | * @param rankingMap The current ranking map that can be used to retrieve ranking information |
| 388 | * for active notifications. |
| 389 | * |
| 390 | */ |
| 391 | public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { |
| 392 | onNotificationRemoved(sbn); |
| 393 | } |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 394 | |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 395 | |
| 396 | /** |
| 397 | * Implement this method to learn when notifications are removed and why. |
| 398 | * <p> |
| 399 | * This might occur because the user has dismissed the notification using system UI (or another |
| 400 | * notification listener) or because the app has withdrawn the notification. |
| 401 | * <p> |
| 402 | * NOTE: The {@link StatusBarNotification} object you receive will be "light"; that is, the |
| 403 | * result from {@link StatusBarNotification#getNotification} may be missing some heavyweight |
| 404 | * fields such as {@link android.app.Notification#contentView} and |
| 405 | * {@link android.app.Notification#largeIcon}. However, all other fields on |
| 406 | * {@link StatusBarNotification}, sufficient to match this call with a prior call to |
| 407 | * {@link #onNotificationPosted(StatusBarNotification)}, will be intact. |
| 408 | * |
| 409 | ** @param sbn A data structure encapsulating at least the original information (tag and id) |
| 410 | * and source (package name) used to post the {@link android.app.Notification} that |
| 411 | * was just removed. |
| 412 | * @param rankingMap The current ranking map that can be used to retrieve ranking information |
| 413 | * for active notifications. |
| 414 | * @param reason see {@link #REASON_LISTENER_CANCEL}, etc. |
| 415 | */ |
| 416 | public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, |
| 417 | int reason) { |
| 418 | onNotificationRemoved(sbn, rankingMap); |
| 419 | } |
| 420 | |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 421 | /** |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 422 | * NotificationStats are not populated for notification listeners, so fall back to |
| 423 | * {@link #onNotificationRemoved(StatusBarNotification, RankingMap, int)}. |
| 424 | * |
| 425 | * @hide |
| 426 | */ |
| 427 | @TestApi |
| 428 | public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, |
| 429 | NotificationStats stats, int reason) { |
| 430 | onNotificationRemoved(sbn, rankingMap, reason); |
| 431 | } |
| 432 | |
| 433 | /** |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 434 | * Implement this method to learn about when the listener is enabled and connected to |
Christoph Studer | cee44ba | 2014-05-20 18:36:43 +0200 | [diff] [blame] | 435 | * the notification manager. You are safe to call {@link #getActiveNotifications()} |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 436 | * at this time. |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 437 | */ |
Christoph Studer | cee44ba | 2014-05-20 18:36:43 +0200 | [diff] [blame] | 438 | public void onListenerConnected() { |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 439 | // optional |
| 440 | } |
| 441 | |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 442 | /** |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 443 | * Implement this method to learn about when the listener is disconnected from the |
| 444 | * notification manager.You will not receive any events after this call, and may only |
| 445 | * call {@link #requestRebind(ComponentName)} at this time. |
| 446 | */ |
| 447 | public void onListenerDisconnected() { |
| 448 | // optional |
| 449 | } |
| 450 | |
| 451 | /** |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 452 | * Implement this method to be notified when the notification ranking changes. |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 453 | * |
| 454 | * @param rankingMap The current ranking map that can be used to retrieve ranking information |
| 455 | * for active notifications. |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 456 | */ |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 457 | public void onNotificationRankingUpdate(RankingMap rankingMap) { |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 458 | // optional |
| 459 | } |
| 460 | |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 461 | /** |
| 462 | * Implement this method to be notified when the |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 463 | * {@link #getCurrentListenerHints() Listener hints} change. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 464 | * |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 465 | * @param hints The current {@link #getCurrentListenerHints() listener hints}. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 466 | */ |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 467 | public void onListenerHintsChanged(int hints) { |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 468 | // optional |
| 469 | } |
| 470 | |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 471 | /** |
Julia Reynolds | 12ad7ca | 2019-01-28 09:29:16 -0500 | [diff] [blame] | 472 | * Implement this method to be notified when the behavior of silent notifications in the status |
| 473 | * bar changes. See {@link NotificationManager#shouldHideSilentStatusBarIcons()}. |
| 474 | * |
| 475 | * @param hideSilentStatusIcons whether or not status bar icons should be hidden for silent |
| 476 | * notifications |
| 477 | */ |
| 478 | public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { |
| 479 | // optional |
| 480 | } |
| 481 | |
| 482 | /** |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 483 | * Implement this method to learn about notification channel modifications. |
| 484 | * |
| 485 | * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated |
| 486 | * device} in order to receive this callback. |
| 487 | * |
| 488 | * @param pkg The package the channel belongs to. |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 489 | * @param user The user on which the change was made. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 490 | * @param channel The channel that has changed. |
| 491 | * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, |
| 492 | * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, |
| 493 | * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. |
| 494 | */ |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 495 | public void onNotificationChannelModified(String pkg, UserHandle user, |
| 496 | NotificationChannel channel, @ChannelOrGroupModificationTypes int modificationType) { |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 497 | // optional |
| 498 | } |
| 499 | |
| 500 | /** |
| 501 | * Implement this method to learn about notification channel group modifications. |
| 502 | * |
| 503 | * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated |
| 504 | * device} in order to receive this callback. |
| 505 | * |
| 506 | * @param pkg The package the group belongs to. |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 507 | * @param user The user on which the change was made. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 508 | * @param group The group that has changed. |
| 509 | * @param modificationType One of {@link #NOTIFICATION_CHANNEL_OR_GROUP_ADDED}, |
| 510 | * {@link #NOTIFICATION_CHANNEL_OR_GROUP_UPDATED}, |
| 511 | * {@link #NOTIFICATION_CHANNEL_OR_GROUP_DELETED}. |
| 512 | */ |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 513 | public void onNotificationChannelGroupModified(String pkg, UserHandle user, |
| 514 | NotificationChannelGroup group, @ChannelOrGroupModificationTypes int modificationType) { |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 515 | // optional |
| 516 | } |
| 517 | |
| 518 | /** |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 519 | * Implement this method to be notified when the |
| 520 | * {@link #getCurrentInterruptionFilter() interruption filter} changed. |
| 521 | * |
| 522 | * @param interruptionFilter The current |
| 523 | * {@link #getCurrentInterruptionFilter() interruption filter}. |
| 524 | */ |
| 525 | public void onInterruptionFilterChanged(int interruptionFilter) { |
| 526 | // optional |
| 527 | } |
| 528 | |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 529 | /** @hide */ |
Mathew Inwood | 31755f9 | 2018-12-20 13:53:36 +0000 | [diff] [blame] | 530 | @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 531 | protected final INotificationManager getNotificationInterface() { |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 532 | if (mNoMan == null) { |
| 533 | mNoMan = INotificationManager.Stub.asInterface( |
| 534 | ServiceManager.getService(Context.NOTIFICATION_SERVICE)); |
| 535 | } |
| 536 | return mNoMan; |
| 537 | } |
| 538 | |
| 539 | /** |
| 540 | * Inform the notification manager about dismissal of a single notification. |
| 541 | * <p> |
| 542 | * Use this if your listener has a user interface that allows the user to dismiss individual |
| 543 | * notifications, similar to the behavior of Android's status bar and notification panel. |
| 544 | * It should be called after the user dismisses a single notification using your UI; |
| 545 | * upon being informed, the notification manager will actually remove the notification |
| 546 | * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 547 | * <p> |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 548 | * <b>Note:</b> If your listener allows the user to fire a notification's |
| 549 | * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call |
| 550 | * this method at that time <i>if</i> the Notification in question has the |
| 551 | * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set. |
| 552 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 553 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 554 | * before performing this operation. |
| 555 | * |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 556 | * @param pkg Package of the notifying app. |
| 557 | * @param tag Tag of the notification as specified by the notifying app in |
| 558 | * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. |
| 559 | * @param id ID of the notification as specified by the notifying app in |
| 560 | * {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}. |
Kenny Guy | a263e4e | 2014-03-03 18:24:03 +0000 | [diff] [blame] | 561 | * <p> |
| 562 | * @deprecated Use {@link #cancelNotification(String key)} |
Dianne Hackborn | 955d8d6 | 2014-10-07 20:17:19 -0700 | [diff] [blame] | 563 | * instead. Beginning with {@link android.os.Build.VERSION_CODES#LOLLIPOP} this method will no longer |
Kenny Guy | a263e4e | 2014-03-03 18:24:03 +0000 | [diff] [blame] | 564 | * cancel the notification. It will continue to cancel the notification for applications |
Dianne Hackborn | 955d8d6 | 2014-10-07 20:17:19 -0700 | [diff] [blame] | 565 | * whose {@code targetSdkVersion} is earlier than {@link android.os.Build.VERSION_CODES#LOLLIPOP}. |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 566 | */ |
Aurimas Liutikas | 514c5ef | 2016-05-24 15:22:55 -0700 | [diff] [blame] | 567 | @Deprecated |
Daniel Sandler | e6f7f2e | 2013-04-25 15:44:16 -0400 | [diff] [blame] | 568 | public final void cancelNotification(String pkg, String tag, int id) { |
John Spurlock | da9a3be | 2014-02-12 12:12:26 -0500 | [diff] [blame] | 569 | if (!isBound()) return; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 570 | try { |
Kenny Guy | a263e4e | 2014-03-03 18:24:03 +0000 | [diff] [blame] | 571 | getNotificationInterface().cancelNotificationFromListener( |
| 572 | mWrapper, pkg, tag, id); |
| 573 | } catch (android.os.RemoteException ex) { |
| 574 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 575 | } |
| 576 | } |
| 577 | |
| 578 | /** |
| 579 | * Inform the notification manager about dismissal of a single notification. |
| 580 | * <p> |
| 581 | * Use this if your listener has a user interface that allows the user to dismiss individual |
| 582 | * notifications, similar to the behavior of Android's status bar and notification panel. |
| 583 | * It should be called after the user dismisses a single notification using your UI; |
| 584 | * upon being informed, the notification manager will actually remove the notification |
| 585 | * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 586 | * <p> |
Kenny Guy | a263e4e | 2014-03-03 18:24:03 +0000 | [diff] [blame] | 587 | * <b>Note:</b> If your listener allows the user to fire a notification's |
| 588 | * {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call |
| 589 | * this method at that time <i>if</i> the Notification in question has the |
| 590 | * {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set. |
| 591 | * <p> |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 592 | * |
| 593 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 594 | * before performing this operation. |
| 595 | * |
Kenny Guy | a263e4e | 2014-03-03 18:24:03 +0000 | [diff] [blame] | 596 | * @param key Notification to dismiss from {@link StatusBarNotification#getKey()}. |
| 597 | */ |
| 598 | public final void cancelNotification(String key) { |
| 599 | if (!isBound()) return; |
| 600 | try { |
| 601 | getNotificationInterface().cancelNotificationsFromListener(mWrapper, |
Daniel Sandler | f5a7838 | 2015-05-15 23:59:36 -0400 | [diff] [blame] | 602 | new String[] { key }); |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 603 | } catch (android.os.RemoteException ex) { |
| 604 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | /** |
| 609 | * Inform the notification manager about dismissal of all notifications. |
| 610 | * <p> |
| 611 | * Use this if your listener has a user interface that allows the user to dismiss all |
| 612 | * notifications, similar to the behavior of Android's status bar and notification panel. |
| 613 | * It should be called after the user invokes the "dismiss all" function of your UI; |
| 614 | * upon being informed, the notification manager will actually remove all active notifications |
| 615 | * and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks. |
| 616 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 617 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 618 | * before performing this operation. |
| 619 | * |
Daniel Sandler | e6f7f2e | 2013-04-25 15:44:16 -0400 | [diff] [blame] | 620 | * {@see #cancelNotification(String, String, int)} |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 621 | */ |
Daniel Sandler | e6f7f2e | 2013-04-25 15:44:16 -0400 | [diff] [blame] | 622 | public final void cancelAllNotifications() { |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 623 | cancelNotifications(null /*all*/); |
| 624 | } |
| 625 | |
| 626 | /** |
| 627 | * Inform the notification manager about dismissal of specific notifications. |
| 628 | * <p> |
| 629 | * Use this if your listener has a user interface that allows the user to dismiss |
| 630 | * multiple notifications at once. |
| 631 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 632 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 633 | * before performing this operation. |
| 634 | * |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 635 | * @param keys Notifications to dismiss, or {@code null} to dismiss all. |
| 636 | * |
| 637 | * {@see #cancelNotification(String, String, int)} |
| 638 | */ |
| 639 | public final void cancelNotifications(String[] keys) { |
John Spurlock | da9a3be | 2014-02-12 12:12:26 -0500 | [diff] [blame] | 640 | if (!isBound()) return; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 641 | try { |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 642 | getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys); |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 643 | } catch (android.os.RemoteException ex) { |
| 644 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 645 | } |
| 646 | } |
| 647 | |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 648 | /** |
Julia Reynolds | 72f1cbb | 2016-09-19 14:57:31 -0400 | [diff] [blame] | 649 | * Inform the notification manager about snoozing a specific notification. |
| 650 | * <p> |
| 651 | * Use this if your listener has a user interface that allows the user to snooze a notification |
Julia Reynolds | 7967230 | 2017-01-12 08:30:16 -0500 | [diff] [blame] | 652 | * until a given {@link SnoozeCriterion}. It should be called after the user snoozes a single |
| 653 | * notification using your UI; upon being informed, the notification manager will actually |
| 654 | * remove the notification and you will get an |
| 655 | * {@link #onNotificationRemoved(StatusBarNotification)} callback. When the snoozing period |
| 656 | * expires, you will get a {@link #onNotificationPosted(StatusBarNotification, RankingMap)} |
| 657 | * callback for the notification. |
| 658 | * @param key The key of the notification to snooze |
| 659 | * @param snoozeCriterionId The{@link SnoozeCriterion#getId()} of a context to snooze the |
| 660 | * notification until. |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 661 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 662 | * @removed |
Julia Reynolds | 7967230 | 2017-01-12 08:30:16 -0500 | [diff] [blame] | 663 | */ |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 664 | @SystemApi |
Julia Reynolds | 7967230 | 2017-01-12 08:30:16 -0500 | [diff] [blame] | 665 | public final void snoozeNotification(String key, String snoozeCriterionId) { |
| 666 | if (!isBound()) return; |
| 667 | try { |
| 668 | getNotificationInterface().snoozeNotificationUntilContextFromListener( |
| 669 | mWrapper, key, snoozeCriterionId); |
| 670 | } catch (android.os.RemoteException ex) { |
| 671 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 672 | } |
| 673 | } |
| 674 | |
| 675 | /** |
| 676 | * Inform the notification manager about snoozing a specific notification. |
| 677 | * <p> |
| 678 | * Use this if your listener has a user interface that allows the user to snooze a notification |
Julia Reynolds | 5098977 | 2017-02-23 14:32:16 -0500 | [diff] [blame] | 679 | * for a time. It should be called after the user snoozes a single notification using |
Julia Reynolds | 72f1cbb | 2016-09-19 14:57:31 -0400 | [diff] [blame] | 680 | * your UI; upon being informed, the notification manager will actually remove the notification |
| 681 | * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the |
| 682 | * snoozing period expires, you will get a |
| 683 | * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the |
| 684 | * notification. |
| 685 | * @param key The key of the notification to snooze |
Julia Reynolds | 5098977 | 2017-02-23 14:32:16 -0500 | [diff] [blame] | 686 | * @param durationMs A duration to snooze the notification for, in milliseconds. |
Julia Reynolds | 72f1cbb | 2016-09-19 14:57:31 -0400 | [diff] [blame] | 687 | */ |
Julia Reynolds | 5098977 | 2017-02-23 14:32:16 -0500 | [diff] [blame] | 688 | public final void snoozeNotification(String key, long durationMs) { |
Julia Reynolds | 72f1cbb | 2016-09-19 14:57:31 -0400 | [diff] [blame] | 689 | if (!isBound()) return; |
| 690 | try { |
Julia Reynolds | b6c1f99 | 2016-11-22 09:26:46 -0500 | [diff] [blame] | 691 | getNotificationInterface().snoozeNotificationUntilFromListener( |
Julia Reynolds | 5098977 | 2017-02-23 14:32:16 -0500 | [diff] [blame] | 692 | mWrapper, key, durationMs); |
Julia Reynolds | b6c1f99 | 2016-11-22 09:26:46 -0500 | [diff] [blame] | 693 | } catch (android.os.RemoteException ex) { |
| 694 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 695 | } |
| 696 | } |
| 697 | |
Julia Reynolds | 72f1cbb | 2016-09-19 14:57:31 -0400 | [diff] [blame] | 698 | |
| 699 | /** |
Amith Yamasani | f47e51e | 2015-04-17 10:02:15 -0700 | [diff] [blame] | 700 | * Inform the notification manager that these notifications have been viewed by the |
Amith Yamasani | c6ecbce | 2015-06-23 12:58:43 -0700 | [diff] [blame] | 701 | * user. This should only be called when there is sufficient confidence that the user is |
| 702 | * looking at the notifications, such as when the notifications appear on the screen due to |
| 703 | * an explicit user interaction. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 704 | * |
| 705 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 706 | * before performing this operation. |
| 707 | * |
Amith Yamasani | f47e51e | 2015-04-17 10:02:15 -0700 | [diff] [blame] | 708 | * @param keys Notifications to mark as seen. |
| 709 | */ |
| 710 | public final void setNotificationsShown(String[] keys) { |
| 711 | if (!isBound()) return; |
| 712 | try { |
| 713 | getNotificationInterface().setNotificationsShownFromListener(mWrapper, keys); |
| 714 | } catch (android.os.RemoteException ex) { |
| 715 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 716 | } |
| 717 | } |
| 718 | |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 719 | |
| 720 | /** |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 721 | * Updates a notification channel for a given package for a given user. This should only be used |
| 722 | * to reflect changes a user has made to the channel via the listener's user interface. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 723 | * |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 724 | * <p>This method will throw a security exception if you don't have access to notifications |
| 725 | * for the given user.</p> |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 726 | * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated |
| 727 | * device} in order to use this method. |
| 728 | * |
| 729 | * @param pkg The package the channel belongs to. |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 730 | * @param user The user the channel belongs to. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 731 | * @param channel the channel to update. |
| 732 | */ |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 733 | public final void updateNotificationChannel(@NonNull String pkg, @NonNull UserHandle user, |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 734 | @NonNull NotificationChannel channel) { |
| 735 | if (!isBound()) return; |
| 736 | try { |
| 737 | getNotificationInterface().updateNotificationChannelFromPrivilegedListener( |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 738 | mWrapper, pkg, user, channel); |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 739 | } catch (RemoteException e) { |
| 740 | Log.v(TAG, "Unable to contact notification manager", e); |
| 741 | throw e.rethrowFromSystemServer(); |
| 742 | } |
| 743 | } |
| 744 | |
| 745 | /** |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 746 | * Returns all notification channels belonging to the given package for a given user. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 747 | * |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 748 | * <p>This method will throw a security exception if you don't have access to notifications |
| 749 | * for the given user.</p> |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 750 | * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated |
Julia Reynolds | 48a6ed9 | 2018-10-22 12:52:03 -0400 | [diff] [blame] | 751 | * device} or be the {@link NotificationAssistantService notification assistant} in order to |
| 752 | * use this method. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 753 | * |
| 754 | * @param pkg The package to retrieve channels for. |
| 755 | */ |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 756 | public final List<NotificationChannel> getNotificationChannels(@NonNull String pkg, |
| 757 | @NonNull UserHandle user) { |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 758 | if (!isBound()) return null; |
| 759 | try { |
| 760 | |
| 761 | return getNotificationInterface().getNotificationChannelsFromPrivilegedListener( |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 762 | mWrapper, pkg, user).getList(); |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 763 | } catch (RemoteException e) { |
| 764 | Log.v(TAG, "Unable to contact notification manager", e); |
| 765 | throw e.rethrowFromSystemServer(); |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | /** |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 770 | * Returns all notification channel groups belonging to the given package for a given user. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 771 | * |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 772 | * <p>This method will throw a security exception if you don't have access to notifications |
| 773 | * for the given user.</p> |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 774 | * <p>The caller must have {@link CompanionDeviceManager#getAssociations() an associated |
Julia Reynolds | 48a6ed9 | 2018-10-22 12:52:03 -0400 | [diff] [blame] | 775 | * device} or be the {@link NotificationAssistantService notification assistant} in order to |
| 776 | * use this method. |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 777 | * |
| 778 | * @param pkg The package to retrieve channel groups for. |
| 779 | */ |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 780 | public final List<NotificationChannelGroup> getNotificationChannelGroups(@NonNull String pkg, |
| 781 | @NonNull UserHandle user) { |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 782 | if (!isBound()) return null; |
| 783 | try { |
| 784 | |
| 785 | return getNotificationInterface().getNotificationChannelGroupsFromPrivilegedListener( |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 786 | mWrapper, pkg, user).getList(); |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 787 | } catch (RemoteException e) { |
| 788 | Log.v(TAG, "Unable to contact notification manager", e); |
| 789 | throw e.rethrowFromSystemServer(); |
| 790 | } |
| 791 | } |
| 792 | |
Amith Yamasani | f47e51e | 2015-04-17 10:02:15 -0700 | [diff] [blame] | 793 | /** |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 794 | * Sets the notification trim that will be received via {@link #onNotificationPosted}. |
| 795 | * |
| 796 | * <p> |
| 797 | * Setting a trim other than {@link #TRIM_FULL} enables listeners that don't need access to the |
| 798 | * full notification features right away to reduce their memory footprint. Full notifications |
| 799 | * can be requested on-demand via {@link #getActiveNotifications(int)}. |
| 800 | * |
| 801 | * <p> |
| 802 | * Set to {@link #TRIM_FULL} initially. |
| 803 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 804 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 805 | * before performing this operation. |
| 806 | * |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 807 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 808 | * @removed |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 809 | * |
| 810 | * @param trim trim of the notifications to be passed via {@link #onNotificationPosted}. |
| 811 | * See <code>TRIM_*</code> constants. |
| 812 | */ |
| 813 | @SystemApi |
| 814 | public final void setOnNotificationPostedTrim(int trim) { |
| 815 | if (!isBound()) return; |
| 816 | try { |
| 817 | getNotificationInterface().setOnNotificationPostedTrimFromListener(mWrapper, trim); |
| 818 | } catch (RemoteException ex) { |
| 819 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | /** |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 824 | * Request the list of outstanding notifications (that is, those that are visible to the |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 825 | * current user). Useful when you don't know what's already been posted. |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 826 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 827 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 828 | * before performing this operation. |
| 829 | * |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 830 | * @return An array of active notifications, sorted in natural order. |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 831 | */ |
| 832 | public StatusBarNotification[] getActiveNotifications() { |
Julia Reynolds | 94a38b3 | 2018-04-20 13:33:36 -0400 | [diff] [blame] | 833 | StatusBarNotification[] activeNotifications = getActiveNotifications(null, TRIM_FULL); |
| 834 | return activeNotifications != null ? activeNotifications : new StatusBarNotification[0]; |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 835 | } |
| 836 | |
| 837 | /** |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 838 | * Like {@link #getActiveNotifications()}, but returns the list of currently snoozed |
| 839 | * notifications, for all users this listener has access to. |
| 840 | * |
| 841 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 842 | * before performing this operation. |
| 843 | * |
Julia Reynolds | a11d0b1 | 2017-02-16 15:01:36 -0500 | [diff] [blame] | 844 | * @return An array of snoozed notifications, sorted in natural order. |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 845 | */ |
| 846 | public final StatusBarNotification[] getSnoozedNotifications() { |
| 847 | try { |
| 848 | ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface() |
| 849 | .getSnoozedNotificationsFromListener(mWrapper, TRIM_FULL); |
| 850 | return cleanUpNotificationList(parceledList); |
| 851 | } catch (android.os.RemoteException ex) { |
| 852 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 853 | } |
| 854 | return null; |
| 855 | } |
| 856 | |
| 857 | /** |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 858 | * Request the list of outstanding notifications (that is, those that are visible to the |
| 859 | * current user). Useful when you don't know what's already been posted. |
| 860 | * |
| 861 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 862 | * @removed |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 863 | * |
| 864 | * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants. |
| 865 | * @return An array of active notifications, sorted in natural order. |
| 866 | */ |
| 867 | @SystemApi |
| 868 | public StatusBarNotification[] getActiveNotifications(int trim) { |
Julia Reynolds | 94a38b3 | 2018-04-20 13:33:36 -0400 | [diff] [blame] | 869 | StatusBarNotification[] activeNotifications = getActiveNotifications(null, trim); |
| 870 | return activeNotifications != null ? activeNotifications : new StatusBarNotification[0]; |
Dan Sandler | ea75fdd | 2014-08-12 12:29:19 -0400 | [diff] [blame] | 871 | } |
| 872 | |
| 873 | /** |
| 874 | * Request one or more notifications by key. Useful if you have been keeping track of |
| 875 | * notifications but didn't want to retain the bits, and now need to go back and extract |
| 876 | * more data out of those notifications. |
| 877 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 878 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 879 | * before performing this operation. |
| 880 | * |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 881 | * @param keys the keys of the notifications to request |
Dan Sandler | ea75fdd | 2014-08-12 12:29:19 -0400 | [diff] [blame] | 882 | * @return An array of notifications corresponding to the requested keys, in the |
| 883 | * same order as the key list. |
| 884 | */ |
| 885 | public StatusBarNotification[] getActiveNotifications(String[] keys) { |
Julia Reynolds | 94a38b3 | 2018-04-20 13:33:36 -0400 | [diff] [blame] | 886 | StatusBarNotification[] activeNotifications = getActiveNotifications(keys, TRIM_FULL); |
| 887 | return activeNotifications != null ? activeNotifications : new StatusBarNotification[0]; |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 888 | } |
| 889 | |
| 890 | /** |
| 891 | * Request one or more notifications by key. Useful if you have been keeping track of |
| 892 | * notifications but didn't want to retain the bits, and now need to go back and extract |
| 893 | * more data out of those notifications. |
| 894 | * |
| 895 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 896 | * @removed |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 897 | * |
| 898 | * @param keys the keys of the notifications to request |
| 899 | * @param trim trim of the notifications to be returned. See <code>TRIM_*</code> constants. |
| 900 | * @return An array of notifications corresponding to the requested keys, in the |
| 901 | * same order as the key list. |
| 902 | */ |
| 903 | @SystemApi |
| 904 | public StatusBarNotification[] getActiveNotifications(String[] keys, int trim) { |
| 905 | if (!isBound()) |
| 906 | return null; |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 907 | try { |
Christoph Studer | b82bc78 | 2014-08-20 14:29:43 +0200 | [diff] [blame] | 908 | ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface() |
| 909 | .getActiveNotificationsFromListener(mWrapper, keys, trim); |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 910 | return cleanUpNotificationList(parceledList); |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 911 | } catch (android.os.RemoteException ex) { |
| 912 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 913 | } |
| 914 | return null; |
| 915 | } |
| 916 | |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 917 | private StatusBarNotification[] cleanUpNotificationList( |
| 918 | ParceledListSlice<StatusBarNotification> parceledList) { |
Julia Reynolds | 94a38b3 | 2018-04-20 13:33:36 -0400 | [diff] [blame] | 919 | if (parceledList == null || parceledList.getList() == null) { |
| 920 | return new StatusBarNotification[0]; |
| 921 | } |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 922 | List<StatusBarNotification> list = parceledList.getList(); |
| 923 | ArrayList<StatusBarNotification> corruptNotifications = null; |
| 924 | int N = list.size(); |
| 925 | for (int i = 0; i < N; i++) { |
| 926 | StatusBarNotification sbn = list.get(i); |
| 927 | Notification notification = sbn.getNotification(); |
| 928 | try { |
| 929 | // convert icon metadata to legacy format for older clients |
| 930 | createLegacyIconExtras(notification); |
| 931 | // populate remote views for older clients. |
| 932 | maybePopulateRemoteViews(notification); |
Selim Cinek | e7238dd | 2017-12-14 17:48:32 -0800 | [diff] [blame] | 933 | // populate people for older clients. |
| 934 | maybePopulatePeople(notification); |
Julia Reynolds | cf63ff1 | 2017-01-24 13:55:48 -0500 | [diff] [blame] | 935 | } catch (IllegalArgumentException e) { |
| 936 | if (corruptNotifications == null) { |
| 937 | corruptNotifications = new ArrayList<>(N); |
| 938 | } |
| 939 | corruptNotifications.add(sbn); |
| 940 | Log.w(TAG, "get(Active/Snoozed)Notifications: can't rebuild notification from " + |
| 941 | sbn.getPackageName()); |
| 942 | } |
| 943 | } |
| 944 | if (corruptNotifications != null) { |
| 945 | list.removeAll(corruptNotifications); |
| 946 | } |
| 947 | return list.toArray(new StatusBarNotification[list.size()]); |
| 948 | } |
| 949 | |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 950 | /** |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 951 | * Gets the set of hints representing current state. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 952 | * |
| 953 | * <p> |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 954 | * The current state may differ from the requested state if the hint represents state |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 955 | * shared across all listeners or a feature the notification host does not support or refuses |
| 956 | * to grant. |
| 957 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 958 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 959 | * before performing this operation. |
| 960 | * |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 961 | * @return Zero or more of the HINT_ constants. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 962 | */ |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 963 | public final int getCurrentListenerHints() { |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 964 | if (!isBound()) return 0; |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 965 | try { |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 966 | return getNotificationInterface().getHintsFromListener(mWrapper); |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 967 | } catch (android.os.RemoteException ex) { |
| 968 | Log.v(TAG, "Unable to contact notification manager", ex); |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 969 | return 0; |
| 970 | } |
| 971 | } |
| 972 | |
| 973 | /** |
| 974 | * Gets the current notification interruption filter active on the host. |
| 975 | * |
| 976 | * <p> |
| 977 | * The interruption filter defines which notifications are allowed to interrupt the user |
| 978 | * (e.g. via sound & vibration) and is applied globally. Listeners can find out whether |
| 979 | * a specific notification matched the interruption filter via |
| 980 | * {@link Ranking#matchesInterruptionFilter()}. |
| 981 | * <p> |
| 982 | * The current filter may differ from the previously requested filter if the notification host |
| 983 | * does not support or refuses to apply the requested filter, or if another component changed |
| 984 | * the filter in the meantime. |
| 985 | * <p> |
| 986 | * Listen for updates using {@link #onInterruptionFilterChanged(int)}. |
| 987 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 988 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 989 | * before performing this operation. |
| 990 | * |
John Spurlock | 8310410 | 2015-02-12 23:25:12 -0500 | [diff] [blame] | 991 | * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when |
| 992 | * unavailable. |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 993 | */ |
| 994 | public final int getCurrentInterruptionFilter() { |
John Spurlock | 8310410 | 2015-02-12 23:25:12 -0500 | [diff] [blame] | 995 | if (!isBound()) return INTERRUPTION_FILTER_UNKNOWN; |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 996 | try { |
Chris Wren | 957ed70 | 2014-09-24 18:17:36 -0400 | [diff] [blame] | 997 | return getNotificationInterface().getInterruptionFilterFromListener(mWrapper); |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 998 | } catch (android.os.RemoteException ex) { |
| 999 | Log.v(TAG, "Unable to contact notification manager", ex); |
John Spurlock | 8310410 | 2015-02-12 23:25:12 -0500 | [diff] [blame] | 1000 | return INTERRUPTION_FILTER_UNKNOWN; |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1001 | } |
| 1002 | } |
| 1003 | |
| 1004 | /** |
Julia Reynolds | 4703bac | 2018-09-12 10:39:30 -0400 | [diff] [blame] | 1005 | * Clears listener hints set via {@link #getCurrentListenerHints()}. |
| 1006 | * |
| 1007 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1008 | * before performing this operation. |
| 1009 | */ |
| 1010 | public final void clearRequestedListenerHints() { |
| 1011 | if (!isBound()) return; |
| 1012 | try { |
| 1013 | getNotificationInterface().clearRequestedListenerHints(mWrapper); |
| 1014 | } catch (android.os.RemoteException ex) { |
| 1015 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 1016 | } |
| 1017 | } |
| 1018 | |
| 1019 | /** |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1020 | * Sets the desired {@link #getCurrentListenerHints() listener hints}. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1021 | * |
| 1022 | * <p> |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 1023 | * This is merely a request, the host may or may not choose to take action depending |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1024 | * on other listener requests or other global state. |
| 1025 | * <p> |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1026 | * Listen for updates using {@link #onListenerHintsChanged(int)}. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1027 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1028 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1029 | * before performing this operation. |
| 1030 | * |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1031 | * @param hints One or more of the HINT_ constants. |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1032 | */ |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1033 | public final void requestListenerHints(int hints) { |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1034 | if (!isBound()) return; |
| 1035 | try { |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1036 | getNotificationInterface().requestHintsFromListener(mWrapper, hints); |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1037 | } catch (android.os.RemoteException ex) { |
| 1038 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 1039 | } |
| 1040 | } |
| 1041 | |
| 1042 | /** |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 1043 | * Sets the desired {@link #getCurrentInterruptionFilter() interruption filter}. |
| 1044 | * |
| 1045 | * <p> |
| 1046 | * This is merely a request, the host may or may not choose to apply the requested |
| 1047 | * interruption filter depending on other listener requests or other global state. |
| 1048 | * <p> |
| 1049 | * Listen for updates using {@link #onInterruptionFilterChanged(int)}. |
| 1050 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1051 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1052 | * before performing this operation. |
| 1053 | * |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 1054 | * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants. |
| 1055 | */ |
| 1056 | public final void requestInterruptionFilter(int interruptionFilter) { |
| 1057 | if (!isBound()) return; |
| 1058 | try { |
| 1059 | getNotificationInterface() |
| 1060 | .requestInterruptionFilterFromListener(mWrapper, interruptionFilter); |
| 1061 | } catch (android.os.RemoteException ex) { |
| 1062 | Log.v(TAG, "Unable to contact notification manager", ex); |
| 1063 | } |
| 1064 | } |
| 1065 | |
| 1066 | /** |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1067 | * Returns current ranking information. |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 1068 | * |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1069 | * <p> |
| 1070 | * The returned object represents the current ranking snapshot and only |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1071 | * applies for currently active notifications. |
| 1072 | * <p> |
| 1073 | * Generally you should use the RankingMap that is passed with events such |
| 1074 | * as {@link #onNotificationPosted(StatusBarNotification, RankingMap)}, |
| 1075 | * {@link #onNotificationRemoved(StatusBarNotification, RankingMap)}, and |
| 1076 | * so on. This method should only be used when needing access outside of |
| 1077 | * such events, for example to retrieve the RankingMap right after |
| 1078 | * initialization. |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1079 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1080 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1081 | * before performing this operation. |
| 1082 | * |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1083 | * @return A {@link RankingMap} object providing access to ranking information |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 1084 | */ |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1085 | public RankingMap getCurrentRanking() { |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1086 | synchronized (mLock) { |
| 1087 | return mRankingMap; |
| 1088 | } |
Daniel Sandler | 25cf8ce | 2013-04-24 15:34:57 -0400 | [diff] [blame] | 1089 | } |
| 1090 | |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1091 | /** |
| 1092 | * This is not the lifecycle event you are looking for. |
| 1093 | * |
| 1094 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1095 | * before performing any operations. |
| 1096 | */ |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1097 | @Override |
| 1098 | public IBinder onBind(Intent intent) { |
| 1099 | if (mWrapper == null) { |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1100 | mWrapper = new NotificationListenerWrapper(); |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1101 | } |
| 1102 | return mWrapper; |
| 1103 | } |
| 1104 | |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1105 | /** @hide */ |
Mathew Inwood | e380737 | 2018-08-10 09:51:03 +0100 | [diff] [blame] | 1106 | @UnsupportedAppUsage |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1107 | protected boolean isBound() { |
John Spurlock | da9a3be | 2014-02-12 12:12:26 -0500 | [diff] [blame] | 1108 | if (mWrapper == null) { |
| 1109 | Log.w(TAG, "Notification listener service not yet bound."); |
| 1110 | return false; |
| 1111 | } |
| 1112 | return true; |
| 1113 | } |
| 1114 | |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1115 | @Override |
| 1116 | public void onDestroy() { |
| 1117 | onListenerDisconnected(); |
| 1118 | super.onDestroy(); |
| 1119 | } |
| 1120 | |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1121 | /** |
| 1122 | * Directly register this service with the Notification Manager. |
| 1123 | * |
| 1124 | * <p>Only system services may use this call. It will fail for non-system callers. |
| 1125 | * Apps should ask the user to add their listener in Settings. |
| 1126 | * |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 1127 | * @param context Context required for accessing resources. Since this service isn't |
| 1128 | * launched as a real Service when using this method, a context has to be passed in. |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1129 | * @param componentName the component that will consume the notification information |
| 1130 | * @param currentUser the user to use as the stream filter |
| 1131 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 1132 | * @removed |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1133 | */ |
Jeff Brown | 5c507c1 | 2014-06-05 17:14:39 -0700 | [diff] [blame] | 1134 | @SystemApi |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 1135 | public void registerAsSystemService(Context context, ComponentName componentName, |
| 1136 | int currentUser) throws RemoteException { |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1137 | if (mWrapper == null) { |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1138 | mWrapper = new NotificationListenerWrapper(); |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1139 | } |
Chris Wren | 0efdb88 | 2016-03-01 17:17:47 -0500 | [diff] [blame] | 1140 | mSystemContext = context; |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1141 | INotificationManager noMan = getNotificationInterface(); |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1142 | mHandler = new MyHandler(context.getMainLooper()); |
Chris Wren | b66a16d | 2016-04-29 10:07:48 -0400 | [diff] [blame] | 1143 | mCurrentUser = currentUser; |
| 1144 | noMan.registerListener(mWrapper, componentName, currentUser); |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1145 | } |
| 1146 | |
| 1147 | /** |
| 1148 | * Directly unregister this service from the Notification Manager. |
| 1149 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1150 | * <p>This method will fail for listeners that were not registered |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1151 | * with (@link registerAsService). |
| 1152 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 1153 | * @removed |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1154 | */ |
Jeff Brown | 5c507c1 | 2014-06-05 17:14:39 -0700 | [diff] [blame] | 1155 | @SystemApi |
Chris Wren | 1941fc7 | 2014-05-14 15:20:51 -0400 | [diff] [blame] | 1156 | public void unregisterAsSystemService() throws RemoteException { |
| 1157 | if (mWrapper != null) { |
| 1158 | INotificationManager noMan = getNotificationInterface(); |
| 1159 | noMan.unregisterListener(mWrapper, mCurrentUser); |
| 1160 | } |
| 1161 | } |
| 1162 | |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1163 | /** |
Elliot Waite | 54de774 | 2017-01-11 15:30:35 -0800 | [diff] [blame] | 1164 | * Request that the listener be rebound, after a previous call to {@link #requestUnbind}. |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1165 | * |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1166 | * <p>This method will fail for listeners that have |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1167 | * not been granted the permission by the user. |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1168 | */ |
Chris Wren | cf548bf | 2016-05-20 14:53:16 -0400 | [diff] [blame] | 1169 | public static void requestRebind(ComponentName componentName) { |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1170 | INotificationManager noMan = INotificationManager.Stub.asInterface( |
| 1171 | ServiceManager.getService(Context.NOTIFICATION_SERVICE)); |
Chris Wren | cf548bf | 2016-05-20 14:53:16 -0400 | [diff] [blame] | 1172 | try { |
| 1173 | noMan.requestBindListener(componentName); |
| 1174 | } catch (RemoteException ex) { |
| 1175 | throw ex.rethrowFromSystemServer(); |
| 1176 | } |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1177 | } |
| 1178 | |
| 1179 | /** |
| 1180 | * Request that the service be unbound. |
| 1181 | * |
Julia Reynolds | 0ffc13b | 2017-04-27 13:54:36 -0400 | [diff] [blame] | 1182 | * <p>Once this is called, you will no longer receive updates and no method calls are |
| 1183 | * guaranteed to be successful, until you next receive the {@link #onListenerConnected()} event. |
| 1184 | * The service will likely be killed by the system after this call. |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1185 | * |
| 1186 | * <p>The service should wait for the {@link #onListenerConnected()} event |
| 1187 | * before performing this operation. I know it's tempting, but you must wait. |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1188 | */ |
Chris Wren | cf548bf | 2016-05-20 14:53:16 -0400 | [diff] [blame] | 1189 | public final void requestUnbind() { |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1190 | if (mWrapper != null) { |
| 1191 | INotificationManager noMan = getNotificationInterface(); |
Chris Wren | cf548bf | 2016-05-20 14:53:16 -0400 | [diff] [blame] | 1192 | try { |
| 1193 | noMan.requestUnbindListener(mWrapper); |
| 1194 | // Disable future messages. |
| 1195 | isConnected = false; |
| 1196 | } catch (RemoteException ex) { |
| 1197 | throw ex.rethrowFromSystemServer(); |
| 1198 | } |
Chris Wren | ab41eec | 2016-01-04 18:01:27 -0500 | [diff] [blame] | 1199 | } |
| 1200 | } |
| 1201 | |
Daniel Sandler | f5a7838 | 2015-05-15 23:59:36 -0400 | [diff] [blame] | 1202 | /** Convert new-style Icons to legacy representations for pre-M clients. */ |
| 1203 | private void createLegacyIconExtras(Notification n) { |
| 1204 | Icon smallIcon = n.getSmallIcon(); |
| 1205 | Icon largeIcon = n.getLargeIcon(); |
Dan Sandler | 99a37f1 | 2015-06-09 14:34:38 -0400 | [diff] [blame] | 1206 | if (smallIcon != null && smallIcon.getType() == Icon.TYPE_RESOURCE) { |
Daniel Sandler | f5a7838 | 2015-05-15 23:59:36 -0400 | [diff] [blame] | 1207 | n.extras.putInt(Notification.EXTRA_SMALL_ICON, smallIcon.getResId()); |
| 1208 | n.icon = smallIcon.getResId(); |
| 1209 | } |
| 1210 | if (largeIcon != null) { |
| 1211 | Drawable d = largeIcon.loadDrawable(getContext()); |
| 1212 | if (d != null && d instanceof BitmapDrawable) { |
| 1213 | final Bitmap largeIconBits = ((BitmapDrawable) d).getBitmap(); |
| 1214 | n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, largeIconBits); |
| 1215 | n.largeIcon = largeIconBits; |
| 1216 | } |
| 1217 | } |
| 1218 | } |
| 1219 | |
Julia Reynolds | d9228f1 | 2015-10-20 10:37:27 -0400 | [diff] [blame] | 1220 | /** |
| 1221 | * Populates remote views for pre-N targeting apps. |
| 1222 | */ |
| 1223 | private void maybePopulateRemoteViews(Notification notification) { |
| 1224 | if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) { |
| 1225 | Builder builder = Builder.recoverBuilder(getContext(), notification); |
Adrian Roos | 5081c0d | 2016-02-26 16:04:19 -0800 | [diff] [blame] | 1226 | |
| 1227 | // Some styles wrap Notification's contentView, bigContentView and headsUpContentView. |
| 1228 | // First inflate them all, only then set them to avoid recursive wrapping. |
| 1229 | RemoteViews content = builder.createContentView(); |
| 1230 | RemoteViews big = builder.createBigContentView(); |
| 1231 | RemoteViews headsUp = builder.createHeadsUpContentView(); |
| 1232 | |
| 1233 | notification.contentView = content; |
| 1234 | notification.bigContentView = big; |
| 1235 | notification.headsUpContentView = headsUp; |
Julia Reynolds | d9228f1 | 2015-10-20 10:37:27 -0400 | [diff] [blame] | 1236 | } |
| 1237 | } |
| 1238 | |
Selim Cinek | e7238dd | 2017-12-14 17:48:32 -0800 | [diff] [blame] | 1239 | /** |
| 1240 | * Populates remote views for pre-P targeting apps. |
| 1241 | */ |
| 1242 | private void maybePopulatePeople(Notification notification) { |
| 1243 | if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) { |
Selim Cinek | 9acd673 | 2018-03-23 16:39:02 -0700 | [diff] [blame] | 1244 | ArrayList<Person> people = notification.extras.getParcelableArrayList( |
Selim Cinek | e7238dd | 2017-12-14 17:48:32 -0800 | [diff] [blame] | 1245 | Notification.EXTRA_PEOPLE_LIST); |
| 1246 | if (people != null && people.isEmpty()) { |
| 1247 | int size = people.size(); |
| 1248 | String[] peopleArray = new String[size]; |
| 1249 | for (int i = 0; i < size; i++) { |
Selim Cinek | 9acd673 | 2018-03-23 16:39:02 -0700 | [diff] [blame] | 1250 | Person person = people.get(i); |
Selim Cinek | e7238dd | 2017-12-14 17:48:32 -0800 | [diff] [blame] | 1251 | peopleArray[i] = person.resolveToLegacyUri(); |
| 1252 | } |
| 1253 | notification.extras.putStringArray(Notification.EXTRA_PEOPLE, peopleArray); |
| 1254 | } |
| 1255 | } |
| 1256 | } |
| 1257 | |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1258 | /** @hide */ |
| 1259 | protected class NotificationListenerWrapper extends INotificationListener.Stub { |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1260 | @Override |
Griff Hazen | 84a00ea | 2014-09-02 17:10:47 -0700 | [diff] [blame] | 1261 | public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder, |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1262 | NotificationRankingUpdate update) { |
Griff Hazen | 84a00ea | 2014-09-02 17:10:47 -0700 | [diff] [blame] | 1263 | StatusBarNotification sbn; |
| 1264 | try { |
| 1265 | sbn = sbnHolder.get(); |
| 1266 | } catch (RemoteException e) { |
| 1267 | Log.w(TAG, "onNotificationPosted: Error receiving StatusBarNotification", e); |
| 1268 | return; |
| 1269 | } |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 1270 | |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 1271 | try { |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 1272 | // convert icon metadata to legacy format for older clients |
| 1273 | createLegacyIconExtras(sbn.getNotification()); |
Julia Reynolds | d9228f1 | 2015-10-20 10:37:27 -0400 | [diff] [blame] | 1274 | maybePopulateRemoteViews(sbn.getNotification()); |
Selim Cinek | 5390e7d | 2018-02-20 19:12:41 -0800 | [diff] [blame] | 1275 | maybePopulatePeople(sbn.getNotification()); |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 1276 | } catch (IllegalArgumentException e) { |
Andreas Gampe | 1ed71f3 | 2015-12-11 15:49:07 -0800 | [diff] [blame] | 1277 | // warn and drop corrupt notification |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 1278 | Log.w(TAG, "onNotificationPosted: can't rebuild notification from " + |
| 1279 | sbn.getPackageName()); |
Andreas Gampe | 1ed71f3 | 2015-12-11 15:49:07 -0800 | [diff] [blame] | 1280 | sbn = null; |
Chris Wren | 24fb894 | 2015-06-18 14:33:56 -0400 | [diff] [blame] | 1281 | } |
Daniel Sandler | f5a7838 | 2015-05-15 23:59:36 -0400 | [diff] [blame] | 1282 | |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1283 | // protect subclass from concurrent modifications of (@link mNotificationKeys}. |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1284 | synchronized (mLock) { |
| 1285 | applyUpdateLocked(update); |
| 1286 | if (sbn != null) { |
| 1287 | SomeArgs args = SomeArgs.obtain(); |
| 1288 | args.arg1 = sbn; |
| 1289 | args.arg2 = mRankingMap; |
| 1290 | mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED, |
| 1291 | args).sendToTarget(); |
| 1292 | } else { |
| 1293 | // still pass along the ranking map, it may contain other information |
| 1294 | mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE, |
| 1295 | mRankingMap).sendToTarget(); |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1296 | } |
John Spurlock | c133ab8 | 2013-06-10 15:16:22 -0400 | [diff] [blame] | 1297 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1298 | |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1299 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1300 | |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1301 | @Override |
Griff Hazen | 84a00ea | 2014-09-02 17:10:47 -0700 | [diff] [blame] | 1302 | public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder, |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1303 | NotificationRankingUpdate update, NotificationStats stats, int reason) { |
Griff Hazen | 84a00ea | 2014-09-02 17:10:47 -0700 | [diff] [blame] | 1304 | StatusBarNotification sbn; |
| 1305 | try { |
| 1306 | sbn = sbnHolder.get(); |
| 1307 | } catch (RemoteException e) { |
| 1308 | Log.w(TAG, "onNotificationRemoved: Error receiving StatusBarNotification", e); |
| 1309 | return; |
| 1310 | } |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1311 | // protect subclass from concurrent modifications of (@link mNotificationKeys}. |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1312 | synchronized (mLock) { |
| 1313 | applyUpdateLocked(update); |
| 1314 | SomeArgs args = SomeArgs.obtain(); |
| 1315 | args.arg1 = sbn; |
| 1316 | args.arg2 = mRankingMap; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 1317 | args.arg3 = reason; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1318 | args.arg4 = stats; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1319 | mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED, |
| 1320 | args).sendToTarget(); |
John Spurlock | c133ab8 | 2013-06-10 15:16:22 -0400 | [diff] [blame] | 1321 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1322 | |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 1323 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1324 | |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 1325 | @Override |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1326 | public void onListenerConnected(NotificationRankingUpdate update) { |
| 1327 | // protect subclass from concurrent modifications of (@link mNotificationKeys}. |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1328 | synchronized (mLock) { |
| 1329 | applyUpdateLocked(update); |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 1330 | } |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 1331 | isConnected = true; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1332 | mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget(); |
John Spurlock | a429429 | 2014-03-24 18:02:32 -0400 | [diff] [blame] | 1333 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1334 | |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1335 | @Override |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1336 | public void onNotificationRankingUpdate(NotificationRankingUpdate update) |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1337 | throws RemoteException { |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1338 | // protect subclass from concurrent modifications of (@link mNotificationKeys}. |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1339 | synchronized (mLock) { |
| 1340 | applyUpdateLocked(update); |
| 1341 | mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE, |
| 1342 | mRankingMap).sendToTarget(); |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1343 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1344 | |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1345 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1346 | |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1347 | @Override |
John Spurlock | d8afe3c | 2014-08-01 14:04:07 -0400 | [diff] [blame] | 1348 | public void onListenerHintsChanged(int hints) throws RemoteException { |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1349 | mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_HINTS_CHANGED, |
| 1350 | hints, 0).sendToTarget(); |
John Spurlock | 1fa865f | 2014-07-21 14:56:39 -0400 | [diff] [blame] | 1351 | } |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 1352 | |
| 1353 | @Override |
| 1354 | public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException { |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1355 | mHandler.obtainMessage(MyHandler.MSG_ON_INTERRUPTION_FILTER_CHANGED, |
| 1356 | interruptionFilter, 0).sendToTarget(); |
Christoph Studer | 85a384b | 2014-08-27 20:16:15 +0200 | [diff] [blame] | 1357 | } |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1358 | |
| 1359 | @Override |
Julia Reynolds | 901bf28 | 2018-08-14 10:09:36 -0400 | [diff] [blame] | 1360 | public void onNotificationEnqueuedWithChannel( |
| 1361 | IStatusBarNotificationHolder notificationHolder, NotificationChannel channel) |
Julia Reynolds | ceecfcf | 2017-01-31 09:44:26 -0500 | [diff] [blame] | 1362 | throws RemoteException { |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1363 | // no-op in the listener |
| 1364 | } |
| 1365 | |
| 1366 | @Override |
Julia Reynolds | 6a63d1b | 2018-08-14 16:59:33 -0400 | [diff] [blame] | 1367 | public void onNotificationsSeen(List<String> keys) |
| 1368 | throws RemoteException { |
| 1369 | // no-op in the listener |
| 1370 | } |
| 1371 | |
| 1372 | @Override |
Julia Reynolds | 7967230 | 2017-01-12 08:30:16 -0500 | [diff] [blame] | 1373 | public void onNotificationSnoozedUntilContext( |
| 1374 | IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId) |
Chris Wren | 51017d0 | 2015-12-15 15:34:46 -0500 | [diff] [blame] | 1375 | throws RemoteException { |
| 1376 | // no-op in the listener |
| 1377 | } |
| 1378 | |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 1379 | @Override |
Tony Mak | eda84a7 | 2018-11-19 17:01:32 +0000 | [diff] [blame] | 1380 | public void onNotificationExpansionChanged( |
| 1381 | String key, boolean isUserAction, boolean isExpanded) { |
| 1382 | // no-op in the listener |
| 1383 | } |
| 1384 | |
| 1385 | @Override |
| 1386 | public void onNotificationDirectReply(String key) { |
| 1387 | // no-op in the listener |
| 1388 | } |
| 1389 | |
| 1390 | @Override |
Tony Mak | 2999670 | 2018-11-26 16:23:34 +0000 | [diff] [blame] | 1391 | public void onSuggestedReplySent(String key, CharSequence reply, int source) { |
| 1392 | // no-op in the listener |
| 1393 | } |
| 1394 | |
| 1395 | @Override |
Tony Mak | 7d4b3a5 | 2018-11-27 17:29:36 +0000 | [diff] [blame] | 1396 | public void onActionClicked(String key, Notification.Action action, int source) { |
| 1397 | // no-op in the listener |
| 1398 | } |
| 1399 | |
| 1400 | @Override |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 1401 | public void onNotificationChannelModification(String pkgName, UserHandle user, |
| 1402 | NotificationChannel channel, |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 1403 | @ChannelOrGroupModificationTypes int modificationType) { |
| 1404 | SomeArgs args = SomeArgs.obtain(); |
| 1405 | args.arg1 = pkgName; |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 1406 | args.arg2 = user; |
| 1407 | args.arg3 = channel; |
| 1408 | args.arg4 = modificationType; |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 1409 | mHandler.obtainMessage( |
| 1410 | MyHandler.MSG_ON_NOTIFICATION_CHANNEL_MODIFIED, args).sendToTarget(); |
| 1411 | } |
| 1412 | |
| 1413 | @Override |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 1414 | public void onNotificationChannelGroupModification(String pkgName, UserHandle user, |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 1415 | NotificationChannelGroup group, |
| 1416 | @ChannelOrGroupModificationTypes int modificationType) { |
| 1417 | SomeArgs args = SomeArgs.obtain(); |
| 1418 | args.arg1 = pkgName; |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 1419 | args.arg2 = user; |
| 1420 | args.arg3 = group; |
| 1421 | args.arg4 = modificationType; |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 1422 | mHandler.obtainMessage( |
| 1423 | MyHandler.MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED, args).sendToTarget(); |
| 1424 | } |
Julia Reynolds | 12ad7ca | 2019-01-28 09:29:16 -0500 | [diff] [blame] | 1425 | |
| 1426 | @Override |
| 1427 | public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) { |
| 1428 | mHandler.obtainMessage(MyHandler.MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED, |
| 1429 | hideSilentStatusIcons).sendToTarget(); |
| 1430 | } |
Chris Wren | f953664 | 2014-04-17 10:01:54 -0400 | [diff] [blame] | 1431 | } |
| 1432 | |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1433 | /** |
| 1434 | * @hide |
| 1435 | */ |
Andreas Gampe | 3f24e69 | 2018-02-05 13:24:28 -0800 | [diff] [blame] | 1436 | @GuardedBy("mLock") |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1437 | public final void applyUpdateLocked(NotificationRankingUpdate update) { |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1438 | mRankingMap = new RankingMap(update); |
| 1439 | } |
| 1440 | |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 1441 | /** @hide */ |
| 1442 | protected Context getContext() { |
Christoph Studer | 4600f9b | 2014-07-22 22:44:43 +0200 | [diff] [blame] | 1443 | if (mSystemContext != null) { |
| 1444 | return mSystemContext; |
| 1445 | } |
| 1446 | return this; |
| 1447 | } |
| 1448 | |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1449 | /** |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1450 | * Stores ranking related information on a currently active notification. |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1451 | * |
| 1452 | * <p> |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1453 | * Ranking objects aren't automatically updated as notification events |
| 1454 | * occur. Instead, ranking information has to be retrieved again via the |
| 1455 | * current {@link RankingMap}. |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1456 | */ |
| 1457 | public static class Ranking { |
Julia Reynolds | 0edb50c | 2016-02-26 14:08:25 -0500 | [diff] [blame] | 1458 | |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1459 | /** Value signifying that the user has not expressed a per-app visibility override value. |
| 1460 | * @hide */ |
Chris Wren | 5ab5c74 | 2016-05-10 15:32:23 -0400 | [diff] [blame] | 1461 | public static final int VISIBILITY_NO_OVERRIDE = NotificationManager.VISIBILITY_NO_OVERRIDE; |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1462 | |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1463 | /** |
| 1464 | * The user is likely to have a negative reaction to this notification. |
| 1465 | */ |
| 1466 | public static final int USER_SENTIMENT_NEGATIVE = -1; |
| 1467 | /** |
| 1468 | * It is not known how the user will react to this notification. |
| 1469 | */ |
| 1470 | public static final int USER_SENTIMENT_NEUTRAL = 0; |
| 1471 | /** |
| 1472 | * The user is likely to have a positive reaction to this notification. |
| 1473 | */ |
| 1474 | public static final int USER_SENTIMENT_POSITIVE = 1; |
| 1475 | |
| 1476 | /** @hide */ |
| 1477 | @IntDef(prefix = { "USER_SENTIMENT_" }, value = { |
| 1478 | USER_SENTIMENT_NEGATIVE, USER_SENTIMENT_NEUTRAL, USER_SENTIMENT_POSITIVE |
| 1479 | }) |
| 1480 | @Retention(RetentionPolicy.SOURCE) |
| 1481 | public @interface UserSentiment {} |
| 1482 | |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1483 | private String mKey; |
| 1484 | private int mRank = -1; |
| 1485 | private boolean mIsAmbient; |
Christoph Studer | ce7d6d2 | 2014-08-26 19:21:31 +0200 | [diff] [blame] | 1486 | private boolean mMatchesInterruptionFilter; |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1487 | private int mVisibilityOverride; |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1488 | private int mSuppressedVisualEffects; |
Chris Wren | 5ab5c74 | 2016-05-10 15:32:23 -0400 | [diff] [blame] | 1489 | private @NotificationManager.Importance int mImportance; |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1490 | private CharSequence mImportanceExplanation; |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1491 | // System specified group key. |
| 1492 | private String mOverrideGroupKey; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1493 | // Notification assistant channel override. |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1494 | private NotificationChannel mChannel; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1495 | // Notification assistant people override. |
| 1496 | private ArrayList<String> mOverridePeople; |
| 1497 | // Notification assistant snooze criteria. |
| 1498 | private ArrayList<SnoozeCriterion> mSnoozeCriteria; |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1499 | private boolean mShowBadge; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1500 | private @UserSentiment int mUserSentiment = USER_SENTIMENT_NEUTRAL; |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 1501 | private boolean mHidden; |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1502 | private long mLastAudiblyAlertedMs; |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1503 | private boolean mNoisy; |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 1504 | private ArrayList<Notification.Action> mSmartActions; |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 1505 | private ArrayList<CharSequence> mSmartReplies; |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1506 | private boolean mCanBubble; |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1507 | |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1508 | public Ranking() {} |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1509 | |
| 1510 | /** |
| 1511 | * Returns the key of the notification this Ranking applies to. |
| 1512 | */ |
| 1513 | public String getKey() { |
| 1514 | return mKey; |
| 1515 | } |
| 1516 | |
| 1517 | /** |
| 1518 | * Returns the rank of the notification. |
| 1519 | * |
| 1520 | * @return the rank of the notification, that is the 0-based index in |
| 1521 | * the list of active notifications. |
| 1522 | */ |
| 1523 | public int getRank() { |
| 1524 | return mRank; |
| 1525 | } |
| 1526 | |
| 1527 | /** |
| 1528 | * Returns whether the notification is an ambient notification, that is |
| 1529 | * a notification that doesn't require the user's immediate attention. |
| 1530 | */ |
| 1531 | public boolean isAmbient() { |
| 1532 | return mIsAmbient; |
| 1533 | } |
| 1534 | |
| 1535 | /** |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1536 | * Returns the user specified visibility for the package that posted |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1537 | * this notification, or |
| 1538 | * {@link NotificationListenerService.Ranking#VISIBILITY_NO_OVERRIDE} if |
| 1539 | * no such preference has been expressed. |
| 1540 | * @hide |
| 1541 | */ |
Mathew Inwood | e380737 | 2018-08-10 09:51:03 +0100 | [diff] [blame] | 1542 | @UnsupportedAppUsage |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1543 | public int getVisibilityOverride() { |
| 1544 | return mVisibilityOverride; |
| 1545 | } |
| 1546 | |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1547 | /** |
| 1548 | * Returns the type(s) of visual effects that should be suppressed for this notification. |
Julia Reynolds | ccc6ae6 | 2018-03-01 16:24:49 -0500 | [diff] [blame] | 1549 | * See {@link NotificationManager.Policy}, e.g. |
| 1550 | * {@link NotificationManager.Policy#SUPPRESSED_EFFECT_LIGHTS}. |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1551 | */ |
| 1552 | public int getSuppressedVisualEffects() { |
| 1553 | return mSuppressedVisualEffects; |
| 1554 | } |
| 1555 | |
Christoph Studer | ce7d6d2 | 2014-08-26 19:21:31 +0200 | [diff] [blame] | 1556 | /** |
| 1557 | * Returns whether the notification matches the user's interruption |
| 1558 | * filter. |
Chris Wren | 0fef44d | 2014-09-30 13:05:14 -0400 | [diff] [blame] | 1559 | * |
| 1560 | * @return {@code true} if the notification is allowed by the filter, or |
| 1561 | * {@code false} if it is blocked. |
Christoph Studer | ce7d6d2 | 2014-08-26 19:21:31 +0200 | [diff] [blame] | 1562 | */ |
| 1563 | public boolean matchesInterruptionFilter() { |
| 1564 | return mMatchesInterruptionFilter; |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1565 | } |
| 1566 | |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1567 | /** |
| 1568 | * Returns the importance of the notification, which dictates its |
Chris Wren | 5ab5c74 | 2016-05-10 15:32:23 -0400 | [diff] [blame] | 1569 | * modes of presentation, see: {@link NotificationManager#IMPORTANCE_DEFAULT}, etc. |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1570 | * |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1571 | * @return the importance of the notification |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1572 | */ |
Chris Wren | 5ab5c74 | 2016-05-10 15:32:23 -0400 | [diff] [blame] | 1573 | public @NotificationManager.Importance int getImportance() { |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1574 | return mImportance; |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1575 | } |
| 1576 | |
| 1577 | /** |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1578 | * If the importance has been overridden by user preference, then this will be non-null, |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1579 | * and should be displayed to the user. |
| 1580 | * |
| 1581 | * @return the explanation for the importance, or null if it is the natural importance |
| 1582 | */ |
| 1583 | public CharSequence getImportanceExplanation() { |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1584 | return mImportanceExplanation; |
Chris Wren | 9fa689f | 2015-11-20 16:44:53 -0500 | [diff] [blame] | 1585 | } |
| 1586 | |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1587 | /** |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1588 | * If the system has overridden the group key, then this will be non-null, and this |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1589 | * key should be used to bundle notifications. |
| 1590 | */ |
| 1591 | public String getOverrideGroupKey() { |
| 1592 | return mOverrideGroupKey; |
| 1593 | } |
| 1594 | |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1595 | /** |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1596 | * Returns the notification channel this notification was posted to, which dictates |
| 1597 | * notification behavior and presentation. |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1598 | */ |
| 1599 | public NotificationChannel getChannel() { |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1600 | return mChannel; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1601 | } |
| 1602 | |
| 1603 | /** |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1604 | * Returns how the system thinks the user feels about notifications from the |
| 1605 | * channel provided by {@link #getChannel()}. You can use this information to expose |
| 1606 | * controls to help the user block this channel's notifications, if the sentiment is |
| 1607 | * {@link #USER_SENTIMENT_NEGATIVE}, or emphasize this notification if the sentiment is |
| 1608 | * {@link #USER_SENTIMENT_POSITIVE}. |
| 1609 | */ |
| 1610 | public int getUserSentiment() { |
| 1611 | return mUserSentiment; |
| 1612 | } |
| 1613 | |
| 1614 | /** |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1615 | * If the {@link NotificationAssistantService} has added people to this notification, then |
| 1616 | * this will be non-null. |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 1617 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 1618 | * @removed |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1619 | */ |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 1620 | @SystemApi |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1621 | public List<String> getAdditionalPeople() { |
| 1622 | return mOverridePeople; |
| 1623 | } |
| 1624 | |
| 1625 | /** |
| 1626 | * Returns snooze criteria provided by the {@link NotificationAssistantService}. If your |
| 1627 | * user interface displays options for snoozing notifications these criteria should be |
| 1628 | * displayed as well. |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 1629 | * @hide |
Julia Reynolds | 7ca3307 | 2017-06-29 13:58:24 -0400 | [diff] [blame] | 1630 | * @removed |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1631 | */ |
Julia Reynolds | 1327d3c | 2017-02-17 09:26:45 -0500 | [diff] [blame] | 1632 | @SystemApi |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1633 | public List<SnoozeCriterion> getSnoozeCriteria() { |
| 1634 | return mSnoozeCriteria; |
| 1635 | } |
| 1636 | |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1637 | /** |
Fabian Kozynski | b0da4bc | 2019-01-15 17:44:27 -0500 | [diff] [blame] | 1638 | * Returns a list of smart {@link Notification.Action} that can be added by the |
| 1639 | * {@link NotificationAssistantService} |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 1640 | */ |
| 1641 | public List<Notification.Action> getSmartActions() { |
| 1642 | return mSmartActions; |
| 1643 | } |
| 1644 | |
| 1645 | /** |
Fabian Kozynski | b0da4bc | 2019-01-15 17:44:27 -0500 | [diff] [blame] | 1646 | * Returns a list of smart replies that can be added by the |
| 1647 | * {@link NotificationAssistantService} |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 1648 | */ |
| 1649 | public List<CharSequence> getSmartReplies() { |
| 1650 | return mSmartReplies; |
| 1651 | } |
| 1652 | |
| 1653 | /** |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1654 | * Returns whether this notification can be displayed as a badge. |
| 1655 | * |
| 1656 | * @return true if the notification can be displayed as a badge, false otherwise. |
| 1657 | */ |
| 1658 | public boolean canShowBadge() { |
| 1659 | return mShowBadge; |
| 1660 | } |
| 1661 | |
Dan Sandler | 1d958f8 | 2018-01-09 21:10:26 -0500 | [diff] [blame] | 1662 | /** |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 1663 | * Returns whether the app that posted this notification is suspended, so this notification |
| 1664 | * should be hidden. |
| 1665 | * |
| 1666 | * @return true if the notification should be hidden, false otherwise. |
| 1667 | */ |
| 1668 | public boolean isSuspended() { |
| 1669 | return mHidden; |
| 1670 | } |
| 1671 | |
| 1672 | /** |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1673 | * Returns the last time this notification alerted the user via sound or vibration. |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1674 | * |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1675 | * @return the time of the last alerting behavior, in milliseconds. |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1676 | */ |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1677 | public long getLastAudiblyAlertedMillis() { |
| 1678 | return mLastAudiblyAlertedMs; |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1679 | } |
| 1680 | |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1681 | /** |
| 1682 | * Returns whether the user has allowed bubbles globally, at the app level, and at the |
| 1683 | * channel level for this notification. |
| 1684 | * |
| 1685 | * <p>This does not take into account the current importance of the notification, the |
| 1686 | * current DND state, or whether the posting app is foreground.</p> |
| 1687 | */ |
| 1688 | public boolean canBubble() { |
| 1689 | return mCanBubble; |
| 1690 | } |
| 1691 | |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1692 | /** @hide */ |
| 1693 | public boolean isNoisy() { |
| 1694 | return mNoisy; |
| 1695 | } |
| 1696 | |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1697 | /** |
Dan Sandler | 1d958f8 | 2018-01-09 21:10:26 -0500 | [diff] [blame] | 1698 | * @hide |
| 1699 | */ |
| 1700 | @VisibleForTesting |
| 1701 | public void populate(String key, int rank, boolean matchesInterruptionFilter, |
Julia Reynolds | 0421e6d | 2016-01-08 09:51:24 -0500 | [diff] [blame] | 1702 | int visibilityOverride, int suppressedVisualEffects, int importance, |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1703 | CharSequence explanation, String overrideGroupKey, |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1704 | NotificationChannel channel, ArrayList<String> overridePeople, |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1705 | ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge, |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1706 | int userSentiment, boolean hidden, long lastAudiblyAlertedMs, |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1707 | boolean noisy, ArrayList<Notification.Action> smartActions, |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1708 | ArrayList<CharSequence> smartReplies, boolean canBubble) { |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1709 | mKey = key; |
| 1710 | mRank = rank; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1711 | mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW; |
Christoph Studer | ce7d6d2 | 2014-08-26 19:21:31 +0200 | [diff] [blame] | 1712 | mMatchesInterruptionFilter = matchesInterruptionFilter; |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1713 | mVisibilityOverride = visibilityOverride; |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1714 | mSuppressedVisualEffects = suppressedVisualEffects; |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1715 | mImportance = importance; |
| 1716 | mImportanceExplanation = explanation; |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1717 | mOverrideGroupKey = overrideGroupKey; |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1718 | mChannel = channel; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1719 | mOverridePeople = overridePeople; |
| 1720 | mSnoozeCriteria = snoozeCriteria; |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1721 | mShowBadge = showBadge; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1722 | mUserSentiment = userSentiment; |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 1723 | mHidden = hidden; |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1724 | mLastAudiblyAlertedMs = lastAudiblyAlertedMs; |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1725 | mNoisy = noisy; |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 1726 | mSmartActions = smartActions; |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 1727 | mSmartReplies = smartReplies; |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1728 | mCanBubble = canBubble; |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1729 | } |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1730 | |
| 1731 | /** |
| 1732 | * {@hide} |
| 1733 | */ |
| 1734 | public static String importanceToString(int importance) { |
| 1735 | switch (importance) { |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1736 | case NotificationManager.IMPORTANCE_UNSPECIFIED: |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1737 | return "UNSPECIFIED"; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1738 | case NotificationManager.IMPORTANCE_NONE: |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1739 | return "NONE"; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1740 | case NotificationManager.IMPORTANCE_MIN: |
Julia Reynolds | f0f629f | 2016-02-25 09:34:04 -0500 | [diff] [blame] | 1741 | return "MIN"; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1742 | case NotificationManager.IMPORTANCE_LOW: |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1743 | return "LOW"; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1744 | case NotificationManager.IMPORTANCE_DEFAULT: |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1745 | return "DEFAULT"; |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1746 | case NotificationManager.IMPORTANCE_HIGH: |
| 1747 | case NotificationManager.IMPORTANCE_MAX: |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1748 | return "HIGH"; |
Julia Reynolds | 5d25ee7 | 2015-11-20 15:38:20 -0500 | [diff] [blame] | 1749 | default: |
| 1750 | return "UNKNOWN(" + String.valueOf(importance) + ")"; |
| 1751 | } |
| 1752 | } |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1753 | } |
| 1754 | |
| 1755 | /** |
| 1756 | * Provides access to ranking information on currently active |
| 1757 | * notifications. |
| 1758 | * |
| 1759 | * <p> |
| 1760 | * Note that this object represents a ranking snapshot that only applies to |
| 1761 | * notifications active at the time of retrieval. |
| 1762 | */ |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1763 | public static class RankingMap implements Parcelable { |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1764 | private final NotificationRankingUpdate mRankingUpdate; |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 1765 | private ArrayMap<String,Integer> mRanks; |
| 1766 | private ArraySet<Object> mIntercepted; |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1767 | private ArrayMap<String, Integer> mVisibilityOverrides; |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1768 | private ArrayMap<String, Integer> mSuppressedVisualEffects; |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1769 | private ArrayMap<String, Integer> mImportance; |
| 1770 | private ArrayMap<String, String> mImportanceExplanation; |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1771 | private ArrayMap<String, String> mOverrideGroupKeys; |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1772 | private ArrayMap<String, NotificationChannel> mChannels; |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1773 | private ArrayMap<String, ArrayList<String>> mOverridePeople; |
| 1774 | private ArrayMap<String, ArrayList<SnoozeCriterion>> mSnoozeCriteria; |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1775 | private ArrayMap<String, Boolean> mShowBadge; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1776 | private ArrayMap<String, Integer> mUserSentiment; |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 1777 | private ArrayMap<String, Boolean> mHidden; |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1778 | private ArrayMap<String, Long> mLastAudiblyAlerted; |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1779 | private ArrayMap<String, Boolean> mNoisy; |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 1780 | private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions; |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 1781 | private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies; |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1782 | private boolean[] mCanBubble; |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1783 | |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1784 | private RankingMap(NotificationRankingUpdate rankingUpdate) { |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1785 | mRankingUpdate = rankingUpdate; |
| 1786 | } |
| 1787 | |
| 1788 | /** |
| 1789 | * Request the list of notification keys in their current ranking |
| 1790 | * order. |
| 1791 | * |
| 1792 | * @return An array of active notification keys, in their ranking order. |
| 1793 | */ |
| 1794 | public String[] getOrderedKeys() { |
| 1795 | return mRankingUpdate.getOrderedKeys(); |
| 1796 | } |
| 1797 | |
| 1798 | /** |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1799 | * Populates outRanking with ranking information for the notification |
| 1800 | * with the given key. |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1801 | * |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1802 | * @return true if a valid key has been passed and outRanking has |
| 1803 | * been populated; false otherwise |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1804 | */ |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1805 | public boolean getRanking(String key, Ranking outRanking) { |
| 1806 | int rank = getRank(key); |
Julia Reynolds | 0421e6d | 2016-01-08 09:51:24 -0500 | [diff] [blame] | 1807 | outRanking.populate(key, rank, !isIntercepted(key), |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1808 | getVisibilityOverride(key), getSuppressedVisualEffects(key), |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1809 | getImportance(key), getImportanceExplanation(key), getOverrideGroupKey(key), |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1810 | getChannel(key), getOverridePeople(key), getSnoozeCriteria(key), |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1811 | getShowBadge(key), getUserSentiment(key), getHidden(key), |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1812 | getLastAudiblyAlerted(key), getNoisy(key), getSmartActions(key), |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1813 | getSmartReplies(key), canBubble(key)); |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1814 | return rank >= 0; |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 1815 | } |
| 1816 | |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1817 | private int getRank(String key) { |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 1818 | synchronized (this) { |
| 1819 | if (mRanks == null) { |
| 1820 | buildRanksLocked(); |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 1821 | } |
| 1822 | } |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 1823 | Integer rank = mRanks.get(key); |
| 1824 | return rank != null ? rank : -1; |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1825 | } |
| 1826 | |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1827 | private boolean isIntercepted(String key) { |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 1828 | synchronized (this) { |
| 1829 | if (mIntercepted == null) { |
| 1830 | buildInterceptedSetLocked(); |
Christoph Studer | 1d599da | 2014-06-12 15:25:59 +0200 | [diff] [blame] | 1831 | } |
| 1832 | } |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 1833 | return mIntercepted.contains(key); |
| 1834 | } |
| 1835 | |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1836 | private int getVisibilityOverride(String key) { |
| 1837 | synchronized (this) { |
| 1838 | if (mVisibilityOverrides == null) { |
| 1839 | buildVisibilityOverridesLocked(); |
| 1840 | } |
| 1841 | } |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1842 | Integer override = mVisibilityOverrides.get(key); |
| 1843 | if (override == null) { |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1844 | return Ranking.VISIBILITY_NO_OVERRIDE; |
| 1845 | } |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 1846 | return override.intValue(); |
| 1847 | } |
| 1848 | |
| 1849 | private int getSuppressedVisualEffects(String key) { |
| 1850 | synchronized (this) { |
| 1851 | if (mSuppressedVisualEffects == null) { |
| 1852 | buildSuppressedVisualEffectsLocked(); |
| 1853 | } |
| 1854 | } |
| 1855 | Integer suppressed = mSuppressedVisualEffects.get(key); |
| 1856 | if (suppressed == null) { |
| 1857 | return 0; |
| 1858 | } |
| 1859 | return suppressed.intValue(); |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 1860 | } |
| 1861 | |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1862 | private int getImportance(String key) { |
| 1863 | synchronized (this) { |
| 1864 | if (mImportance == null) { |
| 1865 | buildImportanceLocked(); |
| 1866 | } |
| 1867 | } |
| 1868 | Integer importance = mImportance.get(key); |
| 1869 | if (importance == null) { |
Julia Reynolds | 8576991 | 2016-10-25 09:08:57 -0400 | [diff] [blame] | 1870 | return NotificationManager.IMPORTANCE_DEFAULT; |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 1871 | } |
| 1872 | return importance.intValue(); |
| 1873 | } |
| 1874 | |
| 1875 | private String getImportanceExplanation(String key) { |
| 1876 | synchronized (this) { |
| 1877 | if (mImportanceExplanation == null) { |
| 1878 | buildImportanceExplanationLocked(); |
| 1879 | } |
| 1880 | } |
| 1881 | return mImportanceExplanation.get(key); |
| 1882 | } |
| 1883 | |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 1884 | private String getOverrideGroupKey(String key) { |
| 1885 | synchronized (this) { |
| 1886 | if (mOverrideGroupKeys == null) { |
| 1887 | buildOverrideGroupKeys(); |
| 1888 | } |
| 1889 | } |
| 1890 | return mOverrideGroupKeys.get(key); |
| 1891 | } |
| 1892 | |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1893 | private NotificationChannel getChannel(String key) { |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1894 | synchronized (this) { |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1895 | if (mChannels == null) { |
| 1896 | buildChannelsLocked(); |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1897 | } |
| 1898 | } |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1899 | return mChannels.get(key); |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 1900 | } |
| 1901 | |
| 1902 | private ArrayList<String> getOverridePeople(String key) { |
| 1903 | synchronized (this) { |
| 1904 | if (mOverridePeople == null) { |
| 1905 | buildOverridePeopleLocked(); |
| 1906 | } |
| 1907 | } |
| 1908 | return mOverridePeople.get(key); |
| 1909 | } |
| 1910 | |
| 1911 | private ArrayList<SnoozeCriterion> getSnoozeCriteria(String key) { |
| 1912 | synchronized (this) { |
| 1913 | if (mSnoozeCriteria == null) { |
| 1914 | buildSnoozeCriteriaLocked(); |
| 1915 | } |
| 1916 | } |
| 1917 | return mSnoozeCriteria.get(key); |
| 1918 | } |
| 1919 | |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 1920 | private boolean getShowBadge(String key) { |
| 1921 | synchronized (this) { |
| 1922 | if (mShowBadge == null) { |
| 1923 | buildShowBadgeLocked(); |
| 1924 | } |
| 1925 | } |
| 1926 | Boolean showBadge = mShowBadge.get(key); |
| 1927 | return showBadge == null ? false : showBadge.booleanValue(); |
| 1928 | } |
| 1929 | |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 1930 | private int getUserSentiment(String key) { |
| 1931 | synchronized (this) { |
| 1932 | if (mUserSentiment == null) { |
| 1933 | buildUserSentimentLocked(); |
| 1934 | } |
| 1935 | } |
| 1936 | Integer userSentiment = mUserSentiment.get(key); |
| 1937 | return userSentiment == null |
| 1938 | ? Ranking.USER_SENTIMENT_NEUTRAL : userSentiment.intValue(); |
| 1939 | } |
| 1940 | |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 1941 | private boolean getHidden(String key) { |
| 1942 | synchronized (this) { |
| 1943 | if (mHidden == null) { |
| 1944 | buildHiddenLocked(); |
| 1945 | } |
| 1946 | } |
| 1947 | Boolean hidden = mHidden.get(key); |
| 1948 | return hidden == null ? false : hidden.booleanValue(); |
| 1949 | } |
| 1950 | |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1951 | private long getLastAudiblyAlerted(String key) { |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1952 | synchronized (this) { |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1953 | if (mLastAudiblyAlerted == null) { |
| 1954 | buildLastAudiblyAlertedLocked(); |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1955 | } |
| 1956 | } |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 1957 | Long lastAudibleAlerted = mLastAudiblyAlerted.get(key); |
| 1958 | return lastAudibleAlerted == null ? -1 : lastAudibleAlerted.longValue(); |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 1959 | } |
| 1960 | |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 1961 | private boolean getNoisy(String key) { |
| 1962 | synchronized (this) { |
| 1963 | if (mNoisy == null) { |
| 1964 | buildNoisyLocked(); |
| 1965 | } |
| 1966 | } |
| 1967 | Boolean noisy = mNoisy.get(key); |
| 1968 | return noisy == null ? false : noisy.booleanValue(); |
| 1969 | } |
| 1970 | |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 1971 | private ArrayList<Notification.Action> getSmartActions(String key) { |
| 1972 | synchronized (this) { |
| 1973 | if (mSmartActions == null) { |
| 1974 | buildSmartActions(); |
| 1975 | } |
| 1976 | } |
| 1977 | return mSmartActions.get(key); |
| 1978 | } |
| 1979 | |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 1980 | private ArrayList<CharSequence> getSmartReplies(String key) { |
| 1981 | synchronized (this) { |
| 1982 | if (mSmartReplies == null) { |
| 1983 | buildSmartReplies(); |
| 1984 | } |
| 1985 | } |
| 1986 | return mSmartReplies.get(key); |
| 1987 | } |
| 1988 | |
Julia Reynolds | 4509ce7 | 2019-01-31 13:12:43 -0500 | [diff] [blame] | 1989 | private boolean canBubble(String key) { |
| 1990 | synchronized (this) { |
| 1991 | if (mRanks == null) { |
| 1992 | buildRanksLocked(); |
| 1993 | } |
| 1994 | if (mCanBubble == null) { |
| 1995 | mCanBubble = mRankingUpdate.getCanBubble(); |
| 1996 | } |
| 1997 | } |
| 1998 | int keyIndex = mRanks.getOrDefault(key, -1); |
| 1999 | return keyIndex >= 0 ? mCanBubble[keyIndex] : false; |
| 2000 | } |
| 2001 | |
Christoph Studer | dda48f1 | 2014-07-29 23:13:16 +0200 | [diff] [blame] | 2002 | // Locked by 'this' |
| 2003 | private void buildRanksLocked() { |
| 2004 | String[] orderedKeys = mRankingUpdate.getOrderedKeys(); |
| 2005 | mRanks = new ArrayMap<>(orderedKeys.length); |
| 2006 | for (int i = 0; i < orderedKeys.length; i++) { |
| 2007 | String key = orderedKeys[i]; |
| 2008 | mRanks.put(key, i); |
| 2009 | } |
| 2010 | } |
| 2011 | |
| 2012 | // Locked by 'this' |
| 2013 | private void buildInterceptedSetLocked() { |
| 2014 | String[] dndInterceptedKeys = mRankingUpdate.getInterceptedKeys(); |
| 2015 | mIntercepted = new ArraySet<>(dndInterceptedKeys.length); |
| 2016 | Collections.addAll(mIntercepted, dndInterceptedKeys); |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2017 | } |
| 2018 | |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2019 | private ArrayMap<String, Integer> buildIntMapFromBundle(Bundle bundle) { |
| 2020 | ArrayMap<String, Integer> newMap = new ArrayMap<>(bundle.size()); |
| 2021 | for (String key : bundle.keySet()) { |
| 2022 | newMap.put(key, bundle.getInt(key)); |
| 2023 | } |
| 2024 | return newMap; |
| 2025 | } |
| 2026 | |
| 2027 | private ArrayMap<String, String> buildStringMapFromBundle(Bundle bundle) { |
| 2028 | ArrayMap<String, String> newMap = new ArrayMap<>(bundle.size()); |
| 2029 | for (String key : bundle.keySet()) { |
| 2030 | newMap.put(key, bundle.getString(key)); |
| 2031 | } |
| 2032 | return newMap; |
| 2033 | } |
| 2034 | |
| 2035 | private ArrayMap<String, Boolean> buildBooleanMapFromBundle(Bundle bundle) { |
| 2036 | ArrayMap<String, Boolean> newMap = new ArrayMap<>(bundle.size()); |
| 2037 | for (String key : bundle.keySet()) { |
| 2038 | newMap.put(key, bundle.getBoolean(key)); |
| 2039 | } |
| 2040 | return newMap; |
| 2041 | } |
| 2042 | |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 2043 | private ArrayMap<String, Long> buildLongMapFromBundle(Bundle bundle) { |
| 2044 | ArrayMap<String, Long> newMap = new ArrayMap<>(bundle.size()); |
| 2045 | for (String key : bundle.keySet()) { |
| 2046 | newMap.put(key, bundle.getLong(key)); |
| 2047 | } |
| 2048 | return newMap; |
| 2049 | } |
| 2050 | |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 2051 | // Locked by 'this' |
| 2052 | private void buildVisibilityOverridesLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2053 | mVisibilityOverrides = buildIntMapFromBundle(mRankingUpdate.getVisibilityOverrides()); |
Chris Wren | 3ad4e3a | 2014-09-02 17:23:51 -0400 | [diff] [blame] | 2054 | } |
| 2055 | |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 2056 | // Locked by 'this' |
| 2057 | private void buildSuppressedVisualEffectsLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2058 | mSuppressedVisualEffects = |
| 2059 | buildIntMapFromBundle(mRankingUpdate.getSuppressedVisualEffects()); |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 2060 | } |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2061 | |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 2062 | // Locked by 'this' |
| 2063 | private void buildImportanceLocked() { |
| 2064 | String[] orderedKeys = mRankingUpdate.getOrderedKeys(); |
| 2065 | int[] importance = mRankingUpdate.getImportance(); |
| 2066 | mImportance = new ArrayMap<>(orderedKeys.length); |
| 2067 | for (int i = 0; i < orderedKeys.length; i++) { |
| 2068 | String key = orderedKeys[i]; |
| 2069 | mImportance.put(key, importance[i]); |
| 2070 | } |
| 2071 | } |
| 2072 | |
| 2073 | // Locked by 'this' |
| 2074 | private void buildImportanceExplanationLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2075 | mImportanceExplanation = |
| 2076 | buildStringMapFromBundle(mRankingUpdate.getImportanceExplanation()); |
Chris Wren | bdf3376 | 2015-12-04 15:50:51 -0500 | [diff] [blame] | 2077 | } |
Julia Reynolds | f612869ae | 2015-11-05 16:48:55 -0500 | [diff] [blame] | 2078 | |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 2079 | // Locked by 'this' |
| 2080 | private void buildOverrideGroupKeys() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2081 | mOverrideGroupKeys = buildStringMapFromBundle(mRankingUpdate.getOverrideGroupKeys()); |
Julia Reynolds | e46bb37 | 2016-03-17 11:05:58 -0400 | [diff] [blame] | 2082 | } |
| 2083 | |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 2084 | // Locked by 'this' |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 2085 | private void buildChannelsLocked() { |
| 2086 | Bundle channels = mRankingUpdate.getChannels(); |
| 2087 | mChannels = new ArrayMap<>(channels.size()); |
| 2088 | for (String key : channels.keySet()) { |
| 2089 | mChannels.put(key, channels.getParcelable(key)); |
Julia Reynolds | 22f02b3 | 2016-12-01 15:05:13 -0500 | [diff] [blame] | 2090 | } |
| 2091 | } |
| 2092 | |
| 2093 | // Locked by 'this' |
| 2094 | private void buildOverridePeopleLocked() { |
| 2095 | Bundle overridePeople = mRankingUpdate.getOverridePeople(); |
| 2096 | mOverridePeople = new ArrayMap<>(overridePeople.size()); |
| 2097 | for (String key : overridePeople.keySet()) { |
| 2098 | mOverridePeople.put(key, overridePeople.getStringArrayList(key)); |
| 2099 | } |
| 2100 | } |
| 2101 | |
| 2102 | // Locked by 'this' |
| 2103 | private void buildSnoozeCriteriaLocked() { |
| 2104 | Bundle snoozeCriteria = mRankingUpdate.getSnoozeCriteria(); |
| 2105 | mSnoozeCriteria = new ArrayMap<>(snoozeCriteria.size()); |
| 2106 | for (String key : snoozeCriteria.keySet()) { |
| 2107 | mSnoozeCriteria.put(key, snoozeCriteria.getParcelableArrayList(key)); |
| 2108 | } |
| 2109 | } |
| 2110 | |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 2111 | // Locked by 'this' |
| 2112 | private void buildShowBadgeLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2113 | mShowBadge = buildBooleanMapFromBundle(mRankingUpdate.getShowBadge()); |
Julia Reynolds | 924eed1 | 2017-01-19 09:52:07 -0500 | [diff] [blame] | 2114 | } |
| 2115 | |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 2116 | // Locked by 'this' |
| 2117 | private void buildUserSentimentLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2118 | mUserSentiment = buildIntMapFromBundle(mRankingUpdate.getUserSentiment()); |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 2119 | } |
| 2120 | |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 2121 | // Locked by 'this' |
| 2122 | private void buildHiddenLocked() { |
Aaron Heuckroth | aa01ea4 | 2018-08-14 10:05:43 -0400 | [diff] [blame] | 2123 | mHidden = buildBooleanMapFromBundle(mRankingUpdate.getHidden()); |
Beverly | 5a20a5e | 2018-03-06 15:02:44 -0500 | [diff] [blame] | 2124 | } |
| 2125 | |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 2126 | // Locked by 'this' |
Gus Prevas | 7306b90 | 2018-12-11 10:57:06 -0500 | [diff] [blame] | 2127 | private void buildLastAudiblyAlertedLocked() { |
| 2128 | mLastAudiblyAlerted = buildLongMapFromBundle(mRankingUpdate.getLastAudiblyAlerted()); |
Gus Prevas | a322649 | 2018-10-23 11:10:09 -0400 | [diff] [blame] | 2129 | } |
| 2130 | |
| 2131 | // Locked by 'this' |
Gus Prevas | 9abc506 | 2018-10-31 16:11:04 -0400 | [diff] [blame] | 2132 | private void buildNoisyLocked() { |
| 2133 | mNoisy = buildBooleanMapFromBundle(mRankingUpdate.getNoisy()); |
| 2134 | } |
| 2135 | |
| 2136 | // Locked by 'this' |
Tony Mak | 628cb93 | 2018-06-19 18:30:41 +0100 | [diff] [blame] | 2137 | private void buildSmartActions() { |
| 2138 | Bundle smartActions = mRankingUpdate.getSmartActions(); |
| 2139 | mSmartActions = new ArrayMap<>(smartActions.size()); |
| 2140 | for (String key : smartActions.keySet()) { |
| 2141 | mSmartActions.put(key, smartActions.getParcelableArrayList(key)); |
| 2142 | } |
| 2143 | } |
| 2144 | |
Tony Mak | c9acf67 | 2018-07-20 13:58:24 +0200 | [diff] [blame] | 2145 | // Locked by 'this' |
| 2146 | private void buildSmartReplies() { |
| 2147 | Bundle smartReplies = mRankingUpdate.getSmartReplies(); |
| 2148 | mSmartReplies = new ArrayMap<>(smartReplies.size()); |
| 2149 | for (String key : smartReplies.keySet()) { |
| 2150 | mSmartReplies.put(key, smartReplies.getCharSequenceArrayList(key)); |
| 2151 | } |
| 2152 | } |
| 2153 | |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2154 | // ----------- Parcelable |
| 2155 | |
| 2156 | @Override |
| 2157 | public int describeContents() { |
| 2158 | return 0; |
| 2159 | } |
| 2160 | |
| 2161 | @Override |
| 2162 | public void writeToParcel(Parcel dest, int flags) { |
| 2163 | dest.writeParcelable(mRankingUpdate, flags); |
| 2164 | } |
| 2165 | |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 2166 | public static final Creator<RankingMap> CREATOR = new Creator<RankingMap>() { |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2167 | @Override |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 2168 | public RankingMap createFromParcel(Parcel source) { |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2169 | NotificationRankingUpdate rankingUpdate = source.readParcelable(null); |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 2170 | return new RankingMap(rankingUpdate); |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2171 | } |
| 2172 | |
| 2173 | @Override |
Christoph Studer | d0694b6 | 2014-06-04 16:36:01 +0200 | [diff] [blame] | 2174 | public RankingMap[] newArray(int size) { |
| 2175 | return new RankingMap[size]; |
Christoph Studer | 05ad482 | 2014-05-16 14:16:03 +0200 | [diff] [blame] | 2176 | } |
| 2177 | }; |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 2178 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2179 | |
| 2180 | private final class MyHandler extends Handler { |
| 2181 | public static final int MSG_ON_NOTIFICATION_POSTED = 1; |
| 2182 | public static final int MSG_ON_NOTIFICATION_REMOVED = 2; |
| 2183 | public static final int MSG_ON_LISTENER_CONNECTED = 3; |
| 2184 | public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4; |
| 2185 | public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5; |
| 2186 | public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6; |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 2187 | public static final int MSG_ON_NOTIFICATION_CHANNEL_MODIFIED = 7; |
| 2188 | public static final int MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED = 8; |
Julia Reynolds | 12ad7ca | 2019-01-28 09:29:16 -0500 | [diff] [blame] | 2189 | public static final int MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED = 9; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2190 | |
| 2191 | public MyHandler(Looper looper) { |
| 2192 | super(looper, null, false); |
| 2193 | } |
| 2194 | |
| 2195 | @Override |
| 2196 | public void handleMessage(Message msg) { |
Chris Wren | 5717bd6 | 2016-04-06 18:15:46 -0400 | [diff] [blame] | 2197 | if (!isConnected) { |
| 2198 | return; |
| 2199 | } |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2200 | switch (msg.what) { |
| 2201 | case MSG_ON_NOTIFICATION_POSTED: { |
| 2202 | SomeArgs args = (SomeArgs) msg.obj; |
| 2203 | StatusBarNotification sbn = (StatusBarNotification) args.arg1; |
| 2204 | RankingMap rankingMap = (RankingMap) args.arg2; |
| 2205 | args.recycle(); |
| 2206 | onNotificationPosted(sbn, rankingMap); |
| 2207 | } break; |
| 2208 | |
| 2209 | case MSG_ON_NOTIFICATION_REMOVED: { |
| 2210 | SomeArgs args = (SomeArgs) msg.obj; |
| 2211 | StatusBarNotification sbn = (StatusBarNotification) args.arg1; |
| 2212 | RankingMap rankingMap = (RankingMap) args.arg2; |
Julia Reynolds | 3aa5f1e | 2016-11-09 15:43:49 -0500 | [diff] [blame] | 2213 | int reason = (int) args.arg3; |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 2214 | NotificationStats stats = (NotificationStats) args.arg4; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2215 | args.recycle(); |
Julia Reynolds | 503ed94 | 2017-10-04 16:04:56 -0400 | [diff] [blame] | 2216 | onNotificationRemoved(sbn, rankingMap, stats, reason); |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2217 | } break; |
| 2218 | |
| 2219 | case MSG_ON_LISTENER_CONNECTED: { |
| 2220 | onListenerConnected(); |
| 2221 | } break; |
| 2222 | |
| 2223 | case MSG_ON_NOTIFICATION_RANKING_UPDATE: { |
| 2224 | RankingMap rankingMap = (RankingMap) msg.obj; |
| 2225 | onNotificationRankingUpdate(rankingMap); |
| 2226 | } break; |
| 2227 | |
| 2228 | case MSG_ON_LISTENER_HINTS_CHANGED: { |
| 2229 | final int hints = msg.arg1; |
| 2230 | onListenerHintsChanged(hints); |
| 2231 | } break; |
| 2232 | |
| 2233 | case MSG_ON_INTERRUPTION_FILTER_CHANGED: { |
| 2234 | final int interruptionFilter = msg.arg1; |
| 2235 | onInterruptionFilterChanged(interruptionFilter); |
| 2236 | } break; |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 2237 | |
| 2238 | case MSG_ON_NOTIFICATION_CHANNEL_MODIFIED: { |
| 2239 | SomeArgs args = (SomeArgs) msg.obj; |
| 2240 | String pkgName = (String) args.arg1; |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 2241 | UserHandle user= (UserHandle) args.arg2; |
| 2242 | NotificationChannel channel = (NotificationChannel) args.arg3; |
| 2243 | int modificationType = (int) args.arg4; |
| 2244 | onNotificationChannelModified(pkgName, user, channel, modificationType); |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 2245 | } break; |
| 2246 | |
| 2247 | case MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED: { |
| 2248 | SomeArgs args = (SomeArgs) msg.obj; |
| 2249 | String pkgName = (String) args.arg1; |
Julia Reynolds | f27d6b2 | 2017-04-13 15:48:16 -0400 | [diff] [blame] | 2250 | UserHandle user = (UserHandle) args.arg2; |
| 2251 | NotificationChannelGroup group = (NotificationChannelGroup) args.arg3; |
| 2252 | int modificationType = (int) args.arg4; |
| 2253 | onNotificationChannelGroupModified(pkgName, user, group, modificationType); |
Julia Reynolds | 73ed76b | 2017-04-04 17:04:38 -0400 | [diff] [blame] | 2254 | } break; |
Julia Reynolds | 12ad7ca | 2019-01-28 09:29:16 -0500 | [diff] [blame] | 2255 | |
| 2256 | case MSG_ON_STATUS_BAR_ICON_BEHAVIOR_CHANGED: { |
| 2257 | onStatusBarIconsBehaviorChanged((Boolean) msg.obj); |
| 2258 | } break; |
Svet Ganov | b8f53ee | 2016-02-18 08:38:56 -0800 | [diff] [blame] | 2259 | } |
| 2260 | } |
| 2261 | } |
Daniel Sandler | 5feceeb | 2013-03-22 18:29:23 -0700 | [diff] [blame] | 2262 | } |